import "./register.css";
import { defineComponent, computed, openBlock, createElementBlock, createElementVNode, createCommentVNode, Fragment, renderList, normalizeStyle, createBlock, ref, onMounted, watch, createTextVNode, normalizeClass, toDisplayString, reactive, readonly, shallowRef, withDirectives, vModelText, unref, withCtx, renderSlot, mergeProps, toHandlers, useAttrs, createVNode, h, nextTick, onUpdated, onBeforeUnmount, createSlots, vModelSelect, withModifiers, Transition, useCssVars, vShow, normalizeProps, guardReactiveProps, createStaticVNode, onUnmounted, resolveComponent, vModelCheckbox, vModelRadio, markRaw, withKeys } from "vue";
import uPlot from "uplot";
import "uplot/dist/uPlot.min.css";
import { Button, Select, Form, Input, Switch, Tooltip, Table, FormItem, Textarea, 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 { closeCompletion, startCompletion, completionKeymap, autocompletion } from "@codemirror/autocomplete";
import { history, historyKeymap, defaultKeymap } from "@codemirror/commands";
import { EditorState, Prec, RangeSetBuilder } from "@codemirror/state";
import { EditorView, keymap, placeholder, Decoration, ViewPlugin } from "@codemirror/view";
import { Lexer, Token, LexerATNSimulator, PredictionContextCache, ATNDeserializer, DFA, Parser, FailedPredicateException, ParserATNSimulator, RecognitionException, NoViableAltException, ParserRuleContext, CharStreams, CommonTokenStream, ParseTreeWalker, ErrorListener } from "antlr4";
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 listPanelPlugins() {
  return [...panels.values()];
}
function listDataSourcePlugins() {
  return [...datasources.values()];
}
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;
  }
}
function normalizeHideFrom(raw) {
  const base = { tooltip: false, viz: false, legend: false };
  if (raw == null) return base;
  if (typeof raw === "string") {
    if (raw === "tooltip" || raw === "viz" || raw === "legend") base[raw] = true;
    else if (raw === "graph") base.viz = true;
    return base;
  }
  if (Array.isArray(raw)) {
    for (const k of raw) {
      if (k === "tooltip" || k === "viz" || k === "legend") {
        base[k] = true;
      }
      if (k === "graph") base.viz = true;
    }
    return base;
  }
  if (typeof raw === "object") {
    const o = raw;
    return {
      tooltip: !!o.tooltip,
      viz: !!(o.viz ?? o.graph),
      legend: !!o.legend
    };
  }
  return base;
}
function normalizeScaleDistribution(raw) {
  if (raw == null) return { type: "linear" };
  if (typeof raw === "string") {
    const type = raw || "linear";
    return {
      type,
      log: type === "linear" ? void 0 : 10
    };
  }
  if (typeof raw === "object") {
    const o = raw;
    const type = String(o.type ?? "linear");
    return {
      type,
      log: o.log == null ? type === "linear" ? void 0 : 10 : Number(o.log),
      linearThreshold: o.linearThreshold == null ? void 0 : Number(o.linearThreshold)
    };
  }
  return { type: "linear" };
}
function normalizeStacking(raw) {
  if (raw == null) return { mode: "none", group: "A" };
  if (typeof raw === "string") return { mode: raw || "none", group: "A" };
  if (typeof raw === "object") {
    const o = raw;
    return {
      mode: String(o.mode ?? "none"),
      group: String(o.group ?? "A")
    };
  }
  return { mode: "none", group: "A" };
}
function normalizeThresholdsStyle(raw) {
  if (raw == null) return { mode: "off" };
  if (typeof raw === "string") return { mode: raw || "off" };
  if (typeof raw === "object" && raw.mode != null) {
    return { mode: String(raw.mode) };
  }
  return { mode: "off" };
}
function addLegendOptions(builder, includeCalcs = true, includeWidth = true) {
  const category = ["Legend"];
  builder.addBoolean(
    {
      id: "legend.showLegend",
      path: "legend.showLegend",
      name: "可见性",
      description: "显示图例",
      category,
      editor: "boolean"
    },
    true
  ).addRadio(
    {
      id: "legend.displayMode",
      path: "legend.displayMode",
      name: "模式",
      category,
      editor: "radio",
      settings: {
        options: [
          { label: "列表", value: "list" },
          { label: "表格", value: "table" }
        ]
      },
      showIf: (c) => c.legend?.showLegend !== false
    },
    "list"
  ).addRadio(
    {
      id: "legend.placement",
      path: "legend.placement",
      name: "位置",
      category,
      editor: "radio",
      settings: {
        options: [
          { label: "底部", value: "bottom" },
          { label: "右侧", value: "right" }
        ]
      },
      showIf: (c) => c.legend?.showLegend !== false
    },
    "bottom"
  );
  if (includeWidth) {
    builder.addNumber(
      {
        id: "legend.width",
        path: "legend.width",
        name: "宽度",
        category,
        editor: "number",
        showIf: (c) => c.legend?.showLegend !== false && c.legend?.placement === "right"
      },
      void 0
    );
  }
  builder.addSelect(
    {
      id: "legend.overflow",
      path: "legend.overflow",
      name: "溢出",
      category,
      editor: "select",
      settings: {
        options: [
          { label: "滚动", value: "scroll" },
          { label: "换行", value: "wrap" }
        ]
      },
      showIf: (c) => c.legend?.showLegend !== false
    },
    "scroll"
  ).addNumber(
    {
      id: "legend.limit",
      path: "legend.limit",
      name: "最大项数",
      category,
      editor: "number",
      showIf: (c) => c.legend?.showLegend !== false
    },
    void 0
  );
  if (includeCalcs) {
    builder.addCustom(
      {
        id: "legend.calcs",
        path: "legend.calcs",
        name: "取值",
        description: "图例表格中显示的计算值",
        category,
        editor: "stats-picker",
        settings: { allowMultiple: true },
        showIf: (c) => c.legend?.showLegend !== false && c.legend?.displayMode === "table"
      },
      []
    );
  }
  return builder;
}
function addTooltipOptions(builder, singleOnly = false, includeHideZeros = false) {
  const category = ["Tooltip"];
  const modes = singleOnly ? [
    { label: "单个", value: "single" },
    { label: "隐藏", value: "none" }
  ] : [
    { label: "单个", value: "single" },
    { label: "全部", value: "multi" },
    { label: "隐藏", value: "none" }
  ];
  builder.addRadio(
    {
      id: "tooltip.mode",
      path: "tooltip.mode",
      name: "提示模式",
      category,
      editor: "radio",
      settings: { options: modes }
    },
    "single"
  ).addRadio(
    {
      id: "tooltip.sort",
      path: "tooltip.sort",
      name: "数值排序",
      category,
      editor: "radio",
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "升序", value: "asc" },
          { label: "降序", value: "desc" }
        ]
      },
      showIf: (c) => c.tooltip?.mode === "multi"
    },
    "none"
  ).addNumber(
    {
      id: "tooltip.hoverProximity",
      path: "tooltip.hoverProximity",
      name: "悬停邻近",
      description: "光标需靠近数据点的距离",
      category,
      editor: "number",
      settings: { min: 0, max: 50 }
    },
    void 0
  ).addNumber(
    {
      id: "tooltip.maxWidth",
      path: "tooltip.maxWidth",
      name: "最大宽度",
      category,
      editor: "number"
    },
    void 0
  ).addNumber(
    {
      id: "tooltip.maxHeight",
      path: "tooltip.maxHeight",
      name: "最大高度",
      category,
      editor: "number",
      showIf: (c) => c.tooltip?.mode === "multi"
    },
    void 0
  );
  if (includeHideZeros) {
    builder.addBoolean(
      {
        id: "tooltip.hideZeros",
        path: "tooltip.hideZeros",
        name: "隐藏零值",
        category,
        editor: "boolean",
        showIf: (c) => c.tooltip?.mode === "multi"
      },
      false
    );
  }
  return builder;
}
function addAxisConfig(builder) {
  const category = ["Axis"];
  builder.addCustom({
    id: "custom.axisPlacement",
    path: "custom.axisPlacement",
    name: "位置",
    category,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "自动", value: "auto" },
        { label: "左侧", value: "left" },
        { label: "右侧", value: "right" },
        { label: "隐藏", value: "hidden" }
      ]
    },
    defaultValue: "auto"
  }).addCustom({
    id: "custom.axisLabel",
    path: "custom.axisLabel",
    name: "标签",
    category,
    editor: "text",
    isCustom: true,
    override: true
  }).addCustom({
    id: "custom.axisWidth",
    path: "custom.axisWidth",
    name: "宽度",
    category,
    editor: "number",
    isCustom: true,
    override: true
  }).addCustom({
    id: "custom.axisSoftMin",
    path: "custom.axisSoftMin",
    name: "软最小值",
    category,
    editor: "number",
    isCustom: true,
    override: true
  }).addCustom({
    id: "custom.axisSoftMax",
    path: "custom.axisSoftMax",
    name: "软最大值",
    category,
    editor: "number",
    isCustom: true,
    override: true
  }).addCustom({
    id: "custom.axisCenteredZero",
    path: "custom.axisCenteredZero",
    name: "零居中",
    category,
    editor: "boolean",
    isCustom: true,
    override: true,
    defaultValue: false
  }).addCustom({
    id: "custom.axisGridShow",
    path: "custom.axisGridShow",
    name: "显示网格线",
    category,
    editor: "boolean",
    isCustom: true,
    override: true
  }).addCustom({
    id: "custom.axisBorderShow",
    path: "custom.axisBorderShow",
    name: "显示边框",
    category,
    editor: "boolean",
    isCustom: true,
    override: true,
    defaultValue: false
  }).addCustom({
    id: "custom.axisColorMode",
    path: "custom.axisColorMode",
    name: "颜色",
    category,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "文本", value: "text" },
        { label: "序列", value: "series" }
      ]
    },
    defaultValue: "text"
  }).addCustom({
    id: "custom.scaleDistribution",
    path: "custom.scaleDistribution",
    name: "刻度",
    category,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "线性", value: "linear" },
        { label: "对数", value: "log" },
        { label: "对称对数", value: "symlog" }
      ]
    },
    defaultValue: { type: "linear" }
  });
  return builder;
}
function addStackingConfig(builder) {
  builder.addCustom({
    id: "custom.stacking",
    path: "custom.stacking",
    name: "堆叠序列",
    category: ["Graph styles"],
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "关闭", value: "none" },
        { label: "标准", value: "normal" },
        { label: "100%", value: "percent" }
      ]
    },
    defaultValue: { mode: "none", group: "A" }
  });
  return builder;
}
function graphConfig(cfg) {
  if (!cfg || typeof cfg !== "object") return {};
  const value = cfg;
  return value.custom && typeof value.custom === "object" ? value.custom : value;
}
function addGraphFieldConfig(builder) {
  const styles = ["Graph styles"];
  builder.addCustom({
    id: "custom.drawStyle",
    path: "custom.drawStyle",
    name: "样式",
    category: styles,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "折线", value: "line" },
        { label: "柱状", value: "bars" },
        { label: "点", value: "points" }
      ]
    },
    defaultValue: "line"
  }).addCustom({
    id: "custom.lineInterpolation",
    path: "custom.lineInterpolation",
    name: "线插值",
    category: styles,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "线性", value: "linear" },
        { label: "平滑", value: "smooth" },
        { label: "阶梯前", value: "stepBefore" },
        { label: "阶梯后", value: "stepAfter" }
      ]
    },
    defaultValue: "linear",
    showIf: (cfg) => graphConfig(cfg).drawStyle === "line"
  }).addCustom({
    id: "custom.barAlignment",
    path: "custom.barAlignment",
    name: "柱对齐",
    category: styles,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "之前", value: -1 },
        { label: "居中", value: 0 },
        { label: "之后", value: 1 }
      ]
    },
    defaultValue: 0,
    showIf: (cfg) => graphConfig(cfg).drawStyle === "bars"
  }).addCustom({
    id: "custom.barWidthFactor",
    path: "custom.barWidthFactor",
    name: "柱宽系数",
    category: styles,
    editor: "slider",
    isCustom: true,
    override: true,
    settings: { min: 0.1, max: 1, step: 0.1 },
    defaultValue: 0.6,
    showIf: (cfg) => graphConfig(cfg).drawStyle === "bars"
  }).addCustom({
    id: "custom.lineWidth",
    path: "custom.lineWidth",
    name: "线宽",
    category: styles,
    editor: "slider",
    isCustom: true,
    override: true,
    settings: { min: 0, max: 10, step: 1 },
    defaultValue: 1,
    showIf: (cfg) => graphConfig(cfg).drawStyle !== "points"
  }).addCustom({
    id: "custom.fillOpacity",
    path: "custom.fillOpacity",
    name: "填充不透明度",
    category: styles,
    editor: "slider",
    isCustom: true,
    override: true,
    settings: { min: 0, max: 100, step: 1 },
    defaultValue: 0,
    showIf: (cfg) => graphConfig(cfg).drawStyle !== "points"
  }).addCustom({
    id: "custom.gradientMode",
    path: "custom.gradientMode",
    name: "渐变模式",
    category: styles,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "无", value: "none" },
        { label: "不透明度", value: "opacity" },
        { label: "色相", value: "hue" },
        { label: "色板", value: "scheme" }
      ]
    },
    defaultValue: "none",
    showIf: (cfg) => graphConfig(cfg).drawStyle !== "points"
  }).addCustom({
    id: "custom.fillBelowTo",
    path: "custom.fillBelowTo",
    name: "填充至",
    category: styles,
    editor: "field-name",
    isCustom: true,
    override: true,
    hideFromDefaults: true
  }).addCustom({
    id: "custom.lineStyle",
    path: "custom.lineStyle",
    name: "线型",
    category: styles,
    editor: "select",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "实线", value: "solid" },
        { label: "虚线", value: "dash" },
        { label: "点线", value: "dot" }
      ]
    },
    defaultValue: { fill: "solid" },
    showIf: (cfg) => graphConfig(cfg).drawStyle === "line"
  }).addCustom({
    id: "custom.spanNulls",
    path: "custom.spanNulls",
    name: "连接空值",
    category: styles,
    editor: "boolean",
    isCustom: true,
    override: true,
    defaultValue: false,
    showIf: (cfg) => graphConfig(cfg).drawStyle === "line"
  }).addCustom({
    id: "custom.insertNulls",
    path: "custom.insertNulls",
    name: "断开数值",
    category: styles,
    editor: "boolean",
    isCustom: true,
    override: true,
    defaultValue: false,
    showIf: (cfg) => graphConfig(cfg).drawStyle === "line"
  }).addCustom({
    id: "custom.showPoints",
    path: "custom.showPoints",
    name: "显示数据点",
    category: styles,
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "自动", value: "auto" },
        { label: "始终", value: "always" },
        { label: "从不", value: "never" }
      ]
    },
    defaultValue: "auto",
    showIf: (cfg) => graphConfig(cfg).drawStyle !== "points"
  }).addCustom({
    id: "custom.showValues",
    path: "custom.showValues",
    name: "显示数值",
    category: styles,
    editor: "boolean",
    isCustom: true,
    override: true,
    defaultValue: false,
    showIf: (cfg) => {
      const graph = graphConfig(cfg);
      return graph.showPoints !== "never" || graph.drawStyle === "points";
    }
  }).addCustom({
    id: "custom.pointSize",
    path: "custom.pointSize",
    name: "点大小",
    category: styles,
    editor: "slider",
    isCustom: true,
    override: true,
    settings: { min: 1, max: 40, step: 1 },
    defaultValue: 5,
    showIf: (cfg) => {
      const graph = graphConfig(cfg);
      return graph.showPoints !== "never" || graph.drawStyle === "points";
    }
  }).addCustom({
    id: "custom.transform",
    path: "custom.transform",
    name: "转换",
    category: styles,
    editor: "select",
    isCustom: true,
    override: true,
    hideFromDefaults: true,
    settings: {
      options: [
        { label: "常量", value: "constant" },
        { label: "负 Y", value: "negative-Y" }
      ]
    }
  }).addCustom({
    id: "custom.thresholdsStyle",
    path: "custom.thresholdsStyle",
    name: "显示阈值",
    category: ["Thresholds"],
    editor: "radio",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "关闭", value: "off" },
        { label: "线条", value: "line" },
        { label: "虚线", value: "dashed" },
        { label: "填充区域", value: "area" },
        { label: "填充区域与线条", value: "line+area" },
        { label: "填充区域与虚线", value: "dashed+area" }
      ]
    },
    defaultValue: { mode: "off" }
  }).addCustom({
    id: "custom.hideFrom",
    path: "custom.hideFrom",
    name: "隐藏区域",
    category: ["Series"],
    editor: "multi-select",
    isCustom: true,
    override: true,
    hideFromDefaults: true,
    settings: {
      options: [
        { label: "提示", value: "tooltip" },
        { label: "可视化", value: "viz" },
        { label: "图例", value: "legend" }
      ]
    },
    defaultValue: { tooltip: false, viz: false, legend: false }
  });
  addStackingConfig(builder);
  addAxisConfig(builder);
  return builder;
}
function addTextSizeOptions(builder, opts = {}) {
  const category = ["文本大小"];
  if (opts.withTitle) {
    builder.addNumber(
      {
        id: "text.titleSize",
        path: "text.titleSize",
        name: "标题",
        category,
        editor: "number",
        settings: { min: 1, placeholder: "自动" }
      },
      void 0
    );
  }
  if (opts.withValue !== false) {
    builder.addNumber(
      {
        id: "text.valueSize",
        path: "text.valueSize",
        name: "数值",
        category,
        editor: "number",
        settings: { min: 1, placeholder: "自动" }
      },
      void 0
    );
  }
  if (opts.withPercentChange) {
    builder.addNumber(
      {
        id: "text.percentSize",
        path: "text.percentSize",
        name: "百分比变化",
        category,
        editor: "number",
        settings: { min: 1, placeholder: "自动" }
      },
      void 0
    );
  }
  return builder;
}
function addHideFrom(builder) {
  builder.addCustom({
    id: "custom.hideFrom",
    path: "custom.hideFrom",
    name: "隐藏区域",
    category: ["Series"],
    editor: "multi-select",
    isCustom: true,
    override: true,
    settings: {
      options: [
        { label: "提示", value: "tooltip" },
        { label: "可视化", value: "viz" },
        { label: "图例", value: "legend" }
      ]
    },
    hideFromDefaults: true,
    defaultValue: { tooltip: false, viz: false, legend: false }
  });
  return builder;
}
function addAnnotationOptions(builder) {
  const category = ["注解"];
  builder.addBoolean(
    {
      id: "annotations.multiLane",
      path: "annotations.multiLane",
      name: "多行注解",
      description: "将每个注解 frame 拆到单独一行",
      category,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "annotations.clustering",
      path: "annotations.clustering",
      name: "注解聚合",
      description: "将高密度点注解合并为区间注解",
      category,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "annotations",
      path: "annotations",
      name: "隐藏指示线与区域",
      description: "隐藏注解指示线与阴影区域",
      category,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "annotations.show",
      path: "annotations.show",
      name: "显示注解",
      category,
      editor: "boolean"
    },
    true
  );
  return builder;
}
const runtimeDataSources = /* @__PURE__ */ new Map();
function getRuntimeDataSource(uid) {
  return runtimeDataSources.get(String(uid || "").trim());
}
function listRuntimeDataSources() {
  return [...runtimeDataSources.values()];
}
const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  FieldConfigBuilder,
  OptionsBuilder: OptionsUIBuilder,
  OptionsUIBuilder,
  STANDARD_FIELD_CONFIG,
  VuePanelPlugin,
  addAnnotationOptions,
  addAxisConfig,
  addGraphFieldConfig,
  addHideFrom,
  addLegendOptions,
  addStackingConfig,
  addTextSizeOptions,
  addTooltipOptions,
  buildStandardFieldConfigDescriptors,
  createDataSourcePlugin,
  createEmptyEditorContext,
  createPanelPlugin,
  getDataSourcePlugin,
  getRuntimeDataSource,
  listDataSourcePlugins,
  listPanelPlugins,
  listRuntimeDataSources,
  normalizeHideFrom,
  normalizeScaleDistribution,
  normalizeStacking,
  normalizeThresholdsStyle,
  registerDataSourcePlugin,
  registerPanelPlugin
}, Symbol.toStringTag, { value: "Module" }));
const _hoisted_1$2g = ["data-mode", "data-code-lang", "data-line-numbers", "data-mini-map"];
const _hoisted_2$1O = ["data-mode", "data-code-lang", "data-line-numbers", "data-mini-map", "innerHTML"];
const _hoisted_3$1B = {
  key: 0,
  class: "code-minimap",
  "data-testid": "text-code-minimap",
  "aria-hidden": "true"
};
const _sfc_main$3i = /* @__PURE__ */ defineComponent({
  __name: "TextRenderer",
  props: {
    options: {},
    title: {},
    replaceVariables: { type: Function },
    width: {},
    height: {},
    data: {},
    fieldConfig: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    function sanitize(html2) {
      return html2.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/\son\w+\s*=\s*(['"]).*?\1/gi, "").replace(/javascript:/gi, "").replace(/<iframe[\s\S]*?>[\s\S]*?<\/iframe>/gi, "");
    }
    function normalizeContentNewlines(content) {
      if (!content.includes("\\n")) return content;
      if (content.includes("\n")) return content;
      return content.replace(/\\n/g, "\n").replace(/\\t/g, "	");
    }
    function mdToHtml(src) {
      if (!src) return " ";
      let s = src.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
      s = s.replace(
        /```([\s\S]*?)```/g,
        (_m, code) => `<pre><code>${code.replace(/^\n/, "")}</code></pre>`
      );
      s = s.replace(/^### (.+)$/gm, "<h3>$1</h3>");
      s = s.replace(/^## (.+)$/gm, "<h2>$1</h2>");
      s = s.replace(/^# (.+)$/gm, "<h1>$1</h1>");
      s = s.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
      s = s.replace(/\*(.+?)\*/g, "<em>$1</em>");
      s = s.replace(/`([^`]+)`/g, "<code>$1</code>");
      s = s.replace(
        /\[(.+?)\]\((https?:\/\/[^)]+)\)/g,
        '<a href="$2" rel="noreferrer" target="_blank">$1</a>'
      );
      const parts = s.split(/\n{2,}/);
      const html2 = parts.map((part) => {
        const trimmed = part.trim();
        if (!trimmed) return "";
        if (/^<(h[1-6]|pre|ul|ol|blockquote)/i.test(trimmed))
          return trimmed.replace(/\n/g, " ");
        return `<p>${trimmed.replace(/\n/g, " ")}</p>`;
      }).join("");
      return html2 || " ";
    }
    const showMiniMap = computed(() => {
      const mode2 = String(opts.value.mode ?? "markdown");
      if (mode2 !== "code") return false;
      return Boolean(
        opts.value.code?.showMiniMap ?? opts.value["code.showMiniMap"]
      );
    });
    const codeLines = computed(() => {
      if (String(opts.value.mode ?? "markdown") !== "code") return [];
      let content = String(opts.value.content ?? "");
      if (props.replaceVariables) content = props.replaceVariables(content);
      content = normalizeContentNewlines(content);
      return content.split("\n");
    });
    const html = computed(() => {
      const mode2 = String(opts.value.mode ?? "markdown");
      let content = String(opts.value.content ?? "");
      if (props.replaceVariables) content = props.replaceVariables(content);
      content = normalizeContentNewlines(content);
      if (!content) return " ";
      if (mode2 === "html") return sanitize(content);
      if (mode2 === "code") {
        const lang = String(
          opts.value.code?.language ?? opts.value["code.language"] ?? "plaintext"
        );
        const showLines = opts.value.code?.showLineNumbers ?? opts.value["code.showLineNumbers"];
        const escaped = content.replace(/&/g, "&amp;").replace(/</g, "&lt;");
        if (showLines) {
          const lines = escaped.split("\n");
          const body = lines.map(
            (line, i) => `<div class="code-line"><span class="ln">${i + 1}</span><span class="lc">${line || " "}</span></div>`
          ).join("");
          return `<pre data-lang="${lang}" class="code-block with-lines"><code>${body}</code></pre>`;
        }
        return `<pre data-lang="${lang}" class="code-block"><code>${escaped}</code></pre>`;
      }
      return sanitize(mdToHtml(content));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "text-panel-host",
        "data-testid": "panel-text",
        "data-mode": String(opts.value.mode ?? "markdown"),
        "data-code-lang": String(opts.value.code?.language ?? opts.value["code.language"] ?? ""),
        "data-line-numbers": String(!!(opts.value.code?.showLineNumbers ?? opts.value["code.showLineNumbers"])),
        "data-mini-map": String(showMiniMap.value)
      }, [
        createElementVNode("div", {
          class: "text-panel markdown-html",
          "data-testid": "panel-text-content",
          "data-testid-grafana": "TextPanel-converted-content",
          "data-mode": String(opts.value.mode ?? "markdown"),
          "data-code-lang": String(opts.value.code?.language ?? opts.value["code.language"] ?? ""),
          "data-line-numbers": String(!!(opts.value.code?.showLineNumbers ?? opts.value["code.showLineNumbers"])),
          "data-mini-map": String(showMiniMap.value),
          role: "region",
          "aria-label": "Text panel",
          tabindex: "0",
          innerHTML: html.value
        }, null, 8, _hoisted_2$1O),
        createCommentVNode(" Grafana code editor mini-map: density overview of lines "),
        showMiniMap.value ? (openBlock(), createElementBlock("aside", _hoisted_3$1B, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(codeLines.value, (line, i) => {
              return openBlock(), createElementBlock(
                "div",
                {
                  key: i,
                  class: "mm-line",
                  style: normalizeStyle({ opacity: line.trim() ? 0.55 : 0.15 })
                },
                null,
                4
                /* STYLE */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$2g);
    };
  }
});
const _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};
const TextRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$3i, [["__scopeId", "data-v-d67e611b"]]);
const _sfc_main$3h = /* @__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(TextRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  { id: "text", name: "文本", state: "stable", skipDataQuery: true },
  _sfc_main$3h
).setPanelOptions((builder) => {
  builder.addRadio(
    {
      id: "mode",
      path: "mode",
      name: "模式",
      category: ["文本"],
      editor: "radio",
      settings: {
        options: [
          { label: "Markdown", value: "markdown" },
          { label: "HTML", value: "html" },
          { label: "代码", value: "code" }
        ]
      }
    },
    "markdown"
  ).addTextArea(
    {
      id: "content",
      path: "content",
      name: "内容",
      category: ["文本"],
      editor: "textarea"
    },
    `# Title

For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)`
  ).addSelect(
    {
      id: "code.language",
      path: "code.language",
      name: "语言",
      category: ["代码"],
      editor: "select",
      settings: {
        options: [
          { label: "plaintext", value: "plaintext" },
          { label: "yaml", value: "yaml" },
          { label: "json", value: "json" },
          { label: "sql", value: "sql" },
          { label: "markdown", value: "markdown" },
          { label: "javascript", value: "javascript" },
          { label: "typescript", value: "typescript" }
        ]
      },
      showIf: (c) => c.mode === "code"
    },
    "plaintext"
  ).addBoolean(
    {
      id: "code.showLineNumbers",
      path: "code.showLineNumbers",
      name: "显示行号",
      category: ["代码"],
      editor: "boolean",
      showIf: (c) => c.mode === "code"
    },
    false
  ).addBoolean(
    {
      id: "code.showMiniMap",
      path: "code.showMiniMap",
      name: "显示缩略图",
      category: ["代码"],
      editor: "boolean",
      showIf: (c) => c.mode === "code"
    },
    false
  );
}).setRuntimeConsumedPaths([
  "mode",
  "content",
  "code.language",
  "code.showLineNumbers",
  "code.showMiniMap"
]).register();
const _hoisted_1$2f = ["data-feed-url", "data-show-image", "data-loading", "data-item-count"];
const _hoisted_2$1N = {
  key: 0,
  class: "alert",
  "data-testid": "news-error",
  role: "alert"
};
const _hoisted_3$1A = {
  key: 1,
  class: "loading",
  "data-testid": "news-loading"
};
const _hoisted_4$1n = {
  key: 2,
  class: "scroll",
  "data-testid": "news-list"
};
const _hoisted_5$1c = ["href"];
const _hoisted_6$13 = ["src", "alt"];
const _hoisted_7$10 = { class: "body" };
const _hoisted_8$T = ["datetime"];
const _hoisted_9$O = { class: "title" };
const _hoisted_10$H = ["href"];
const _hoisted_11$B = {
  class: "content",
  "data-testid": "news-content"
};
const DEFAULT_FEED_URL = "https://grafana.com/blog/news.xml";
const _sfc_main$3g = /* @__PURE__ */ defineComponent({
  __name: "NewsRenderer",
  props: {
    options: {},
    width: {}
  },
  setup(__props, { expose: __expose }) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const feedUrl = computed(() => {
      const raw = opts.value.feedUrl ?? opts.value.url;
      const s = typeof raw === "string" && raw.trim() ? raw.trim() : DEFAULT_FEED_URL;
      return s;
    });
    const showImage = computed(() => opts.value.showImage !== false);
    const useWideLayout = computed(() => (props.width ?? 0) > 600);
    const loading = ref(true);
    const error = ref(null);
    const items = ref([]);
    function getProperty(node, property) {
      return node.querySelector(property)?.textContent ?? "";
    }
    function parseFeed(txt) {
      const doc = new DOMParser().parseFromString(txt, "text/xml");
      const isAtom = !!doc.querySelector("feed");
      if (isAtom) {
        return Array.from(doc.querySelectorAll("entry")).map((node) => {
          const link = node.querySelector("link[href]")?.getAttribute("href") || node.querySelector("link")?.textContent || "#";
          const pub = getProperty(node, "updated") || getProperty(node, "published");
          return {
            title: getProperty(node, "title"),
            link,
            content: getProperty(node, "summary") || getProperty(node, "content"),
            date: Date.parse(pub) || 0,
            ogImage: node.querySelector("meta[property='og:image']")?.getAttribute("content") || void 0
          };
        });
      }
      return Array.from(doc.querySelectorAll("item")).map((node) => {
        const pub = getProperty(node, "pubDate");
        const content = getProperty(node, "description").replace(
          /<\/?[^>]+(>|$)/g,
          ""
        );
        return {
          title: getProperty(node, "title"),
          link: getProperty(node, "link"),
          content,
          date: Date.parse(pub) || 0,
          ogImage: node.querySelector("meta[property='og:image']")?.getAttribute("content") || void 0
        };
      });
    }
    function formatNewsDate(ms) {
      if (!ms) return "";
      const d = new Date(ms);
      return d.toLocaleDateString("en-US", { month: "short", day: "2-digit" }).replace(",", "");
    }
    async function load() {
      loading.value = true;
      error.value = null;
      items.value = [];
      try {
        const { getResourceHttp: getResourceHttp2 } = await Promise.resolve().then(() => index$1);
        const axiosRes = await getResourceHttp2().request({
          url: feedUrl.value,
          method: "GET",
          responseType: "text",
          // Keep empty/error chrome snappy for offline demos (Grafana fails fast on CORS).
          timeout: 4e3
        });
        if (axiosRes.status < 200 || axiosRes.status >= 300)
          throw new Error(`HTTP ${axiosRes.status}`);
        const txt = typeof axiosRes.data === "string" ? axiosRes.data : String(axiosRes.data ?? "");
        items.value = parseFeed(txt);
      } catch (e) {
        error.value = e?.message || String(e);
      } finally {
        loading.value = false;
      }
    }
    onMounted(load);
    watch(feedUrl, load);
    __expose({ loading, error, items });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "news",
        "data-testid": "panel-news",
        "data-feed-url": feedUrl.value,
        "data-show-image": String(showImage.value),
        "data-loading": loading.value ? "1" : "0",
        "data-item-count": String(items.value.length)
      }, [
        error.value ? (openBlock(), createElementBlock("div", _hoisted_2$1N, [..._cache[0] || (_cache[0] = [
          createElementVNode(
            "div",
            { class: "alert-title" },
            "加载 RSS 源时出错",
            -1
            /* CACHED */
          ),
          createElementVNode(
            "div",
            { class: "alert-body" },
            [
              createTextVNode(" 请确保订阅源网址正确无误，并且在服务器上正确配置了 CORS。请参阅 "),
              createElementVNode("a", {
                class: "doc-link",
                href: "https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/news/",
                target: "_blank",
                rel: "noreferrer"
              }, "新闻面板文档"),
              createTextVNode("。 ")
            ],
            -1
            /* CACHED */
          )
        ])])) : loading.value ? (openBlock(), createElementBlock("div", _hoisted_3$1A, " 加载中... ")) : (openBlock(), createElementBlock("div", _hoisted_4$1n, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(items.value, (it, index2) => {
              return openBlock(), createElementBlock(
                "article",
                {
                  key: `${index2}-${it.link}`,
                  class: normalizeClass(["item", { wide: useWideLayout.value }]),
                  "data-testid": "news-item"
                },
                [
                  showImage.value && it.ogImage ? (openBlock(), createElementBlock("a", {
                    key: 0,
                    class: normalizeClass(["social-image", { wide: useWideLayout.value }]),
                    href: it.link,
                    target: "_blank",
                    rel: "noopener noreferrer",
                    tabindex: "-1",
                    "aria-hidden": "true"
                  }, [
                    createElementVNode("img", {
                      src: it.ogImage,
                      alt: it.title,
                      "data-testid": "news-image"
                    }, null, 8, _hoisted_6$13)
                  ], 10, _hoisted_5$1c)) : createCommentVNode("v-if", true),
                  createElementVNode("div", _hoisted_7$10, [
                    createElementVNode("time", {
                      class: "date",
                      datetime: formatNewsDate(it.date)
                    }, toDisplayString(formatNewsDate(it.date)) + " ", 9, _hoisted_8$T),
                    createElementVNode("h1", _hoisted_9$O, [
                      createElementVNode("a", {
                        class: "title-link",
                        href: it.link,
                        target: "_blank",
                        rel: "noreferrer"
                      }, toDisplayString(it.title), 9, _hoisted_10$H)
                    ]),
                    createElementVNode(
                      "div",
                      _hoisted_11$B,
                      toDisplayString(it.content),
                      1
                      /* TEXT */
                    )
                  ])
                ],
                2
                /* CLASS */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ]))
      ], 8, _hoisted_1$2f);
    };
  }
});
const NewsRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$3g, [["__scopeId", "data-v-c3c2147b"]]);
const _sfc_main$3f = /* @__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(NewsRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  { id: "news", name: "新闻", state: "stable", skipDataQuery: true },
  _sfc_main$3f
).setPanelOptions((builder) => {
  const category = ["新闻"];
  builder.addText(
    {
      id: "feedUrl",
      path: "feedUrl",
      name: "订阅源 URL",
      category
    },
    "https://grafana.com/blog/news.xml"
  ).addBoolean(
    {
      id: "showImage",
      path: "showImage",
      name: "显示图片",
      category
    },
    true
  );
}).setRuntimeConsumedPaths(["feedUrl", "showImage"]).register();
const state$3 = reactive({ boot: null });
function setBootData(boot) {
  state$3.boot = boot;
}
function useBootData() {
  return readonly(state$3);
}
function getBootData() {
  if (!state$3.boot) {
    throw new Error("BootData not initialized");
  }
  return state$3.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
      },
      ...partial?.user ?? {}
    },
    settings: {
      appSubUrl: "",
      buildInfo: { version: "13.2.0-pre-vue", commit: "local", env: "dev" },
      featureToggles: {},
      datasources: {},
      panels: {},
      minRefreshInterval: "5s",
      ...partial?.settings ?? {}
    },
    navTree: partial?.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);
}
function resetOfflineStorage() {
  if (typeof localStorage === "undefined") return;
  localStorage.removeItem(DASH_STORAGE_KEY);
  localStorage.removeItem(DS_STORAGE_KEY);
}
const OFFLINE_STORAGE_KEYS = {
  dashboards: DASH_STORAGE_KEY,
  datasources: DS_STORAGE_KEY
};
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((t2) => String(t2).includes("zabbix"));
      } else if (d.uid.startsWith("ds-signoz") || d.uid.includes("live-signoz")) {
        needs = !types.some((t2) => String(t2) === "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", stringInput: "10,25,40,15,30,70" },
    { 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 h2 = d.h ?? 8;
    if (x + w > 24) {
      x = 0;
      y += rowH || 8;
      rowH = 0;
    }
    const gridPos = { x, y, w, h: h2 };
    x += w;
    rowH = Math.max(rowH, h2);
    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(config2) {
      return instance.request(config2);
    },
    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();
  }
}
function axiosHeadersToRecord(headers) {
  const out = {};
  if (!headers || typeof headers !== "object") return out;
  for (const [k, v] of Object.entries(headers)) {
    if (v == null) continue;
    out[k] = Array.isArray(v) ? String(v[0]) : String(v);
  }
  return out;
}
let backendHttp = null;
let datasourceHttpClient = null;
let resourceHttp = null;
let appHttp = 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;
}
function getResourceHttp() {
  if (!resourceHttp) {
    resourceHttp = createHttpClient({
      kind: "resource",
      withCredentials: false,
      timeoutMs: 3e4
    });
  }
  return resourceHttp;
}
function getAppHttp() {
  if (!appHttp) {
    appHttp = createHttpClient({
      kind: "app",
      withCredentials: true,
      timeoutMs: 3e4
    });
  }
  return appHttp;
}
function configureDatasourceHttpClient(opts) {
  datasourceHttpClient?.dispose();
  datasourceHttpClient = createHttpClient({
    kind: "datasource",
    withCredentials: false,
    timeoutMs: opts?.timeoutMs ?? 6e4,
    adapter: opts?.adapter
  });
  return datasourceHttpClient;
}
function resetHttpClients() {
  backendHttp?.dispose();
  datasourceHttpClient?.dispose();
  resourceHttp?.dispose();
  appHttp?.dispose();
  backendHttp = null;
  datasourceHttpClient = null;
  resourceHttp = null;
  appHttp = null;
}
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;
}
function getGrafanaAuthSnapshot() {
  if (readWindowToken()) {
    return {
      present: true,
      source: "window",
      preview: redactToken(readWindowToken())
    };
  }
  if (readStorageToken()) {
    return {
      present: true,
      source: "localStorage",
      preview: redactToken(readStorageToken())
    };
  }
  if (readEnvToken()) {
    return {
      present: true,
      source: "env",
      preview: redactToken(readEnvToken())
    };
  }
  return { present: false, source: "none", preview: "" };
}
function redactToken(token) {
  if (!token) return "";
  if (token.length <= 8) return "***";
  return `${token.slice(0, 4)}***${token.slice(-2)}`;
}
function setGrafanaAuthToken(token) {
  try {
    if (typeof localStorage === "undefined") return;
    if (!token) localStorage.removeItem(STORAGE_KEY);
    else localStorage.setItem(STORAGE_KEY, token);
  } catch {
  }
}
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 t2 = getGrafanaAuthToken();
  if (!t2) throw new GrafanaAuthError();
  return t2;
}
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 (config2) => {
        const url = resolveUrl(config2);
        const headers = {};
        const raw = config2.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: (config2.method || "GET").toUpperCase(),
          headers,
          body: config2.data,
          signal: config2.signal,
          credentials: "same-origin"
        });
        const text = await res.text();
        const h2 = {};
        res.headers.forEach((val, key) => {
          h2[key] = val;
        });
        return {
          data: text,
          status: res.status,
          statusText: res.statusText,
          headers: h2,
          config: config2
        };
      }
    });
  }
}
function resolveUrl(config2) {
  const base = config2.baseURL || "";
  const url = config2.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
};
const state$2 = reactive({
  path: typeof window !== "undefined" ? window.location.pathname : "/",
  query: {},
  hash: ""
});
function useLocationService() {
  return {
    state: readonly(state$2),
    partial: (update) => {
      if (update.path != null) state$2.path = update.path;
      if (update.query != null)
        state$2.query = { ...state$2.query, ...update.query };
      if (update.hash != null) state$2.hash = update.hash;
    },
    push: (path, query) => {
      state$2.path = path;
      if (query) state$2.query = query;
    },
    replace: (path, query) => {
      state$2.path = path;
      if (query) state$2.query = query;
    },
    getSearchObject: () => ({ ...state$2.query })
  };
}
const LoadingStateEnum = {
  Loading: "Loading",
  Done: "Done",
  Error: "Error",
  NotStarted: "NotStarted",
  Streaming: "Streaming"
};
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";
}
const TIME_SERIES_VALUE_FIELD_NAME = "Value";
const TIME_SERIES_TIME_FIELD_NAME = "Time";
function formatLabels(labels) {
  if (!labels) return "";
  return Object.entries(labels).filter(([, v]) => v != null && v !== "").map(([k, v]) => `${k}=${v}`).join(", ");
}
function getFieldDisplayName(field, frame, allFrames) {
  const name = calculateFieldDisplayName(field, frame, allFrames);
  if (field.state?.displayName !== name) {
    field.state = { ...field.state || {}, displayName: name };
  }
  return name;
}
function isGenericValueName(s) {
  const t2 = s.trim();
  if (!t2 || t2 === TIME_SERIES_VALUE_FIELD_NAME) return true;
  if (/^Value\s*\{/.test(t2)) return true;
  return false;
}
function calculateFieldDisplayName(field, frame, allFrames) {
  const cfg = field.config ?? {};
  if (cfg.displayName && String(cfg.displayName).length && !isGenericValueName(String(cfg.displayName))) {
    return String(cfg.displayName);
  }
  if (cfg.displayNameFromDS && String(cfg.displayNameFromDS).length && !isGenericValueName(String(cfg.displayNameFromDS))) {
    return String(cfg.displayNameFromDS);
  }
  if (field.type === "time" && !field.labels) {
    return field.name || TIME_SERIES_TIME_FIELD_NAME;
  }
  const frames = allFrames?.length ? allFrames : frame ? [frame] : [];
  let frameNamesDiffer = false;
  if (frames.length > 1) {
    for (let i = 1; i < frames.length; i++) {
      if (frames[i].name !== frames[i - 1].name) {
        frameNamesDiffer = true;
        break;
      }
    }
  }
  const parts = [];
  let frameNameAdded = false;
  let labelsAdded = false;
  if (frameNamesDiffer && frame?.name) {
    parts.push(frame.name);
    frameNameAdded = true;
  }
  if (field.name && !isGenericValueName(field.name)) {
    parts.push(field.name);
  }
  if (field.labels && Object.keys(field.labels).length) {
    const singleLabel = getSingleLabelName(
      frames.length ? frames : frame ? [frame] : []
    );
    if (singleLabel && field.labels[singleLabel] != null && field.labels[singleLabel] !== "") {
      parts.push(String(field.labels[singleLabel]));
      labelsAdded = true;
    } else {
      const allLabels = formatLabels(field.labels);
      if (allLabels) {
        parts.push(allLabels);
        labelsAdded = true;
      }
    }
  }
  if (frame && !frameNameAdded && !labelsAdded && isGenericValueName(field.name || "")) {
    if (frame.name) {
      parts.push(frame.name);
      frameNameAdded = true;
    }
  }
  if (parts.length) return parts.join(" ");
  if (field.name) return field.name;
  if (frame?.name) return frame.name;
  return TIME_SERIES_VALUE_FIELD_NAME;
}
function getSingleLabelName(frames) {
  const keys = /* @__PURE__ */ new Set();
  for (const fr of frames) {
    for (const f of fr.fields) {
      if (!f.labels) continue;
      for (const k of Object.keys(f.labels)) keys.add(k);
      if (keys.size > 1) return null;
    }
  }
  if (keys.size === 1) return [...keys][0];
  return null;
}
const frameRevision = /* @__PURE__ */ new WeakMap();
const normalizedRevision = /* @__PURE__ */ new WeakMap();
let nextRevision = 1;
function assignFrameRevision(frame, revision) {
  const rev = nextRevision++;
  frameRevision.set(frame, rev);
  return rev;
}
function getFrameRevision(frame) {
  return frameRevision.get(frame);
}
function markFrameNormalized(frame, revision) {
  const rev = getFrameRevision(frame) ?? assignFrameRevision(frame);
  frameRevision.set(frame, rev);
  normalizedRevision.set(frame, rev);
  return rev;
}
function isFrameNormalized(frame) {
  const rev = frameRevision.get(frame);
  if (rev == null) return false;
  return normalizedRevision.get(frame) === rev;
}
function customOf(frame) {
  const meta2 = frame.meta;
  if (!meta2 || typeof meta2 !== "object") return {};
  const custom = meta2.custom;
  if (!custom || typeof custom !== "object" || Array.isArray(custom)) return {};
  return custom;
}
function frameContextMatches(frame, ctx) {
  if (!ctx) return true;
  const custom = customOf(frame);
  const checks = [
    [ctx.source, custom.source],
    [ctx.datasourceUid, custom.datasourceUid],
    [ctx.profile, custom.profile],
    [ctx.signal, custom.signal],
    [ctx.requestId, custom.requestId],
    [ctx.semanticKind, custom.semanticKind],
    [
      ctx.preferredVisualisationType,
      custom.preferredVisualisationType ?? frame.meta?.preferredVisualisationType
    ]
  ];
  for (const [want, have] of checks) {
    if (want == null) continue;
    if (have !== want) return false;
  }
  if (ctx.refId != null && frame.refId != null && frame.refId !== ctx.refId) {
    return false;
  }
  return true;
}
function canSkipNormalize(frame, ctx) {
  return isFrameNormalized(frame) && frameContextMatches(frame, ctx);
}
function cloneValue$1(v) {
  if (v == null || typeof v !== "object") return v;
  if (Array.isArray(v)) return v.map(cloneValue$1);
  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 allocValues(len) {
  const values = new Array(len);
  for (let i = 0; i < len; i++) values[i] = null;
  return values;
}
function normalizeDataFrames(frames, ctx) {
  return (frames ?? []).map((frame) => {
    if (canSkipNormalize(frame, ctx)) {
      return 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;
      const src = f.values ?? [];
      const values = allocValues(len);
      const isTime = type === "time" || /^time$/i.test(f.name);
      if (isTime) type = "time";
      for (let i = 0; i < src.length && i < len; i++) {
        const v = src[i];
        if (isTime) {
          values[i] = normalizeTimeValue(v, () => {
            nanosecondFields.add(f.name);
          });
          continue;
        }
        if (type === "number") {
          if (v == null || v === "") {
            values[i] = null;
            continue;
          }
          if (typeof v === "number") {
            values[i] = v;
            continue;
          }
          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);
              values[i] = s;
            } else {
              values[i] = Number(v);
            }
            continue;
          }
          if (typeof v === "string") {
            if (v === "NaN") {
              values[i] = NaN;
              continue;
            }
            if (v === "+Inf" || v === "Infinity") {
              values[i] = Infinity;
              continue;
            }
            if (v === "-Inf" || v === "-Infinity") {
              values[i] = -Infinity;
              continue;
            }
            if (isUint64String(v)) {
              uint64Fields.add(f.name);
              values[i] = v;
              continue;
            }
            const n2 = Number(v);
            values[i] = Number.isFinite(n2) || n2 === Infinity || n2 === -Infinity || Number.isNaN(n2) ? n2 : null;
            continue;
          }
          const n = Number(v);
          values[i] = Number.isFinite(n) || n === Infinity || n === -Infinity || Number.isNaN(n) ? n : null;
          continue;
        }
        values[i] = v;
      }
      return {
        name: f.name,
        type,
        config: { ...f.config || {} },
        values,
        labels: asStringLabels(f.labels),
        state: f.state ? { ...f.state } : void 0
      };
    });
    const prevMeta = frame.meta ? cloneValue$1(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;
    }
    const out = 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
      }))
    });
    markFrameNormalized(out);
    return out;
  });
}
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 formattedValueToString(val) {
  return `${val.prefix ?? ""}${val.text}${val.suffix ?? ""}`;
}
function toFixed(value, decimals) {
  if (decimals == null) {
    if (!Number.isFinite(value)) return String(value);
    if (Number.isInteger(value) || Math.abs(value - Math.round(value)) < 1e-9) {
      return String(Math.round(value));
    }
    const abs = Math.abs(value);
    const d = abs >= 100 ? 0 : abs >= 1 ? 1 : abs >= 0.01 ? 2 : 3;
    return String(Number(value.toFixed(d)));
  }
  return value.toFixed(Math.max(0, Math.min(10, Math.floor(decimals))));
}
function toFixedUnit(unit = "") {
  return (value, decimals) => ({
    text: toFixed(value, decimals),
    suffix: unit ? ` ${unit}` : void 0
  });
}
function scaledUnits(factor, extArray, offset = 0) {
  return (value, decimals) => {
    if (value === null || value === void 0 || Number.isNaN(value)) {
      return { text: "" };
    }
    let si = offset;
    let v = Math.abs(value);
    while (v >= factor && si < extArray.length - 1) {
      v /= factor;
      si += 1;
    }
    const sign = value < 0 ? "-" : "";
    return {
      // When decimals is null/undefined, toFixed uses auto precision (Grafana axis ticks).
      text: `${sign}${toFixed(v, decimals)}`,
      suffix: extArray[si] ? ` ${extArray[si]}` : void 0
    };
  };
}
function booleanValueFormatter(t2 = "True", f = "False") {
  return (value) => ({ text: value ? t2 : f });
}
function locale(value, decimals) {
  try {
    return {
      text: value.toLocaleString(void 0, {
        maximumFractionDigits: decimals ?? 2,
        minimumFractionDigits: decimals ?? void 0
      })
    };
  } catch {
    return { text: toFixed(value, decimals) };
  }
}
function stringFormatter(value) {
  return { text: value == null ? "" : String(value) };
}
function dateTimeAsIso(value) {
  try {
    return { text: new Date(value).toISOString() };
  } catch {
    return { text: String(value) };
  }
}
function dateTimeAsSystem(value, _decimals, _scaled, timeZone) {
  try {
    const d = new Date(value);
    if (Number.isNaN(d.getTime())) return { text: String(value) };
    const pad = (n) => String(n).padStart(2, "0");
    const tz = String(timeZone || "browser").toLowerCase();
    const useUtc = tz === "utc" || tz === "gmt" || tz === "etc/utc";
    const Y = useUtc ? d.getUTCFullYear() : d.getFullYear();
    const M = useUtc ? d.getUTCMonth() + 1 : d.getMonth() + 1;
    const D = useUtc ? d.getUTCDate() : d.getDate();
    const h2 = useUtc ? d.getUTCHours() : d.getHours();
    const m = useUtc ? d.getUTCMinutes() : d.getMinutes();
    const s = useUtc ? d.getUTCSeconds() : d.getSeconds();
    const text = `${Y}-${pad(M)}-${pad(D)} ${pad(h2)}:${pad(m)}:${pad(s)}`;
    return { text };
  } catch {
    return { text: String(value) };
  }
}
const index$2 = /* @__PURE__ */ new Map();
function register$3(id, fn) {
  index$2.set(id, fn);
}
function build() {
  if (index$2.size) return;
  register$3("none", (v, d) => {
    if (d != null) return { text: Number(v).toFixed(d) };
    if (!Number.isFinite(v)) return { text: String(v) };
    if (Number.isInteger(v) || Math.abs(v - Math.round(v)) < 1e-9)
      return { text: String(Math.round(v)) };
    const abs = Math.abs(v);
    if (abs >= 100 && Math.abs(v - Math.round(v)) < 0.5)
      return { text: String(Math.round(v)) };
    const decimals = abs >= 1e3 ? 0 : abs >= 1 ? 1 : abs >= 0.01 ? 2 : 3;
    return { text: String(Number(v.toFixed(decimals))) };
  });
  register$3("short", scaledUnits(1e3, ["", "K", "Mil", "Bil", "Tri"]));
  register$3("percent", (v, d) => ({
    text: d == null ? String(v) : v.toFixed(d),
    suffix: "%"
  }));
  register$3("percentunit", (v, d) => {
    const p = v * 100;
    return {
      text: d == null ? String(Number(p.toPrecision(12))) : p.toFixed(d),
      suffix: "%"
    };
  });
  register$3("locale", (v, d) => locale(v, d));
  register$3("string", (_v) => stringFormatter(_v));
  register$3("bool", booleanValueFormatter());
  register$3("boolean", booleanValueFormatter());
  for (const u of ["ns", "µs", "ms", "s", "m", "h", "d"]) {
    register$3(u, toFixedUnit(u));
  }
  register$3(
    "bytes",
    scaledUnits(1024, ["B", "KiB", "MiB", "GiB", "TiB", "PiB"])
  );
  register$3("decbytes", scaledUnits(1e3, ["B", "kB", "MB", "GB", "TB", "PB"]));
  register$3("bits", scaledUnits(1e3, ["b", "Kbit", "Mbit", "Gbit", "Tbit"]));
  register$3("decbits", scaledUnits(1e3, ["b", "Kbit", "Mbit", "Gbit", "Tbit"]));
  register$3("kbytes", scaledUnits(1024, ["KiB", "MiB", "GiB", "TiB"]));
  register$3("mbytes", scaledUnits(1024, ["MiB", "GiB", "TiB"]));
  for (const u of [
    "cps",
    "ops",
    "reqps",
    "rps",
    "wps",
    "iops",
    "binBps",
    "Bps",
    "pps"
  ]) {
    register$3(u, toFixedUnit(u));
  }
  register$3("dateTimeAsIso", (v) => dateTimeAsIso(v));
  register$3("dateTimeAsSystem", (v) => dateTimeAsSystem(v));
  register$3("sci", (v, d) => ({ text: v.toExponential(d ?? 2) }));
  register$3("humidity", toFixedUnit("%H"));
  register$3("dB", toFixedUnit("dB"));
  register$3("dBm", toFixedUnit("dBm"));
  register$3("celsius", toFixedUnit("°C"));
  register$3("fahrenheit", toFixedUnit("°F"));
  register$3("farenheit", toFixedUnit("°F"));
  register$3("lengthm", toFixedUnit("m"));
  register$3("lengthmm", toFixedUnit("mm"));
  register$3("velocityms", toFixedUnit("m/s"));
}
function getValueFormat(id) {
  build();
  if (!id) return toFixedUnit("");
  if (index$2.has(id)) return index$2.get(id);
  if (id.startsWith("currency")) {
    const sym = id.split(":")[1] || "$";
    return (v, d) => ({
      text: (d == null ? v : Number(v.toFixed(d))).toString(),
      prefix: sym
    });
  }
  if (id.startsWith("time:")) {
    return (v) => dateTimeAsIso(v);
  }
  return toFixedUnit(id);
}
function sortThresholds(steps) {
  return [...steps].sort((a, b) => a.value - b.value);
}
function getActiveThreshold(value, thresholds) {
  if (!thresholds?.steps?.length) return void 0;
  const steps = sortThresholds(thresholds.steps);
  let active = steps[0];
  for (const step of steps) {
    if (value >= step.value) active = step;
  }
  return active;
}
function applyValueMappings(value, mappings) {
  if (!mappings?.length) return void 0;
  for (const m of mappings) {
    if (m.type === "value") {
      const opts = m.options;
      const key = String(value);
      if (opts[key]?.text != null) return opts[key].text;
    }
    if (m.type === "range") {
      const opts = m.options;
      const n = Number(value);
      if (!Number.isNaN(n) && (opts.from == null || n >= opts.from) && (opts.to == null || n <= opts.to)) {
        return opts.result?.text;
      }
    }
    if (m.type === "regex") {
      const opts = m.options;
      if (opts.pattern) {
        try {
          if (new RegExp(opts.pattern).test(String(value ?? "")))
            return opts.result?.text;
        } catch {
        }
      }
    }
    if (m.type === "special") {
      const opts = m.options;
      if (opts.match === "null" && (value == null || value === ""))
        return opts.result?.text;
      if (opts.match === "nan" && typeof value === "number" && Number.isNaN(value))
        return opts.result?.text;
      if (opts.match === "true" && value === true) return opts.result?.text;
      if (opts.match === "false" && value === false) return opts.result?.text;
      if (opts.match === "empty" && value === "") return opts.result?.text;
    }
  }
  return void 0;
}
const NAMED_VIZ_COLORS = {
  green: "#73BF69",
  red: "#F2495C",
  yellow: "#FADE2A",
  orange: "#FF9830",
  blue: "#5794F2",
  purple: "#B877D9",
  gray: "#808080",
  grey: "#808080",
  "super-light-text": "#CCCCDC",
  text: "#CCCCDC"
};
const DEFAULT_THRESHOLDS_STEPS = [
  { value: Number.NEGATIVE_INFINITY, color: "green" },
  { value: 80, color: "red" }
];
function resolveVizColor(color) {
  if (!color) return void 0;
  if (color.startsWith("#") || color.startsWith("rgb")) return color;
  return NAMED_VIZ_COLORS[color] ?? NAMED_VIZ_COLORS[color.toLowerCase()] ?? color;
}
const GRYLRD_STOPS = [
  [115, 191, 105],
  // green #73BF69
  [226, 192, 61],
  // mid (Grafana fieldColor.test calcFn(_, 0.5))
  [242, 73, 92]
  // red #F2495C
];
function continuousGrYlRd(percent) {
  const t2 = Math.max(0, Math.min(1, percent));
  const stops = GRYLRD_STOPS;
  const x = t2 * (stops.length - 1);
  const i = Math.min(Math.floor(x), stops.length - 2);
  const f = x - i;
  const a = stops[i];
  const b = stops[i + 1];
  const r = Math.round(a[0] + (b[0] - a[0]) * f);
  const g = Math.round(a[1] + (b[1] - a[1]) * f);
  const bl = Math.round(a[2] + (b[2] - a[2]) * f);
  return `rgb(${r}, ${g}, ${bl})`;
}
function getFieldColor(value, config2 = {}) {
  if (config2.color?.mode === "fixed" && config2.color.fixedColor) {
    return resolveVizColor(config2.color.fixedColor);
  }
  if (config2.color?.mode === "palette-classic") {
    return "#7EB26D";
  }
  if (config2.color?.mode === "continuous-GrYlRd" || config2.color?.mode === "continuous-RdYlGr") {
    const min = config2.min ?? 0;
    const max = config2.max ?? 100;
    const delta = max - min || 1;
    let percent = (value - min) / delta;
    if (!Number.isFinite(percent)) percent = 0;
    percent = Math.max(0, Math.min(1, percent));
    if (config2.color?.mode === "continuous-RdYlGr") percent = 1 - percent;
    return continuousGrYlRd(percent);
  }
  const thresholds = config2.thresholds?.steps?.length ? config2.thresholds : { steps: DEFAULT_THRESHOLDS_STEPS };
  return resolveVizColor(getActiveThreshold(value, thresholds)?.color);
}
function anyToNumber(value) {
  if (value == null || value === "") return NaN;
  if (typeof value === "number") return value;
  if (typeof value === "boolean") return value ? 1 : 0;
  const n = Number(value);
  return n;
}
function toStringProcessor(value) {
  return {
    text: value == null ? "" : String(value),
    numeric: anyToNumber(value)
  };
}
function getDisplayProcessor(options) {
  if (!options?.field) return toStringProcessor;
  const field = options.field;
  const config2 = field.config ?? {};
  let unit = config2.unit;
  if (field.type === "time" && !unit) unit = "dateTimeAsSystem";
  if (field.type === "boolean" && !unit) unit = "bool";
  if (field.type === "string" && !unit) unit = "string";
  const formatFunc = getValueFormat(unit || "none");
  return (value, adjacentDecimals) => {
    const mappedText = applyValueMappings(value, config2.mappings);
    const mappedColor = getMappingColor(value, config2.mappings);
    if (unit === "string") {
      return {
        text: mappedText ?? (value == null ? "" : String(value)),
        numeric: NaN,
        color: mappedColor ?? getFieldColor(anyToNumber(value), config2)
      };
    }
    const numeric = anyToNumber(value);
    if (mappedText != null) {
      return {
        text: mappedText,
        numeric,
        color: mappedColor ?? (Number.isFinite(numeric) ? getFieldColor(numeric, config2) : void 0)
      };
    }
    if (value == null || value === "") {
      return {
        text: config2.noValue != null ? String(config2.noValue) : "-",
        numeric: NaN
      };
    }
    if (typeof value === "number" && Number.isNaN(value)) {
      return { text: "NaN", numeric: NaN };
    }
    if (value === Infinity || value === -Infinity) {
      return { text: String(value), numeric: value };
    }
    const decimals = adjacentDecimals ?? config2.decimals;
    let text;
    let prefix;
    let suffix;
    if (Number.isFinite(numeric)) {
      let fv;
      if (unit === "dateTimeAsSystem" || unit === "dateTimeAsIso") {
        fv = dateTimeAsSystem(
          numeric,
          decimals,
          void 0,
          options?.timeZone
        );
        if (unit === "dateTimeAsIso") {
          try {
            fv = { text: new Date(numeric).toISOString() };
          } catch {
            fv = dateTimeAsSystem(
              numeric,
              decimals,
              void 0,
              options?.timeZone
            );
          }
        }
      } else {
        fv = formatFunc(numeric, decimals);
      }
      text = fv.text;
      prefix = fv.prefix;
      suffix = fv.suffix;
    } else {
      text = String(value);
    }
    let percent;
    if (Number.isFinite(numeric) && config2.min != null && config2.max != null && config2.max !== config2.min) {
      percent = (numeric - Number(config2.min)) / (Number(config2.max) - Number(config2.min));
      percent = Math.max(0, Math.min(1, percent));
    }
    let color = mappedColor;
    if (!color && Number.isFinite(numeric)) {
      if (config2.thresholds?.mode === "percentage" && percent != null) {
        color = getActiveThreshold(percent * 100, {
          steps: sortThresholds(config2.thresholds.steps).map((s) => ({
            ...s
            // steps already 0-100 in percentage mode
          }))
        })?.color;
      } else {
        color = getFieldColor(numeric, config2);
      }
    }
    const display = {
      text,
      numeric: Number.isFinite(numeric) ? numeric : NaN,
      prefix,
      suffix,
      color,
      percent
    };
    return display;
  };
}
function getMappingColor(value, mappings) {
  if (!mappings?.length) return void 0;
  for (const m of mappings) {
    if (m.type === "value") {
      const opts = m.options;
      const hit = opts[String(value)];
      if (hit?.color) return hit.color;
    }
    if (m.type === "range") {
      const opts = m.options;
      const n = Number(value);
      if (!Number.isNaN(n) && (opts.from == null || n >= opts.from) && (opts.to == null || n <= opts.to)) {
        if (opts.result?.color) return opts.result.color;
      }
    }
  }
  return void 0;
}
function numericValues(field) {
  return field.values.map((v) => v == null || v === "" ? null : Number(v)).filter((v) => v != null && !Number.isNaN(v));
}
function reduceField$1(field, reducers = [
  "lastNotNull"
  /* lastNotNull */
]) {
  const nums = numericValues(field);
  const out = {};
  for (const r of reducers) {
    if (r === "count") {
      out[r] = nums.length;
      continue;
    }
    if (r === "allIsNull") {
      out[r] = field.values.every((v) => v == null || v === "");
      continue;
    }
    if (r === "allIsZero") {
      out[r] = nums.length > 0 && nums.every((n) => n === 0);
      continue;
    }
    if (r === "distinctCount") {
      out[r] = new Set(nums).size;
      continue;
    }
    if (r === "changeCount") {
      let c = 0;
      for (let i = 1; i < nums.length; i++) if (nums[i] !== nums[i - 1]) c++;
      out[r] = c;
      continue;
    }
    if (!nums.length) {
      out[r] = null;
      continue;
    }
    switch (r) {
      case "last":
        out[r] = Number(field.values[field.values.length - 1]);
        break;
      case "lastNotNull":
        out[r] = nums[nums.length - 1];
        break;
      case "first":
        out[r] = Number(field.values[0]);
        break;
      case "firstNotNull":
        out[r] = nums[0];
        break;
      case "min":
        out[r] = Math.min(...nums);
        break;
      case "max":
        out[r] = Math.max(...nums);
        break;
      case "mean":
        out[r] = nums.reduce((a, b) => a + b, 0) / nums.length;
        break;
      case "sum":
        out[r] = nums.reduce((a, b) => a + b, 0);
        break;
      case "range":
        out[r] = Math.max(...nums) - Math.min(...nums);
        break;
      case "diff":
        out[r] = nums[nums.length - 1] - nums[0];
        break;
      case "diffperc": {
        const a = nums[0];
        out[r] = a === 0 ? null : (nums[nums.length - 1] - a) / Math.abs(a) * 100;
        break;
      }
      case "delta": {
        let d = 0;
        for (let i = 1; i < nums.length; i++) {
          const step = nums[i] - nums[i - 1];
          if (step > 0) d += step;
        }
        out[r] = d;
        break;
      }
      case "step": {
        let maxStep = 0;
        for (let i = 1; i < nums.length; i++)
          maxStep = Math.max(maxStep, Math.abs(nums[i] - nums[i - 1]));
        out[r] = maxStep;
        break;
      }
      case "variance": {
        const mean = nums.reduce((a, b) => a + b, 0) / nums.length;
        out[r] = nums.reduce((a, b) => a + (b - mean) ** 2, 0) / nums.length;
        break;
      }
      case "stdDev": {
        const mean = nums.reduce((a, b) => a + b, 0) / nums.length;
        const v = nums.reduce((a, b) => a + (b - mean) ** 2, 0) / nums.length;
        out[r] = Math.sqrt(v);
        break;
      }
      case "median": {
        const s = [...nums].sort((a, b) => a - b);
        const mid = Math.floor(s.length / 2);
        out[r] = s.length % 2 ? s[mid] : (s[mid - 1] + s[mid]) / 2;
        break;
      }
      case "logmin": {
        const pos = nums.filter((n) => n > 0);
        out[r] = pos.length ? Math.min(...pos) : null;
        break;
      }
      default:
        out[r] = nums[nums.length - 1];
    }
  }
  return out;
}
const CLASSIC_PALETTE_DARK = [
  "#73BF69",
  // green
  "#F2CC0C",
  // semi-dark-yellow
  "#5794F2",
  // blue
  "#FF9830",
  // orange
  "#F2495C",
  // red
  "#B877D9",
  // purple
  "#37872D",
  // dark-green
  "#E0B400",
  // dark-yellow
  "#1F60C4",
  // dark-blue
  "#FA6400",
  // dark-orange
  "#C4162A",
  // dark-red
  "#8F3BB8",
  // dark-purple
  "#C8F2C2",
  // super-light-green
  "#FFF899",
  // super-light-yellow
  "#C0D8FF"
  // super-light-blue
];
const CLASSIC_PALETTE_LIGHT = [
  "#56A64B",
  // green (one notch darker)
  "#E0B400",
  // semi-dark-yellow → dark-yellow
  "#3274D9",
  // blue
  "#FF780A",
  // orange
  "#E02F44",
  // red
  "#A352CC",
  // purple
  "#19730E",
  // dark-green
  "#CC9D00",
  // dark-yellow
  "#1250B0",
  // dark-blue
  "#E55400",
  // dark-orange
  "#AD0317",
  // dark-red
  "#7C2EA3",
  // dark-purple
  "#96D98D",
  // super-light-green
  "#FFEE52",
  // super-light-yellow
  "#8AB8FF"
  // super-light-blue
];
function resolveThemeModeHint(mode2) {
  if (mode2 === "light" || mode2 === "dark") return mode2;
  if (typeof document !== "undefined") {
    const t2 = document.documentElement.getAttribute("data-theme") || document.documentElement.dataset.theme || document.body?.dataset?.theme || "";
    if (String(t2).toLowerCase() === "light") return "light";
  }
  return "dark";
}
function getClassicPalette$1(mode2) {
  return resolveThemeModeHint(mode2) === "light" ? CLASSIC_PALETTE_LIGHT : CLASSIC_PALETTE_DARK;
}
function resolveNamedColor(color, ctx) {
  if (!color) return color;
  if (color.startsWith("#") || color.startsWith("rgb") || color.startsWith("hsl") || color.startsWith("var(")) {
    return color;
  }
  if (ctx?.getColorByName) return ctx.getColorByName(color);
  const mode2 = resolveThemeModeHint(ctx?.mode);
  const table = mode2 === "light" ? CLASSIC_PALETTE_LIGHT : CLASSIC_PALETTE_DARK;
  const names = [
    "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"
  ];
  const idx = names.indexOf(color);
  if (idx >= 0) return table[idx];
  return color;
}
function getFieldSeriesColor(fieldName, seriesIndex, config2 = {}, theme) {
  const ctx = {};
  const palette2 = getClassicPalette$1(ctx.mode);
  if (config2.color?.mode === "fixed" && config2.color.fixedColor) {
    return resolveNamedColor(config2.color.fixedColor, ctx);
  }
  if (config2.color?.mode === "palette-classic" || !config2.color?.mode) {
    return palette2[seriesIndex % palette2.length];
  }
  return palette2[Math.abs(hash(fieldName)) % palette2.length];
}
function hash(s) {
  let h2 = 0;
  for (let i = 0; i < s.length; i++) h2 = h2 * 31 + s.charCodeAt(i) | 0;
  return h2;
}
function getThresholdColor(value, config2, theme) {
  const ctx = {};
  const c = getActiveThreshold(value, config2.thresholds)?.color;
  return c ? resolveNamedColor(c, ctx) : void 0;
}
function formatValue(value, config2 = {}) {
  const processor = getDisplayProcessor({
    field: {
      name: "v",
      type: typeof value === "string" ? "string" : "number",
      config: config2,
      values: []
    }
  });
  return formattedValueToString(processor(value));
}
function reduceField(field, reducers = ["lastNotNull"]) {
  const r = reduceField$1(field, reducers);
  const out = {};
  for (const [k, v] of Object.entries(r)) {
    if (typeof v === "boolean") out[k] = v ? 1 : 0;
    else if (Array.isArray(v)) out[k] = v.length;
    else out[k] = v;
  }
  return out;
}
function clamp$1(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 h2 = 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 + h2 / 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$1(color, value) {
  if (color === "") return "#000000";
  value = clamp$1(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$1(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$1(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);
}
function getContrastText(background, darkText = "#ffffff", lightText = "#000000", threshold = 3) {
  return getContrastRatio(darkText, background) >= threshold ? darkText : lightText;
}
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 getContrastText2(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$1(result.main, 0.15);
    if (!result.contrastText)
      result.contrastText = getContrastText2(result.main);
    if (!result.borderTransparent)
      result.borderTransparent = alpha$1(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: getContrastText2,
    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-shade": colors.secondary.shade,
    "--grafana-secondary-text": colors.secondary.text,
    "--grafana-secondary-border": colors.secondary.border,
    "--grafana-secondary-transparent": colors.secondary.transparent,
    "--grafana-secondary-contrast": colors.secondary.contrastText,
    "--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,
    "--grafana-radius-sm": shape.radius.sm,
    "--grafana-radius-md": shape.radius.md,
    "--grafana-radius-lg": shape.radius.lg,
    // 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$1 = reactive({
  preference: "dark"
});
const theme2Ref = shallowRef(
  createTheme({ colors: { mode: "dark" } })
);
function onThemeChange(fn) {
  listeners$1.add(fn);
  return () => listeners$1.delete(fn);
}
function systemPrefersDark() {
  if (typeof window === "undefined" || !window.matchMedia) return true;
  return window.matchMedia("(prefers-color-scheme: dark)").matches;
}
function resolveMode(pref = state$1.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 t2 = q.get("theme");
    if (t2 === "light" || t2 === "dark") return t2;
  } catch {
  }
  return null;
}
function readBootTheme() {
  try {
    const boot = globalThis.__grafana_boot_data__ ?? globalThis.grafanaBootData;
    const t2 = boot?.user?.theme;
    if (t2 === "light" || t2 === "dark" || t2 === "system") return t2;
  } 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$1.preference);
  notify(mode2);
}
function initTheme(options) {
  const fallback = resolveInitialPreference();
  const preference = options?.preference ?? fallback.preference;
  const runtimeOnly = options?.runtimeOnly ?? fallback.runtimeOnly;
  state$1.preference = preference;
  const mode2 = runtimeOnly ?? resolveMode(preference);
  rebuildTheme(mode2, !runtimeOnly);
  return mode2;
}
function useTheme() {
  const resolved = computed(() => {
    const url = readUrlTheme();
    if (url) return url;
    return resolveMode(state$1.preference);
  });
  const setMode = (mode2, opts) => {
    state$1.preference = mode2;
    const effective = opts?.runtimeOnly ? resolveMode(mode2) : readUrlTheme() ?? resolveMode(mode2);
    rebuildTheme(effective, !opts?.runtimeOnly);
  };
  const setRuntimeMode = (mode2) => {
    rebuildTheme(mode2, false);
  };
  return {
    /** User preference including 'system' */
    mode: readonly(computed(() => state$1.preference)),
    preference: readonly(computed(() => state$1.preference)),
    /** Resolved light|dark */
    resolved,
    theme2: readonly(theme2Ref),
    setMode,
    setRuntimeMode,
    tokens: computed(() => {
      const t2 = theme2Ref.value;
      return {
        bg: t2.colors.background.canvas,
        panelBg: t2.colors.background.primary,
        text: t2.colors.text.primary,
        primary: t2.colors.primary.main,
        border: t2.colors.border.medium
      };
    })
  };
}
if (typeof window !== "undefined") {
  try {
    watchSystemTheme(() => {
      if (state$1.preference === "system" && !readUrlTheme()) {
        rebuildTheme(resolveMode("system"), false);
      }
    });
  } catch {
  }
}
function hasPermission(action) {
  try {
    return Boolean(getBootData().user.permissions[action]);
  } catch {
    return false;
  }
}
function usePermissions() {
  return {
    can: hasPermission,
    canReadDashboards: () => hasPermission("dashboards:read"),
    canWriteDashboards: () => hasPermission("dashboards:write"),
    canReadDatasources: () => hasPermission("datasources:read"),
    canWriteDatasources: () => hasPermission("datasources:write")
  };
}
function isFeatureEnabled(name) {
  try {
    return Boolean(getBootData().settings.featureToggles[name]);
  } catch {
    return false;
  }
}
const MARKS = [
  "app-shell-painted",
  "route-skeleton-painted",
  "dashboard-document-ready",
  "dashboard-shell-painted",
  "dashboard-interactive",
  "panel-plugin-ready",
  "panel-first-data",
  "visible-panels-settled",
  "dashboard-settled"
];
const config = {
  enabled: false,
  counters: false
};
const counters = /* @__PURE__ */ new Map();
const ring = [];
const RING_MAX = 200;
function now() {
  return typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
}
function pushRing(type, name, detail) {
  ring.push({ t: now(), type, name, detail });
  if (ring.length > RING_MAX) ring.shift();
}
function readQueryFlag() {
  try {
    if (typeof location === "undefined") return false;
    return new URLSearchParams(location.search).get("perf") === "1";
  } catch {
    return false;
  }
}
function configurePerf(opts = {}) {
  if (typeof opts.enabled === "boolean") config.enabled = opts.enabled;
  if (typeof opts.counters === "boolean") config.counters = opts.counters;
  if (readQueryFlag()) {
    config.enabled = true;
    config.counters = true;
  }
}
function isPerfEnabled() {
  if (readQueryFlag()) return true;
  return config.enabled;
}
function markName(name, detail) {
  const gen = detail?.generation != null ? `:g${detail.generation}` : "";
  const panel2 = detail?.panelId != null ? `:p${detail.panelId}` : "";
  return `gv:${name}${gen}${panel2}`;
}
function perfMark(name, detail) {
  if (!isPerfEnabled()) return;
  const full = markName(name, detail);
  try {
    if (typeof performance !== "undefined" && performance.mark) {
      performance.mark(full);
    }
  } catch {
  }
  pushRing("mark", full, detail);
}
function perfMeasure(name, startMark, endMark, detail) {
  if (!isPerfEnabled()) return;
  const start = markName(startMark, detail);
  const end = markName(endMark, detail);
  const full = `gv:measure:${name}${detail?.generation != null ? `:g${detail.generation}` : ""}`;
  try {
    if (typeof performance !== "undefined" && performance.measure) {
      performance.measure(full, start, end);
    }
  } catch {
  }
  pushRing("measure", full, detail);
}
function perfCount(name, delta = 1, detail) {
  if (!isPerfEnabled() || !config.counters) return;
  const key = detail?.panelId != null ? `${name}:p${detail.panelId}` : name;
  counters.set(key, (counters.get(key) || 0) + delta);
  pushRing("counter", key, detail);
}
function getPerfCounters() {
  return Object.fromEntries(counters.entries());
}
function getPerfRing() {
  return ring.slice();
}
function resetPerf() {
  counters.clear();
  ring.length = 0;
  try {
    if (typeof performance !== "undefined" && performance.clearMarks) {
      for (const m of MARKS) performance.clearMarks(`gv:${m}`);
    }
  } catch {
  }
}
function listPerfMarkNames() {
  return [...MARKS];
}
class QueryPriorityQueue {
  items = [];
  seq = 0;
  get size() {
    return this.items.filter((i) => !i.cancelled).length;
  }
  enqueue(value, priority) {
    const item = {
      priority,
      seq: this.seq++,
      value,
      cancelled: false
    };
    this.items.push(item);
    this.items.sort((a, b) => b.priority - a.priority || a.seq - b.seq);
    return item;
  }
  /** Mark matching queued items cancelled (O(n)); start-time skip is O(1). */
  cancelWhere(pred) {
    let n = 0;
    for (const item of this.items) {
      if (!item.cancelled && pred(item.value)) {
        item.cancelled = true;
        n += 1;
      }
    }
    return n;
  }
  dequeue() {
    while (this.items.length) {
      const item = this.items.shift();
      if (!item.cancelled) return item.value;
    }
    return void 0;
  }
  clear() {
    this.items = [];
  }
}
class QueryScheduler {
  concurrency;
  resolveDataSource;
  cacheTtlMs;
  maxCacheEntries;
  maxCacheBytes;
  cacheBytes = 0;
  active = /* @__PURE__ */ new Map();
  inflight = /* @__PURE__ */ new Map();
  queue = new QueryPriorityQueue();
  running = 0;
  cache = /* @__PURE__ */ new Map();
  stats = reactive({
    started: 0,
    completed: 0,
    cancelled: 0,
    errors: 0,
    cacheHits: 0,
    skippedHidden: 0
  });
  constructor(opts) {
    this.concurrency = opts.concurrency ?? 6;
    this.resolveDataSource = opts.resolveDataSource;
    this.cacheTtlMs = opts.cacheTtlMs ?? 0;
    this.maxCacheEntries = opts.maxCacheEntries ?? 200;
    this.maxCacheBytes = opts.maxCacheBytes ?? 32 * 1024 * 1024;
  }
  run(request) {
    if (request.visible === false) {
      this.stats.skippedHidden += 1;
      return Promise.resolve({
        state: LoadingStateEnum.Done,
        series: [],
        timeRange: request.range,
        request: { requestId: request.requestId }
      });
    }
    const cacheKey = this.cacheTtlMs > 0 ? this.buildCacheKey(request) : "";
    if (cacheKey) {
      const hit = this.cache.get(cacheKey);
      if (hit && hit.expiresAt > Date.now()) {
        hit.lastAccess = Date.now();
        this.stats.cacheHits += 1;
        perfCount("query.cacheHit");
        return Promise.resolve({
          ...hit.data,
          request: { requestId: request.requestId }
        });
      }
    }
    const dedupKey = cacheKey || this.buildCacheKey(request);
    const existing = this.inflight.get(dedupKey);
    if (existing) {
      perfCount("query.dedup");
      return existing.then((data) => ({
        ...data,
        request: { requestId: request.requestId }
      }));
    }
    this.cancel(request.requestId);
    const controller = new AbortController();
    const priority = typeof request.priority === "number" ? request.priority : request.visible === false ? 0 : 10;
    const promise = this.enqueue(
      () => this.execute(request, controller.signal, cacheKey || dedupKey),
      priority,
      () => ({
        state: LoadingStateEnum.NotStarted,
        series: [],
        timeRange: request.range,
        request: { requestId: request.requestId }
      })
    );
    this.inflight.set(dedupKey, promise);
    promise.finally(() => {
      if (this.inflight.get(dedupKey) === promise) this.inflight.delete(dedupKey);
    });
    this.active.set(request.requestId, {
      requestId: request.requestId,
      controller,
      promise,
      dedupKey
    });
    promise.finally(() => {
      const cur = this.active.get(request.requestId);
      if (cur?.promise === promise) this.active.delete(request.requestId);
    });
    return promise;
  }
  cancel(requestId) {
    const cur = this.active.get(requestId);
    if (cur) {
      cur.controller.abort();
      this.active.delete(requestId);
      if (cur.dedupKey && this.inflight.get(cur.dedupKey) === cur.promise) {
        this.inflight.delete(cur.dedupKey);
      }
      this.stats.cancelled += 1;
      perfCount("query.cancelled");
    }
  }
  cancelAll() {
    for (const id of [...this.active.keys()]) this.cancel(id);
  }
  clearCache() {
    this.cache.clear();
    this.cacheBytes = 0;
  }
  /** Drop queued (not yet running) work — resolve as NotStarted and drain. */
  cancelQueued() {
    while (true) {
      const next = this.queue.dequeue();
      if (!next) break;
      next.cancel();
    }
    this.queue.clear();
  }
  buildCacheKey(request) {
    const targets = (request.targets ?? []).map((t2) => ({
      refId: t2.refId,
      hide: t2.hide,
      datasource: typeof t2.datasource === "string" ? t2.datasource : t2.datasource ? { uid: t2.datasource.uid, type: t2.datasource.type } : void 0,
      // stable JSON of non-secret query fields
      query: sanitizeQueryFields(t2)
    }));
    return JSON.stringify({
      backendMode: getBackendMode(),
      targets,
      from: request.range.from.getTime(),
      to: request.range.to.getTime(),
      maxDataPoints: request.maxDataPoints,
      intervalMs: request.intervalMs,
      scopedVars: request.scopedVars,
      panelId: request.panelId
    });
  }
  putCache(key, data) {
    if (!key || this.cacheTtlMs <= 0) return;
    const estimatedBytes = estimatePanelDataBytes(data);
    const prev = this.cache.get(key);
    if (prev) this.cacheBytes -= prev.estimatedBytes;
    this.cache.set(key, {
      key,
      data,
      expiresAt: Date.now() + this.cacheTtlMs,
      lastAccess: Date.now(),
      estimatedBytes
    });
    this.cacheBytes += estimatedBytes;
    this.evictCache();
  }
  evictCache() {
    while (this.cache.size > this.maxCacheEntries || this.cacheBytes > this.maxCacheBytes) {
      const oldest = [...this.cache.values()].sort(
        (a, b) => a.lastAccess - b.lastAccess
      )[0];
      if (!oldest) break;
      this.cache.delete(oldest.key);
      this.cacheBytes = Math.max(0, this.cacheBytes - oldest.estimatedBytes);
    }
  }
  enqueue(fn, priority = 0, cancelledResult) {
    return new Promise((resolve, reject) => {
      let settled = false;
      const settleResolve = (v) => {
        if (settled) return;
        settled = true;
        resolve(v);
      };
      const settleReject = (e) => {
        if (settled) return;
        settled = true;
        reject(e);
      };
      const run = () => {
        this.running += 1;
        this.stats.started += 1;
        perfCount("query.started");
        fn().then(settleResolve, settleReject).finally(() => {
          this.running -= 1;
          const next = this.queue.dequeue();
          if (next) next.run();
        });
      };
      if (this.running < this.concurrency) run();
      else {
        perfCount("query.queued");
        this.queue.enqueue(
          {
            run,
            cancel: () => {
              this.stats.cancelled += 1;
              settleResolve(
                cancelledResult ? cancelledResult() : {
                  state: LoadingStateEnum.NotStarted,
                  series: [],
                  timeRange: { from: /* @__PURE__ */ new Date(0), to: /* @__PURE__ */ new Date(0) }
                }
              );
            }
          },
          priority
        );
      }
    });
  }
  async execute(request, signal, cacheKey) {
    const visible = request.targets.filter((t2) => !t2.hide);
    if (!visible.length) {
      return {
        state: LoadingStateEnum.Done,
        series: [],
        timeRange: request.range,
        request: { requestId: request.requestId }
      };
    }
    try {
      const groups = /* @__PURE__ */ new Map();
      for (const t2 of visible) {
        const key = t2.datasource?.uid ?? t2.datasource?.type ?? "default";
        const list = groups.get(key) ?? [];
        list.push(t2);
        groups.set(key, list);
      }
      const series = [];
      const groupEntries = [...groups.entries()];
      const results = await Promise.all(
        groupEntries.map(async ([key, targets]) => {
          if (signal.aborted) throw new DOMException("Aborted", "AbortError");
          const ds2 = this.resolveDataSource(targets[0].datasource ?? key);
          if (!ds2) {
            return {
              error: `Data source not found: ${key}`,
              frames: []
            };
          }
          const res = await ds2.query({ ...request, targets }, signal);
          return {
            error: null,
            frames: res.data.map((f) => ({
              ...f,
              refId: f.refId ?? targets[0].refId
            }))
          };
        })
      );
      for (const r of results) {
        if (r.error) {
          this.stats.errors += 1;
          return {
            state: LoadingStateEnum.Error,
            series: [],
            timeRange: request.range,
            error: { message: r.error },
            request: { requestId: request.requestId }
          };
        }
        series.push(...r.frames);
      }
      this.stats.completed += 1;
      const data = {
        state: LoadingStateEnum.Done,
        series,
        timeRange: request.range,
        request: { requestId: request.requestId }
      };
      this.putCache(cacheKey, data);
      return data;
    } catch (e) {
      if (e.name === "AbortError") {
        return {
          state: LoadingStateEnum.NotStarted,
          series: [],
          timeRange: request.range,
          request: { requestId: request.requestId }
        };
      }
      this.stats.errors += 1;
      return {
        state: LoadingStateEnum.Error,
        series: [],
        timeRange: request.range,
        error: { message: e instanceof Error ? e.message : String(e) },
        request: { requestId: request.requestId }
      };
    }
  }
}
const SECRET_KEY = /password|token|secret|authorization|credential|api[_-]?key/i;
function sanitizeQueryFields(target) {
  const out = {};
  for (const [k, v] of Object.entries(target)) {
    if (k === "datasource") continue;
    if (SECRET_KEY.test(k)) continue;
    if (v == null || typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
      out[k] = v;
    } else if (Array.isArray(v) || typeof v === "object" && v) {
      try {
        out[k] = JSON.parse(JSON.stringify(v));
      } catch {
      }
    }
  }
  return out;
}
function estimatePanelDataBytes(data) {
  let n = 256;
  for (const frame of data.series ?? []) {
    n += 64;
    for (const field of frame.fields ?? []) {
      const values = field.values;
      if (Array.isArray(values)) n += values.length * 16;
      else n += 64;
    }
  }
  return n;
}
const catalogs = {
  "en-US": {
    "dashboard.save": "Save",
    "dashboard.edit": "Edit",
    "dashboard.view": "View",
    "dashboard.share": "Share",
    "dashboard.refresh": "Refresh",
    "dashboard.addPanel": "Add panel",
    "dashboard.import": "Import JSON",
    "dashboard.undo": "Undo",
    "dashboard.redo": "Redo",
    "dashboard.inspect": "Inspect",
    "dashboard.copy": "Copy",
    "dashboard.duplicate": "Duplicate panel",
    "dashboard.paste": "Paste",
    "dashboard.library": "Panel library",
    "dashboard.saveLibrary": "Save to library",
    "dashboard.screenshot": "Screenshot",
    "dashboard.loading": "Loading…",
    "dashboard.list": "Dashboards",
    "dashboard.new": "New",
    "dashboard.time.custom": "Custom range",
    "dashboard.time.last5m": "Last 5 minutes",
    "dashboard.time.last15m": "Last 15 minutes",
    "dashboard.time.last1h": "Last 1 hour",
    "dashboard.time.last6h": "Last 6 hours",
    "dashboard.time.last24h": "Last 24 hours",
    "dashboard.time.last7d": "Last 7 days",
    "datasources.title": "Data sources",
    "datasources.add": "Add data source",
    "datasources.search": "Search data sources…",
    "datasources.allTypes": "All types",
    "datasources.default": "default",
    "datasources.empty": "No data sources match",
    "common.cancel": "Cancel",
    "common.apply": "Apply",
    "common.close": "Close",
    "common.search": "Search",
    "common.delete": "Delete",
    "common.settings": "Settings",
    "panel.options": "Panel options",
    "panel.field": "Field",
    "panel.query": "Query",
    "panel.transform": "Transform",
    "panel.alert": "Alert",
    "editor.thresholds": "Thresholds",
    "editor.unit": "Unit",
    "editor.mappings": "Value mappings",
    "editor.color": "Color",
    "time.timezone": "Time zone",
    "time.browser": "Browser time",
    "panel.noData": "No data",
    "dashboard.empty": "Empty dashboard",
    "dashboard.variables": "Variables"
  },
  "zh-Hans": {
    "dashboard.save": "保存",
    "dashboard.edit": "编辑",
    "dashboard.view": "查看",
    "dashboard.share": "分享",
    "dashboard.refresh": "刷新",
    "dashboard.addPanel": "添加面板",
    "dashboard.import": "导入 JSON",
    "dashboard.undo": "撤销",
    "dashboard.redo": "重做",
    "dashboard.inspect": "检查",
    "dashboard.copy": "复制",
    "dashboard.duplicate": "复制面板",
    "dashboard.paste": "粘贴",
    "dashboard.library": "面板库",
    "dashboard.saveLibrary": "存入库",
    "dashboard.screenshot": "截图",
    "dashboard.loading": "加载中…",
    "dashboard.list": "仪表盘",
    "dashboard.new": "新建",
    "dashboard.time.custom": "自定义范围",
    "dashboard.time.last5m": "最近 5 分钟",
    "dashboard.time.last15m": "最近 15 分钟",
    "dashboard.time.last1h": "最近 1 小时",
    "dashboard.time.last6h": "最近 6 小时",
    "dashboard.time.last24h": "最近 24 小时",
    "dashboard.time.last7d": "最近 7 天",
    "datasources.title": "数据源",
    "datasources.add": "添加数据源",
    "datasources.search": "搜索数据源…",
    "datasources.allTypes": "全部类型",
    "datasources.default": "默认",
    "datasources.empty": "无匹配的数据源",
    "common.cancel": "取消",
    "common.apply": "应用",
    "common.close": "关闭",
    "common.search": "搜索",
    "common.delete": "删除",
    "common.settings": "设置",
    "panel.options": "面板选项",
    "panel.field": "字段",
    "panel.query": "查询",
    "panel.transform": "转换",
    "panel.alert": "告警",
    "editor.thresholds": "阈值",
    "editor.unit": "单位",
    "editor.mappings": "值映射",
    "editor.color": "颜色",
    "time.timezone": "时区",
    "time.browser": "浏览器时区",
    "panel.noData": "暂无数据",
    "dashboard.empty": "空仪表盘",
    "dashboard.variables": "变量"
  }
};
const state = reactive({ locale: "zh-Hans", rtl: false });
function setLocale(locale2) {
  state.locale = catalogs[locale2] ? locale2 : "zh-Hans";
  if (typeof document !== "undefined") {
    document.documentElement.lang = state.locale;
  }
}
function setRTL(rtl) {
  state.rtl = rtl;
  if (typeof document !== "undefined") {
    const direction = rtl ? "rtl" : "ltr";
    document.documentElement.setAttribute("dir", direction);
    document.documentElement.dataset.direction = direction;
  }
}
function t(key, fallback) {
  return catalogs[state.locale]?.[key] ?? catalogs["zh-Hans"][key] ?? catalogs["en-US"][key] ?? fallback ?? key;
}
function useI18n() {
  return {
    locale: readonly(computed(() => state.locale)),
    rtl: readonly(computed(() => state.rtl)),
    t,
    setLocale,
    setRTL
  };
}
function registerI18nCatalog(locale2, entries) {
  catalogs[locale2] = { ...catalogs[locale2] ?? {}, ...entries };
}
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 || {} }
  }));
}
function getRuntimeDataSourceSettings(uid) {
  const s = registry$1.get(uid);
  return s ? { ...s, jsonData: { ...s.jsonData || {} } } : void 0;
}
function mergeDataSourceSettings(parts) {
  const byUid2 = /* @__PURE__ */ new Map();
  const backendDefaultUids = /* @__PURE__ */ new Set();
  const runtimeDefaultUids = /* @__PURE__ */ new Set();
  for (const s of parts.seeds || []) {
    if (!s?.uid) continue;
    byUid2.set(s.uid, {
      ...s,
      source: "seed",
      isDefault: false,
      jsonData: { ...s.jsonData || {} }
    });
  }
  for (const s of parts.backend || []) {
    if (!s?.uid) continue;
    const prev = byUid2.get(s.uid);
    byUid2.set(s.uid, {
      ...prev || {},
      ...s,
      source: "backend",
      // explicit false/true from backend wins; undefined keeps previous only if prev was backend/runtime
      isDefault: s.isDefault === true ? true : s.isDefault === false ? false : !!prev?.isDefault && prev.source !== "seed",
      jsonData: { ...prev?.jsonData || {}, ...s.jsonData || {} }
    });
    if (s.isDefault === true) backendDefaultUids.add(s.uid);
  }
  for (const s of parts.runtime || []) {
    if (!s?.uid) continue;
    const prev = byUid2.get(s.uid);
    const merged = {
      ...prev || {},
      ...s,
      source: "runtime",
      jsonData: { ...prev?.jsonData || {}, ...s.jsonData || {} }
    };
    if (prev?.source === "backend") {
      if (s.url == null && prev.url != null) merged.url = prev.url;
      if (!s.type && prev.type) merged.type = prev.type;
    }
    byUid2.set(s.uid, merged);
    if (s.isDefault === true) runtimeDefaultUids.add(s.uid);
  }
  for (const [uid, s] of byUid2) {
    if (s.source === "seed") {
      byUid2.set(uid, { ...s, isDefault: false });
      continue;
    }
    if ((s.type === "grafana-testdata-datasource" || s.type === "mixed" || uid === "testdata" || uid === "mixed") && s.source !== "backend" && backendDefaultUids.size > 0 && !backendDefaultUids.has(uid)) {
      byUid2.set(uid, { ...s, isDefault: false });
    }
  }
  if (backendDefaultUids.size > 1) {
    throw new RuntimeDataSourceSettingsError(
      `multiple default datasources from backend: ${[...backendDefaultUids].join(",")}`,
      "DATASOURCE_DEFAULT_CONFLICT"
    );
  }
  let chosenDefault;
  if (backendDefaultUids.size === 1) {
    chosenDefault = [...backendDefaultUids][0];
  } else if (runtimeDefaultUids.size === 1) {
    chosenDefault = [...runtimeDefaultUids][0];
  } else if (runtimeDefaultUids.size > 1) {
    throw new RuntimeDataSourceSettingsError(
      `multiple default datasources: ${[...runtimeDefaultUids].join(",")}`,
      "DATASOURCE_DEFAULT_CONFLICT"
    );
  }
  for (const [uid, s] of byUid2) {
    const want = chosenDefault != null && uid === chosenDefault;
    if (!!s.isDefault !== want) {
      byUid2.set(uid, { ...s, isDefault: want });
    }
  }
  return [...byUid2.values()];
}
function getEffectiveDefaultDataSource(list) {
  const items = list ?? listRuntimeDataSourceSettings();
  return items.find((s) => s.isDefault);
}
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 [];
  }
}
async function getDataSourceByUid(uid) {
  try {
    const res = await backendSrv.get(
      `/api/datasources/uid/${encodeURIComponent(uid)}`
    );
    return res.data ?? null;
  } catch {
    return null;
  }
}
async function saveDataSource(ds2) {
  const uid = String(ds2.uid || "");
  if (uid) {
    try {
      const res2 = await backendSrv.put(
        `/api/datasources/uid/${encodeURIComponent(uid)}`,
        ds2
      );
      return res2.data ?? ds2;
    } catch {
    }
  }
  const res = await backendSrv.post("/api/datasources", ds2);
  return res.data ?? ds2;
}
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 isDataSourceError(e) {
  return e instanceof DataSourceError;
}
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
  });
}
let provider = null;
const memory = /* @__PURE__ */ new Map();
function configureRuntimeCredentials(p) {
  provider = p;
}
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;
  if (!provider) return null;
  const c = await provider(uid);
  return c ?? null;
}
function clearRuntimeCredentials() {
  memory.clear();
  provider = 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 getDatasourceHttpLog(uid) {
  if (!uid) return [...httpLog];
  return httpLog.filter((e) => e.uid === uid);
}
function clearDatasourceHttpLog() {
  httpLog.length = 0;
}
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 t2 = setTimeout(() => resolve(), ms);
    if (signal) {
      const onAbort = () => {
        clearTimeout(t2);
        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 DEFAULT_TTL_MS = 5 * 6e4;
const DEFAULT_MAX_BYTES = 32 * 1024 * 1024;
const store$1 = /* @__PURE__ */ new Map();
let totalBytes$1 = 0;
let maxBytes = DEFAULT_MAX_BYTES;
let ttlMs = DEFAULT_TTL_MS;
const SENSITIVE_HEADER = /(authorization|cookie|token|password|secret|api[-_]?key|signoz-api-key)/i;
function configureQueryInspectorStore(opts) {
  if (opts?.maxBytes != null) maxBytes = opts.maxBytes;
  if (opts?.ttlMs != null) ttlMs = opts.ttlMs;
}
function clearQueryInspectorStore() {
  store$1.clear();
  totalBytes$1 = 0;
}
function redactHeaders(h2) {
  if (!h2) return {};
  const out = {};
  for (const [k, v] of Object.entries(h2)) {
    out[k] = SENSITIVE_HEADER.test(k) ? "[REDACTED]" : v;
  }
  return out;
}
function redactBody(body) {
  if (body == null) return body;
  const text = typeof body === "string" ? body : JSON.stringify(body);
  const redacted = text.replace(/"auth"\s*:\s*"[^"]*"/gi, '"auth":"[REDACTED]"').replace(/"token"\s*:\s*"[^"]*"/gi, '"token":"[REDACTED]"').replace(/"password"\s*:\s*"[^"]*"/gi, '"password":"[REDACTED]"').replace(/Bearer\s+[A-Za-z0-9\-._~+/]+=*/g, "Bearer [REDACTED]");
  try {
    return JSON.parse(redacted);
  } catch {
    return redacted;
  }
}
function estimateBytes$1(value) {
  try {
    return new TextEncoder().encode(JSON.stringify(value)).length;
  } catch {
    return 0;
  }
}
function purgeExpired(now2 = Date.now()) {
  for (const [k, e] of store$1) {
    if (e.expiresAt <= now2) {
      totalBytes$1 -= e.bytes;
      store$1.delete(k);
    }
  }
}
function evictLru() {
  while (totalBytes$1 > maxBytes && store$1.size) {
    const oldest = store$1.keys().next().value;
    if (!oldest) break;
    const e = store$1.get(oldest);
    totalBytes$1 -= e.bytes;
    store$1.delete(oldest);
  }
}
function makeInspectorKey(requestId, datasourceUid) {
  return `${requestId}::${datasourceUid}`;
}
function putQueryInspectorEntry(input) {
  purgeExpired();
  const key = makeInspectorKey(input.requestId, input.datasourceUid);
  const request = {
    method: input.request?.method,
    url: input.request?.url,
    headers: redactHeaders(input.request?.headers),
    body: redactBody(input.request?.body)
  };
  const entry = {
    key,
    requestId: input.requestId,
    datasourceUid: input.datasourceUid,
    savedAt: Date.now(),
    expiresAt: Date.now() + (input.ttlMs ?? ttlMs),
    bytes: 0,
    request,
    response: input.response,
    stats: input.stats,
    warnings: input.warnings,
    capability: input.capability
  };
  entry.bytes = estimateBytes$1(entry);
  const prev = store$1.get(key);
  if (prev) totalBytes$1 -= prev.bytes;
  store$1.delete(key);
  store$1.set(key, entry);
  totalBytes$1 += entry.bytes;
  evictLru();
  return entry;
}
function getQueryInspectorEntry(requestId, datasourceUid) {
  purgeExpired();
  return store$1.get(makeInspectorKey(requestId, datasourceUid));
}
function listQueryInspectorEntries(datasourceUid) {
  purgeExpired();
  const all = [...store$1.values()];
  return datasourceUid ? all.filter((e) => e.datasourceUid === datasourceUid) : all;
}
function getQueryInspectorStats() {
  purgeExpired();
  return { entries: store$1.size, totalBytes: totalBytes$1, maxBytes, ttlMs };
}
const TYPE_ALIASES = {
  testdata: "grafana-testdata-datasource",
  testdatasource: "grafana-testdata-datasource",
  "test-data": "grafana-testdata-datasource",
  "grafana-testdata-datasource": "grafana-testdata-datasource",
  mixed: "mixed",
  "-- mixed --": "mixed",
  prometheus: "prometheus",
  prom: "prometheus",
  loki: "loki",
  zabbix: "alexanderzobnin-zabbix-datasource",
  "alexanderzobnin-zabbix-datasource": "alexanderzobnin-zabbix-datasource",
  signoz: "signoz"
};
function normalizeDataSourceType(type) {
  const raw = String(type ?? "").trim();
  if (!raw) return "";
  if (TYPE_ALIASES[raw]) return TYPE_ALIASES[raw];
  const lower = raw.toLowerCase();
  if (TYPE_ALIASES[lower]) return TYPE_ALIASES[lower];
  if (lower.includes("testdata") || lower.includes("test-data"))
    return "grafana-testdata-datasource";
  if (lower.includes("zabbix")) return "alexanderzobnin-zabbix-datasource";
  return raw;
}
function normalizeUid(uid) {
  if (uid == null || uid === "") return void 0;
  if (typeof uid === "string") {
    if (uid === "[object Object]") return void 0;
    return uid;
  }
  if (typeof uid === "object") {
    const o = uid;
    if (typeof o.uid === "string" && o.uid && o.uid !== "[object Object]")
      return o.uid;
  }
  return void 0;
}
function loadedIdentity(instances) {
  return [...instances.values()].map((d) => d.uid).sort().join(",") || "(empty)";
}
function createDataSourceCatalog() {
  const instances = /* @__PURE__ */ new Map();
  const appliedFingerprints = /* @__PURE__ */ new Map();
  let hooks = null;
  let ready = false;
  let readyWaiters = [];
  let configureChain = Promise.resolve();
  let configureSeq = 0;
  let lastDefaultConflictLog = "";
  function markReady() {
    ready = true;
    const waiters = readyWaiters;
    readyWaiters = [];
    for (const w of waiters) w();
  }
  function register2(ds2) {
    instances.set(ds2.uid, ds2);
    hooks?.registerRuntimeDataSource?.(ds2.uid, ds2);
  }
  function dispose(uid) {
    if (uid) {
      instances.get(uid)?.dispose?.();
      instances.delete(uid);
      appliedFingerprints.delete(uid);
      hooks?.unregisterRuntimeDataSource?.(uid);
      return;
    }
    for (const id of [...instances.keys()]) {
      dispose(id);
    }
  }
  function resolve(ref2) {
    if (typeof ref2 === "string") {
      const key = ref2.trim();
      if (!key) {
        throw new DataSourceError("DATASOURCE_REQUIRED", "缺少数据源引用", {
          ref: ref2,
          loaded: loadedIdentity(instances)
        });
      }
      const byUid2 = instances.get(key);
      if (byUid2) return byUid2;
      const byName = [...instances.values()].filter((d) => d.name === key);
      if (byName.length === 1) return byName[0];
      if (byName.length > 1) {
        throw new DataSourceError(
          "DATASOURCE_AMBIGUOUS",
          `数据源名称存在多个实例: ${key}`,
          {
            ref: ref2,
            loaded: loadedIdentity(instances)
          }
        );
      }
      const type2 = normalizeDataSourceType(key);
      if (type2) {
        const matches = [...instances.values()].filter(
          (d) => d.type === type2 || normalizeDataSourceType(d.type) === type2 || d.uid === key
        );
        if (type2 === "grafana-testdata-datasource") {
          const preferred = matches.find((d) => d.uid === "testdata") || matches.find((d) => /testdata/i.test(d.uid)) || (matches.length === 1 ? matches[0] : void 0);
          if (preferred) return preferred;
        }
        if (matches.length === 1) return matches[0];
        if (matches.length > 1) {
          throw new DataSourceError(
            "DATASOURCE_AMBIGUOUS",
            `数据源类型存在多个实例: ${key}`,
            { ref: ref2, loaded: loadedIdentity(instances) }
          );
        }
      }
      throw new DataSourceError(
        "DATASOURCE_NOT_FOUND",
        `数据源未找到: ${key}`,
        {
          uid: key,
          ref: ref2,
          loaded: loadedIdentity(instances)
        }
      );
    }
    const rawUid = ref2?.uid;
    const uid = normalizeUid(rawUid);
    const type = normalizeDataSourceType(
      typeof ref2?.type === "string" ? ref2.type : void 0
    );
    const name = typeof ref2?.name === "string" ? ref2.name : void 0;
    if (uid) {
      const hit = instances.get(uid);
      if (hit) {
        if (type && hit.type && normalizeDataSourceType(hit.type) !== type && hit.type !== type) {
          if (normalizeDataSourceType(hit.type) !== type) {
            throw new DataSourceError(
              "DATASOURCE_TYPE_MISMATCH",
              `数据源类型不匹配: expected ${type}, got ${hit.type}`,
              { uid, ref: ref2, loaded: loadedIdentity(instances) }
            );
          }
        }
        return hit;
      }
      if (type === "grafana-testdata-datasource" || /testdata/i.test(uid)) {
        const matches = [...instances.values()].filter(
          (d) => normalizeDataSourceType(d.type) === "grafana-testdata-datasource"
        );
        const preferred = matches.find((d) => d.uid === uid) || matches.find((d) => d.uid === "testdata") || (matches.length === 1 ? matches[0] : void 0);
        if (preferred) return preferred;
      }
      throw new DataSourceError(
        "DATASOURCE_NOT_FOUND",
        `数据源未找到: ${uid}`,
        {
          uid,
          ref: ref2,
          loaded: loadedIdentity(instances)
        }
      );
    }
    if (name) {
      const matches = [...instances.values()].filter(
        (d) => d.name === name || d.name?.toLowerCase() === name.toLowerCase()
      );
      if (matches.length === 1) return matches[0];
      if (matches.length > 1) {
        const preferred = matches.find((d) => d.uid === "testdata") || matches.find(
          (d) => normalizeDataSourceType(d.type) === "grafana-testdata-datasource"
        );
        const types = new Set(
          matches.map((d) => normalizeDataSourceType(d.type) || d.type)
        );
        if (preferred && types.size === 1) return preferred;
        throw new DataSourceError(
          "DATASOURCE_AMBIGUOUS",
          `数据源名称存在多个实例: ${name}`,
          {
            ref: ref2,
            loaded: loadedIdentity(instances)
          }
        );
      }
    }
    if (type) {
      const matches = [...instances.values()].filter(
        (d) => d.type === type || normalizeDataSourceType(d.type) === type
      );
      if (type === "grafana-testdata-datasource") {
        const preferred = matches.find((d) => d.uid === "testdata") || matches.find((d) => /testdata/i.test(d.uid)) || (matches.length === 1 ? matches[0] : void 0);
        if (preferred) return preferred;
      }
      if (matches.length === 0) {
        throw new DataSourceError(
          "DATASOURCE_NOT_FOUND",
          `数据源类型未找到: ${type}`,
          {
            ref: ref2,
            loaded: loadedIdentity(instances)
          }
        );
      }
      if (matches.length > 1) {
        throw new DataSourceError(
          "DATASOURCE_AMBIGUOUS",
          `数据源类型存在多个实例: ${type}`,
          { ref: ref2, loaded: loadedIdentity(instances) }
        );
      }
      return matches[0];
    }
    throw new DataSourceError("DATASOURCE_REQUIRED", "缺少数据源引用", {
      ref: ref2,
      loaded: loadedIdentity(instances)
    });
  }
  function tryResolve(ref2) {
    try {
      return resolve(ref2);
    } catch {
      return void 0;
    }
  }
  async function doConfigure(input) {
    if (!input?.getDataSourcePlugin) {
      throw new Error(
        "DataSourceCatalog.configure requires getDataSourcePlugin"
      );
    }
    hooks = input;
    const seq2 = ++configureSeq;
    let settings = input.settings;
    if (!settings) {
      const runtimeSettings = listRuntimeDataSourceSettings();
      let backendSettings = [];
      if (isGrafanaLiveConfigured()) {
        try {
          const res = await backendSrv.get("/api/datasources");
          const list = Array.isArray(res.data) ? res.data : res.data?.datasources ?? [];
          backendSettings = list.filter(
            (row) => Boolean(row?.uid && row?.type)
          ).map((row) => ({
            uid: String(row.uid),
            type: String(row.type),
            name: String(row.name || row.uid),
            url: typeof row.url === "string" ? row.url : void 0,
            access: typeof row.access === "string" ? row.access : "proxy",
            isDefault: !!row.isDefault,
            jsonData: row.jsonData && typeof row.jsonData === "object" ? row.jsonData : {},
            source: "backend"
          }));
        } catch {
          backendSettings = [];
        }
      }
      const seedSpecs = [
        ["testdata", "grafana-testdata-datasource", "TestData"],
        ["prometheus", "prometheus", "Prometheus"],
        ["loki", "loki", "Loki"],
        ["jaeger", "jaeger", "Jaeger"],
        ["pyroscope", "grafana-pyroscope-datasource", "Pyroscope"],
        ["mixed", "mixed", "Mixed"],
        ["-- Grafana --", "grafana", "Grafana"],
        ["dashboard", "dashboard", "Dashboard"]
      ];
      const seeds = seedSpecs.map(
        ([uid, type, name]) => ({
          uid,
          type,
          name,
          isDefault: false,
          jsonData: {},
          source: "seed"
        })
      );
      try {
        settings = mergeDataSourceSettings({
          runtime: runtimeSettings,
          backend: backendSettings,
          seeds
        });
      } catch (e) {
        const err = e;
        const msg = `${err?.code || "MERGE_ERROR"}:${err?.message || String(e)}`;
        if (msg !== lastDefaultConflictLog) {
          lastDefaultConflictLog = msg;
          console.error(
            "[DataSourceCatalog] merge failed",
            err?.code || err?.message || e
          );
        }
        settings = mergeDataSourceSettings({
          runtime: runtimeSettings.map((s) => ({ ...s, isDefault: false })),
          backend: backendSettings.map((s) => ({ ...s, isDefault: false })),
          seeds
        });
      }
    }
    if (seq2 !== configureSeq) return;
    const desired = /* @__PURE__ */ new Map();
    for (const row of settings ?? []) {
      if (!row?.uid || !row?.type) continue;
      desired.set(row.uid, row);
    }
    for (const uid of [...instances.keys()]) {
      if (!desired.has(uid)) ;
    }
    const settingsFingerprint = (row) => {
      const jd = row.jsonData || {};
      return [
        row.uid,
        row.type,
        row.url || "",
        row.access || "proxy",
        String(jd.dataMode ?? ""),
        String(jd.apiProfile ?? ""),
        String(jd.credentialMode ?? "")
      ].join("|");
    };
    for (const row of desired.values()) {
      const fp = settingsFingerprint(row);
      const existing = instances.get(row.uid);
      const prevFp = appliedFingerprints.get(row.uid);
      if (existing) {
        if (prevFp === void 0) {
          const existingUrl = String(existing.url || "").trim();
          const desiredUrl = String(row.url || "").trim();
          if (!desiredUrl || existingUrl) {
            appliedFingerprints.set(row.uid, fp);
            continue;
          }
          dispose(row.uid);
        } else if (prevFp === fp) {
          continue;
        } else {
          dispose(row.uid);
        }
      }
      const typeKey = normalizeDataSourceType(row.type) || row.type;
      const mod = input.getDataSourcePlugin(typeKey) || input.getDataSourcePlugin(row.type);
      if (!mod?.createDataSource) {
        if (typeof console !== "undefined") {
          console.warn(
            `[DataSourceCatalog] skip uid=${row.uid}: no createDataSource for type=${row.type}` + (typeKey !== row.type ? ` (normalized=${typeKey})` : "") + " — is the plugin registered?"
          );
        }
        continue;
      }
      const api = mod.createDataSource({
        uid: row.uid,
        type: row.type,
        name: row.name,
        url: row.url,
        access: row.access || "proxy",
        jsonData: row.jsonData || {},
        meta: mod.meta ?? {}
      });
      register2({
        uid: row.uid,
        type: row.type,
        name: row.name,
        ...api
      });
      appliedFingerprints.set(row.uid, fp);
    }
    markReady();
  }
  function configure(input = hooks) {
    const run = configureChain.then(() => doConfigure(input));
    configureChain = run.then(
      () => void 0,
      () => void 0
    );
    return run;
  }
  return {
    configure,
    list() {
      return [...instances.values()].map((d) => ({
        uid: d.uid,
        type: d.type,
        name: d.name
      }));
    },
    resolve,
    tryResolve,
    getInstances() {
      return instances;
    },
    register: register2,
    dispose,
    isReady() {
      return ready;
    },
    whenReady() {
      if (ready) return Promise.resolve();
      return new Promise((resolveReady) => {
        readyWaiters.push(resolveReady);
      });
    }
  };
}
let defaultCatalog = null;
function getDataSourceCatalog() {
  if (!defaultCatalog) defaultCatalog = createDataSourceCatalog();
  return defaultCatalog;
}
function resetDataSourceCatalog() {
  defaultCatalog?.dispose();
  defaultCatalog = null;
}
const DEFAULTS = {
  panelPipelineWorker: true,
  progressiveScheduler: true,
  filterOnDemandSelect: true
};
let flags = { ...DEFAULTS };
function readQueryFlags() {
  if (typeof window === "undefined") return null;
  try {
    const sp = new URLSearchParams(window.location.search);
    if (!sp.has("perfFlag")) return null;
    const raw = sp.get("perfFlag");
    if (raw === "0" || raw === "false" || raw === "off") {
      return {
        panelPipelineWorker: false,
        progressiveScheduler: false,
        filterOnDemandSelect: false
      };
    }
    if (raw === "1" || raw === "true" || raw === "on") {
      return {
        panelPipelineWorker: true,
        progressiveScheduler: true,
        filterOnDemandSelect: true
      };
    }
  } catch {
  }
  return null;
}
function readWindowFlags() {
  if (typeof window === "undefined") return null;
  const w = window;
  return w.__GRAFANA_VUE_PERF_FLAGS__ ?? null;
}
function initPerfFlags(overrides) {
  flags = {
    ...DEFAULTS,
    ...readWindowFlags() || {},
    ...readQueryFlags() || {},
    ...overrides || {}
  };
  return { ...flags };
}
function getPerfFlags() {
  return { ...flags };
}
function setPerfFlags(next) {
  flags = { ...flags, ...next };
  return { ...flags };
}
function __resetPerfFlagsForTests() {
  flags = { ...DEFAULTS };
}
const DEFAULT_PIPELINE_WORKER_THRESHOLD_BYTES = 512 * 1024;
function estimateFrameBytes(frames) {
  if (!frames?.length) return 0;
  let n = 0;
  for (const f of frames) {
    const rows = Number(f.length) || 0;
    const cols = Array.isArray(f.fields) ? f.fields.length : 1;
    n += rows * cols * 8 + 256;
  }
  return n;
}
function shouldUsePipelineWorker(input) {
  const thresholdBytes = input.thresholdBytes ?? DEFAULT_PIPELINE_WORKER_THRESHOLD_BYTES;
  const estimatedBytes = typeof input.estimatedBytes === "number" ? input.estimatedBytes : estimateFrameBytes(input.frames);
  if (input.enabled === false) {
    return { useWorker: false, reason: "disabled", estimatedBytes, thresholdBytes };
  }
  if (estimatedBytes < thresholdBytes) {
    return { useWorker: false, reason: "below-threshold", estimatedBytes, thresholdBytes };
  }
  if (typeof Worker === "undefined") {
    return { useWorker: false, reason: "no-worker", estimatedBytes, thresholdBytes };
  }
  return { useWorker: true, reason: "above-threshold", estimatedBytes, thresholdBytes };
}
function createStreamCoalescer(commit) {
  let pending2;
  let raf = null;
  let disposed = false;
  function schedule() {
    if (disposed || raf != null) return;
    const scheduleFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(() => cb(Date.now()), 16);
    raf = scheduleFrame(() => {
      raf = null;
      if (disposed) {
        pending2 = void 0;
        return;
      }
      if (pending2 !== void 0) {
        const v = pending2;
        pending2 = void 0;
        commit(v);
      }
    });
  }
  function push(item) {
    if (disposed) return;
    if (item.complete) {
      pending2 = void 0;
      if (raf != null && typeof cancelAnimationFrame === "function") {
        cancelAnimationFrame(raf);
      }
      raf = null;
      commit(item.value);
      return;
    }
    pending2 = item.value;
    schedule();
  }
  function dispose() {
    disposed = true;
    pending2 = void 0;
    if (raf != null && typeof cancelAnimationFrame === "function") {
      cancelAnimationFrame(raf);
    }
    raf = null;
  }
  return { push, dispose };
}
const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  DEFAULT_PIPELINE_WORKER_THRESHOLD_BYTES,
  DataSourceError,
  GrafanaAuthError,
  NormalizedHeaders,
  OFFLINE_STORAGE_KEYS,
  QueryPriorityQueue,
  QueryScheduler,
  RuntimeDataSourceSettingsError,
  THEME_STORAGE_KEY,
  __resetPerfFlagsForTests,
  applyCredentialHeaders,
  applyGrafanaAuthHeaders,
  axiosHeadersToRecord,
  backendRequest,
  backendSrv,
  clearDatasourceHttpLog,
  clearQueryInspectorStore,
  clearRuntimeCredentials,
  clearRuntimeDataSourceSettings,
  configureBackendSrv,
  configureDatasourceHttpClient,
  configurePerf,
  configureQueryInspectorStore,
  configureRuntimeCredentials,
  configureRuntimeDataSourceSettings,
  createDataSourceCatalog,
  createDefaultBootData,
  createHttpClient,
  createStreamCoalescer,
  datasourceHttp,
  estimateFrameBytes,
  getAppHttp,
  getBackendHttp,
  getBackendMode,
  getBootData,
  getDataSourceByUid,
  getDataSourceCatalog,
  getDatasourceHttpClient,
  getDatasourceHttpLog,
  getEffectiveDefaultDataSource,
  getGrafanaAuthSnapshot,
  getGrafanaAuthToken,
  getGrafanaBaseUrl,
  getLiveDashboardBuilders,
  getPerfCounters,
  getPerfFlags,
  getPerfRing,
  getQueryInspectorEntry,
  getQueryInspectorStats,
  getResourceHttp,
  getRuntimeCredential,
  getRuntimeDataSourceSettings,
  hasPermission,
  initPerfFlags,
  initTheme,
  isDataSourceError,
  isFeatureEnabled,
  isGrafanaLiveConfigured,
  isPerfEnabled,
  listDataSources,
  listPerfMarkNames,
  listQueryInspectorEntries,
  listRuntimeDataSourceSettings,
  makeInspectorKey,
  mergeDataSourceSettings,
  normalizeDataSourceType,
  onThemeChange,
  perfCount,
  perfMark,
  perfMeasure,
  putQueryInspectorEntry,
  readUrlTheme,
  redactToken,
  registerI18nCatalog,
  registerLiveDashboardBuilders,
  requireGrafanaAuthToken,
  resetDataSourceCatalog,
  resetHttpClients,
  resetOfflineStorage,
  resetPerf,
  resolveInitialPreference,
  sanitizeErrorText,
  saveDataSource,
  setBootData,
  setGrafanaAuthToken,
  setLocale,
  setPerfFlags,
  setRTL,
  setRuntimeCredential,
  shouldUsePipelineWorker,
  t,
  useBootData,
  useI18n,
  useLocationService,
  usePermissions,
  useTheme,
  withDataSourceContext
}, Symbol.toStringTag, { value: "Module" }));
const _hoisted_1$2e = ["data-folder-uid", "data-include-vars", "data-show-folder-names", "data-show-headings", "data-max-items", "data-show-folder", "data-show-starred", "data-show-recent", "data-show-search", "data-item-count"];
const _hoisted_2$1M = {
  key: 0,
  class: "empty-state",
  "data-testid": "dashlist-empty"
};
const _hoisted_3$1z = {
  key: 1,
  class: "group",
  "data-testid": "dashlist-starred"
};
const _hoisted_4$1m = {
  key: 0,
  class: "heading",
  "data-testid": "dashlist-header"
};
const _hoisted_5$1b = ["href"];
const _hoisted_6$12 = {
  key: 0,
  class: "folder"
};
const _hoisted_7$$ = {
  key: 2,
  class: "group",
  "data-testid": "dashlist-recent"
};
const _hoisted_8$S = {
  key: 0,
  class: "heading",
  "data-testid": "dashlist-header"
};
const _hoisted_9$N = ["href"];
const _hoisted_10$G = {
  key: 0,
  class: "folder"
};
const _hoisted_11$A = {
  key: 3,
  class: "group",
  "data-testid": "dashlist-search-results"
};
const _hoisted_12$t = {
  key: 0,
  class: "heading",
  "data-testid": "dashlist-header"
};
const _hoisted_13$s = ["href"];
const _hoisted_14$q = {
  key: 0,
  class: "folder"
};
const _sfc_main$3e = /* @__PURE__ */ defineComponent({
  __name: "DashListRenderer",
  props: {
    options: {},
    replaceVariables: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const replace = (s) => props.replaceVariables ? props.replaceVariables(s) : s;
    const maxItems = computed(() => Number(opts.value.maxItems ?? 10));
    const query = computed(() => String(opts.value.query ?? ""));
    const showHeadings = computed(() => opts.value.showHeadings !== false);
    const showFolderNames = computed(() => opts.value.showFolderNames !== false);
    const showStarred = computed(() => opts.value.showStarred !== false);
    const showRecentlyViewed = computed(
      () => opts.value.showRecentlyViewed === true
    );
    const showSearch = computed(() => opts.value.showSearch === true);
    const keepTime = computed(() => opts.value.keepTime === true);
    const includeVars = computed(() => opts.value.includeVars === true);
    const folderUID = computed(() => {
      const v = opts.value.folderUID;
      return v == null || v === "" ? "" : String(v);
    });
    const tags = computed(() => {
      const t2 = opts.value.tags;
      if (Array.isArray(t2)) return t2.map(String);
      return String(t2 || "").split(",").map((s) => s.trim()).filter(Boolean);
    });
    const starred = ref([]);
    const recent = ref([]);
    const searched = ref([]);
    const loading = ref(false);
    function mapDash(d, flags2 = {}) {
      return {
        uid: String(d.uid ?? ""),
        title: String(d.title ?? d.name ?? d.uid ?? ""),
        url: String(d.url || `/d/${d.uid}`),
        folderTitle: d.folderTitle || d.folder || "",
        tags: d.tags || [],
        starred: !!d.isStarred || !!d.starred || !!flags2.starred,
        ...flags2
      };
    }
    async function load() {
      loading.value = true;
      try {
        const tasks = [];
        if (showStarred.value) {
          tasks.push(
            (async () => {
              try {
                const res = await backendSrv.get("/api/search", {
                  type: "dash-db",
                  limit: maxItems.value,
                  starred: "true"
                });
                const raw = Array.isArray(res.data) ? res.data : res.data?.dashboards ?? [];
                starred.value = raw.map((d) => mapDash(d)).slice(0, maxItems.value);
              } catch {
                starred.value = [];
              }
            })()
          );
        } else {
          starred.value = [];
        }
        if (showRecentlyViewed.value) {
          tasks.push(
            (async () => {
              try {
                const res = await backendSrv.get("/api/search", {
                  type: "dash-db",
                  limit: maxItems.value
                });
                const raw = Array.isArray(res.data) ? res.data : res.data?.dashboards ?? [];
                recent.value = raw.map((d) => mapDash(d)).slice(0, maxItems.value);
              } catch {
                recent.value = [];
              }
            })()
          );
        } else {
          recent.value = [];
        }
        if (showSearch.value) {
          tasks.push(
            (async () => {
              try {
                const res = await backendSrv.get("/api/search", {
                  type: "dash-db",
                  limit: maxItems.value,
                  query: replace(query.value) || void 0,
                  folderUIDs: folderUID.value || void 0,
                  tag: tags.value.length ? tags.value.map(replace).join(",") : void 0
                });
                const raw = Array.isArray(res.data) ? res.data : res.data?.dashboards ?? [];
                searched.value = raw.map((d) => mapDash(d)).slice(0, maxItems.value);
              } catch {
                searched.value = [];
              }
            })()
          );
        } else {
          searched.value = [];
        }
        await Promise.all(tasks);
      } finally {
        loading.value = false;
      }
    }
    onMounted(load);
    watch(
      [
        maxItems,
        query,
        folderUID,
        tags,
        showStarred,
        showRecentlyViewed,
        showSearch,
        showHeadings,
        showFolderNames
      ],
      load
    );
    function withQuery(url) {
      const parts = [];
      if (keepTime.value) parts.push("from=now-6h", "to=now");
      if (includeVars.value) parts.push("var-all=1");
      if (!parts.length) return url;
      return url.includes("?") ? `${url}&${parts.join("&")}` : `${url}?${parts.join("&")}`;
    }
    const showEmptyState = computed(
      () => !showStarred.value && !showRecentlyViewed.value && !showSearch.value
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "dashlist",
        "data-testid": "panel-dashlist",
        "data-folder-uid": String(folderUID.value ?? ""),
        "data-include-vars": String(!!opts.value.includeVars),
        "data-show-folder-names": String(showFolderNames.value),
        "data-show-headings": String(showHeadings.value),
        "data-max-items": String(maxItems.value),
        "data-show-folder": String(showFolderNames.value),
        "data-show-starred": String(showStarred.value),
        "data-show-recent": String(showRecentlyViewed.value),
        "data-show-search": String(showSearch.value),
        "data-item-count": String(starred.value.length + recent.value.length + searched.value.length)
      }, [
        showEmptyState.value ? (openBlock(), createElementBlock("div", _hoisted_2$1M, " 未配置数据面板组 ")) : createCommentVNode("v-if", true),
        createCommentVNode(" Starred group (always render section when enabled, even if empty — Grafana keeps empty <ul>) "),
        showStarred.value ? (openBlock(), createElementBlock("section", _hoisted_3$1z, [
          showHeadings.value ? (openBlock(), createElementBlock("div", _hoisted_4$1m, " 已加星标的数据面板 ")) : createCommentVNode("v-if", true),
          createElementVNode("ul", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(starred.value, (it) => {
                return openBlock(), createElementBlock("li", {
                  key: "s" + it.uid,
                  "data-testid": "dashlist-item"
                }, [
                  createElementVNode("a", {
                    class: "link",
                    href: withQuery(it.url)
                  }, toDisplayString(it.title), 9, _hoisted_5$1b),
                  showFolderNames.value && it.folderTitle ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_6$12,
                    toDisplayString(it.folderTitle),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true),
        showRecentlyViewed.value ? (openBlock(), createElementBlock("section", _hoisted_7$$, [
          showHeadings.value ? (openBlock(), createElementBlock("div", _hoisted_8$S, " 最近查看的数据面板 ")) : createCommentVNode("v-if", true),
          createElementVNode("ul", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(recent.value, (it) => {
                return openBlock(), createElementBlock("li", {
                  key: "r" + it.uid,
                  "data-testid": "dashlist-item"
                }, [
                  createElementVNode("a", {
                    class: "link",
                    href: withQuery(it.url)
                  }, toDisplayString(it.title), 9, _hoisted_9$N),
                  showFolderNames.value && it.folderTitle ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_10$G,
                    toDisplayString(it.folderTitle),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true),
        showSearch.value ? (openBlock(), createElementBlock("section", _hoisted_11$A, [
          showHeadings.value ? (openBlock(), createElementBlock("div", _hoisted_12$t, " 搜索 ")) : createCommentVNode("v-if", true),
          createElementVNode("ul", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(searched.value, (it) => {
                return openBlock(), createElementBlock("li", {
                  key: "q" + it.uid,
                  "data-testid": "dashlist-item"
                }, [
                  createElementVNode("a", {
                    class: "link",
                    href: withQuery(it.url)
                  }, toDisplayString(it.title), 9, _hoisted_13$s),
                  showFolderNames.value && it.folderTitle ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_14$q,
                    toDisplayString(it.folderTitle),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$2e);
    };
  }
});
const DashListRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$3e, [["__scopeId", "data-v-beee74dc"]]);
const _sfc_main$3d = /* @__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(DashListRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "dashlist",
    name: "仪表盘列表",
    description: "星标 / 最近 / 搜索仪表盘",
    state: "stable",
    skipDataQuery: true
  },
  _sfc_main$3d
).setPanelOptions((builder) => {
  const cat = ["仪表盘列表"];
  builder.addBoolean(
    {
      id: "keepTime",
      path: "keepTime",
      name: "包含当前时间范围",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "includeVars",
      path: "includeVars",
      name: "包含当前模板变量",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "showStarred",
      path: "showStarred",
      name: "星标",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showRecentlyViewed",
      path: "showRecentlyViewed",
      name: "最近查看",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "showSearch",
      path: "showSearch",
      name: "搜索",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "showHeadings",
      path: "showHeadings",
      name: "显示标题",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showFolderNames",
      path: "showFolderNames",
      name: "显示文件夹名",
      category: cat
    },
    true
  ).addNumber(
    {
      id: "maxItems",
      path: "maxItems",
      name: "最大条目",
      category: cat,
      settings: { min: 1 }
    },
    10
  ).addText(
    {
      id: "query",
      path: "query",
      name: "查询",
      category: cat,
      showIf: (c) => !!c.showSearch
    },
    ""
  ).addText(
    {
      id: "folderUID",
      path: "folderUID",
      name: "文件夹 UID",
      category: cat,
      showIf: (c) => !!c.showSearch
    },
    void 0
  ).addText(
    {
      id: "tags",
      path: "tags",
      name: "标签",
      description: "逗号分隔或 JSON 数组",
      category: cat,
      showIf: (c) => !!c.showSearch
    },
    void 0
  );
}).setRuntimeConsumedPaths([
  "folderUID",
  "includeVars",
  "keepTime",
  "maxItems",
  "query",
  "showFolderNames",
  "showHeadings",
  "showRecentlyViewed",
  "showSearch",
  "showStarred",
  "tags"
]).register();
const _hoisted_1$2d = ["data-limit", "data-only-in-range", "data-only-this-dash", "data-show-time", "data-show-tags", "data-show-user", "data-navigate", "data-nav-before", "data-nav-after", "data-row-count"];
const _hoisted_2$1L = {
  key: 0,
  class: "filter-bar",
  "data-testid": "annolist-filter-bar"
};
const _hoisted_3$1y = { class: "meta-line" };
const _hoisted_4$1l = {
  key: 0,
  class: "time"
};
const _hoisted_5$1a = {
  key: 1,
  class: "user",
  "data-testid": "annolist-user"
};
const _hoisted_6$11 = { class: "text" };
const _hoisted_7$_ = ["href"];
const _hoisted_8$R = {
  key: 0,
  class: "tags"
};
const _hoisted_9$M = {
  key: 1,
  class: "empty",
  "data-testid": "annolist-empty"
};
const _sfc_main$3c = /* @__PURE__ */ defineComponent({
  __name: "AnnoListRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    replaceVariables: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const tagFilter = ref("");
    const hasFilter = computed(() => {
      if (tagFilter.value.trim()) return true;
      const tags = opts.value.tags;
      if (Array.isArray(tags) && tags.length) return true;
      if (typeof tags === "string" && tags.trim()) return true;
      return false;
    });
    const allRows = computed(() => {
      const limit = Number(opts.value.limit ?? 10);
      const onlyInTimeRange = opts.value.onlyInTimeRange !== false && opts.value.onlyInTimeRange !== "false";
      const onlyThisDash = opts.value.onlyFromThisDashboard === true || opts.value.onlyFromThisDashboard === "true" || opts.value.onlyFromThisDashboard === "yes";
      const from = props.data?.timeRange?.from?.getTime?.() ?? 0;
      const to = props.data?.timeRange?.to?.getTime?.() ?? Date.now();
      const navPanel = opts.value.navigateToPanel === false || opts.value.navigateToPanel === "dashboard" || opts.value.navigateToPanel === "false" ? false : true;
      const annos = props.data?.annotations ?? [];
      return annos.filter((a) => {
        if (onlyInTimeRange && !(a.time >= from && a.time <= to)) return false;
        if (onlyThisDash && a.dashboardUID && props.data?.request) {
          const dashUid = props.data.request?.dashboardUID;
          if (dashUid && a.dashboardUID !== dashUid) return false;
        }
        return true;
      }).slice(0, limit).map((a) => ({
        time: opts.value.showTime === false ? "" : new Date(a.time).toISOString(),
        timeMs: a.time,
        text: a.title || a.text || "",
        tags: (a.tags ?? []).join(","),
        user: String(
          a.login || a.user || a.email || ""
        ),
        panelId: a.panelId,
        dashboardUID: a.dashboardUID,
        navigateToPanel: navPanel
      }));
    });
    function parseDurationMs2(raw) {
      const s = String(raw || "").trim();
      const m = s.match(/^(\d+)(ms|s|m|h|d)?$/i);
      if (!m) return 0;
      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;
    }
    function navHref(r) {
      const before = parseDurationMs2(String(opts.value.navigateBefore ?? "10m"));
      const after = parseDurationMs2(String(opts.value.navigateAfter ?? "10m"));
      const from = new Date(r.timeMs - before).toISOString();
      const to = new Date(r.timeMs + after).toISOString();
      if (r.navigateToPanel && r.panelId != null) {
        return `?viewPanel=${r.panelId}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
      }
      return `?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
    }
    const rows = computed(() => {
      const limit = Number(opts.value.limit ?? 10);
      let list = allRows.value;
      const q = tagFilter.value.trim().toLowerCase();
      if (q)
        list = list.filter(
          (r) => r.tags.toLowerCase().includes(q) || r.text.toLowerCase().includes(q) || r.user.toLowerCase().includes(q)
        );
      const filterTags = Array.isArray(opts.value.tags) ? opts.value.tags.map(String) : String(opts.value.tags || "").split(",").map((t2) => t2.trim()).filter(Boolean);
      if (filterTags.length) {
        list = list.filter(
          (r) => filterTags.some(
            (t2) => r.tags.split(",").map((x) => x.trim()).includes(t2)
          )
        );
      }
      return list.slice(0, limit);
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "annolist",
        "data-testid": "panel-annolist",
        "data-limit": String(opts.value.limit ?? 10),
        "data-only-in-range": String(opts.value.onlyInTimeRange !== false),
        "data-only-this-dash": String(
          !!opts.value.onlyFromThisDashboard && opts.value.onlyFromThisDashboard !== false
        ),
        "data-show-time": String(opts.value.showTime !== false),
        "data-show-tags": String(opts.value.showTags !== false),
        "data-show-user": String(opts.value.showUser !== false),
        "data-navigate": String(
          opts.value.navigateToPanel !== false && opts.value.navigateToPanel !== "dashboard"
        ),
        "data-nav-before": String(opts.value.navigateBefore ?? "10m"),
        "data-nav-after": String(opts.value.navigateAfter ?? "10m"),
        "data-row-count": String(rows.value.length)
      }, [
        hasFilter.value ? (openBlock(), createElementBlock("div", _hoisted_2$1L, [
          _cache[1] || (_cache[1] = createElementVNode(
            "b",
            { class: "filter-label" },
            "筛选：",
            -1
            /* CACHED */
          )),
          withDirectives(createElementVNode(
            "input",
            {
              "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => tagFilter.value = $event),
              class: "filter",
              "data-testid": "annolist-filter",
              placeholder: "按标签/文本/用户筛选…"
            },
            null,
            512
            /* NEED_PATCH */
          ), [
            [vModelText, tagFilter.value]
          ])
        ])) : createCommentVNode("v-if", true),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(rows.value, (r, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: "row",
              "data-testid": "annolist-row"
            }, [
              createElementVNode("div", _hoisted_3$1y, [
                opts.value.showTime !== false && r.time ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_4$1l,
                  toDisplayString(r.time),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                opts.value.showUser !== false && r.user ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_5$1a,
                  toDisplayString(r.user),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ]),
              createElementVNode("div", _hoisted_6$11, [
                createTextVNode(
                  toDisplayString(r.text) + " ",
                  1
                  /* TEXT */
                ),
                r.panelId != null || opts.value.navigateBefore || opts.value.navigateAfter ? (openBlock(), createElementBlock("a", {
                  key: 0,
                  class: "nav",
                  "data-testid": "annolist-nav",
                  href: navHref(r)
                }, toDisplayString(r.navigateToPanel && r.panelId != null ? `面板 #${r.panelId}` : "打开时间范围"), 9, _hoisted_7$_)) : createCommentVNode("v-if", true)
              ]),
              opts.value.showTags !== false && r.tags ? (openBlock(), createElementBlock(
                "div",
                _hoisted_8$R,
                toDisplayString(r.tags),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true)
            ]);
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        createCommentVNode(" zh-Hans: Grafana i18n annolist.anno-list-panel.no-annotations-found "),
        !rows.value.length ? (openBlock(), createElementBlock("div", _hoisted_9$M, " 未找到注释 ")) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$2d);
    };
  }
});
const AnnoListRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$3c, [["__scopeId", "data-v-6f5ada7a"]]);
const _sfc_main$3b = /* @__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(AnnoListRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "annolist",
    name: "注解列表",
    state: "stable",
    skipDataQuery: true
  },
  _sfc_main$3b
).setPanelOptions((builder) => {
  const category = ["注解列表"];
  builder.addRadio(
    {
      id: "onlyFromThisDashboard",
      path: "onlyFromThisDashboard",
      name: "查询范围",
      category,
      settings: {
        options: [
          { label: "本仪表盘", value: true },
          { label: "全部仪表盘", value: false }
        ]
      }
    },
    true
  ).addRadio(
    {
      id: "onlyInTimeRange",
      path: "onlyInTimeRange",
      name: "时间范围",
      category,
      settings: {
        options: [
          { label: "当前时间范围", value: true },
          { label: "不限", value: false }
        ]
      }
    },
    true
  ).addText({
    id: "tags",
    path: "tags",
    name: "标签",
    description: "逗号分隔；仅显示包含任一标签的注解",
    category
  }).addNumber(
    {
      id: "limit",
      path: "limit",
      name: "条数限制",
      category,
      settings: { min: 1, max: 1e3 }
    },
    10
  ).addBoolean(
    {
      id: "showUser",
      path: "showUser",
      name: "显示用户",
      category
    },
    true
  ).addBoolean(
    {
      id: "showTime",
      path: "showTime",
      name: "显示时间",
      category
    },
    true
  ).addBoolean(
    {
      id: "showTags",
      path: "showTags",
      name: "显示标签",
      category
    },
    true
  ).addRadio(
    {
      id: "navigateToPanel",
      path: "navigateToPanel",
      name: "链接目标",
      category,
      settings: {
        options: [
          { label: "面板", value: true },
          { label: "仪表盘", value: false }
        ]
      }
    },
    true
  ).addText(
    {
      id: "navigateBefore",
      path: "navigateBefore",
      name: "前移时间",
      description: "如 10m、1h",
      category
    },
    "10m"
  ).addText(
    {
      id: "navigateAfter",
      path: "navigateAfter",
      name: "后移时间",
      description: "如 10m、1h",
      category
    },
    "10m"
  );
}).setRuntimeConsumedPaths([
  "limit",
  "navigateAfter",
  "navigateBefore",
  "navigateToPanel",
  "onlyFromThisDashboard",
  "onlyInTimeRange",
  "showTags",
  "showTime",
  "showUser",
  "tags"
]).register();
const __vite_glob_0_0 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M7.41 8.59 12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>\n';
const __vite_glob_0_1 = '<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_2 = '<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_3 = '<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_4 = '<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_5 = '<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_6 = '<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_7 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M4 9h16v2H4V9zm2-5h12v2H6V4zm-2 10h16v2H4v-2zm2 5h12v2H6v-2z"/></svg>\n';
const __vite_glob_0_8 = '<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_9 = '<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_10 = '<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_11 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 6c3.79 0 7.17 2.13 8.82 5.5-.59 1.22-1.42 2.27-2.41 3.12l1.41 1.41C21.53 14.39 22.66 12.99 23 11.5 21.27 7.11 17 4 12 4c-1.27 0-2.49.2-3.64.57l1.65 1.65C10.66 6.09 11.32 6.5 12 6.5zm-9.5-2.63 1.41-1.41 18.16 18.16-1.41 1.41-3.23-3.23C15.29 18.73 13.7 19 12 19 7 19 2.73 15.89 1 11.5c.69-1.66 1.72-3.13 3-4.32L2.5 3.37zM12 16.5c-1.01 0-1.94-.3-2.72-.81l1.49-1.49c.3.1.62.15.96.15 1.66 0 3-1.34 3-3 0-.34-.05-.66-.15-.96l1.49-1.49c.51.78.81 1.71.81 2.72 0 2.76-2.24 5-5 5zm-3.16-3.16 1.11-1.11c-.06.2-.1.41-.1.62 0 .83.67 1.5 1.5 1.5.21 0 .42-.04.62-.1l1.11-1.11-4.24-4.24z"/></svg>\n';
const __vite_glob_0_12 = '<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_13 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/></svg>\n';
const __vite_glob_0_14 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM9.5 16H8v-1.5c0-.83-.67-1.5-1.5-1.5H6v-1h.5c.83 0 1.5-.67 1.5-1.5V9h1.5v1.5c0 .83.67 1.5 1.5 1.5h.5v1h-.5c-.83 0-1.5.67-1.5 1.5V16zm7.5-1.5h-1.5L14 12l1.5-2.5H17L15.5 12 17 14.5z"/></svg>\n';
const __vite_glob_0_15 = '<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_16 = '<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_17 = '<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_18 = '<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_19 = '<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_20 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z"/></svg>\n';
const __vite_glob_0_21 = '<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_22 = '<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_23 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58s1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41s-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/></svg>\n';
const __vite_glob_0_24 = '<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_25 = '<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-down.svg": __vite_glob_0_0,
  "./assets/angle-left.svg": __vite_glob_0_1,
  "./assets/angle-right.svg": __vite_glob_0_2,
  "./assets/apps.svg": __vite_glob_0_3,
  "./assets/arrow-left.svg": __vite_glob_0_4,
  "./assets/check.svg": __vite_glob_0_5,
  "./assets/cog.svg": __vite_glob_0_6,
  "./assets/compress.svg": __vite_glob_0_7,
  "./assets/copy.svg": __vite_glob_0_8,
  "./assets/exclamation-triangle.svg": __vite_glob_0_9,
  "./assets/external-link-alt.svg": __vite_glob_0_10,
  "./assets/eye-slash.svg": __vite_glob_0_11,
  "./assets/eye.svg": __vite_glob_0_12,
  "./assets/filter.svg": __vite_glob_0_13,
  "./assets/function.svg": __vite_glob_0_14,
  "./assets/info.svg": __vite_glob_0_15,
  "./assets/more.svg": __vite_glob_0_16,
  "./assets/plus.svg": __vite_glob_0_17,
  "./assets/save.svg": __vite_glob_0_18,
  "./assets/search.svg": __vite_glob_0_19,
  "./assets/sort.svg": __vite_glob_0_20,
  "./assets/step-backward.svg": __vite_glob_0_21,
  "./assets/sync.svg": __vite_glob_0_22,
  "./assets/tag.svg": __vite_glob_0_23,
  "./assets/times.svg": __vite_glob_0_24,
  "./assets/trash.svg": __vite_glob_0_25
});
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 = {
  "filter-alt": "filter",
  label: "tag",
  functions: "function",
  "eye-off": "eye-slash",
  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$3a = /* @__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" || props.variant === "toolbar") 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: normalizeClass(["g-button", [`g-button--${__props.variant}`, `g-button--${size.value}`]])
      }, {
        default: withCtx(() => [
          renderSlot(_ctx.$slots, "default", {}, void 0, true)
        ]),
        _: 3
        /* FORWARDED */
      }, 8, ["type", "danger", "size", "disabled", "loading", "html-type", "data-testid", "class"]);
    };
  }
});
const GButton = /* @__PURE__ */ _export_sfc(_sfc_main$3a, [["__scopeId", "data-v-391eb04e"]]);
function flattenSelectOptions(list) {
  if (!list?.length) return [];
  const out = [];
  for (const opt of list) {
    if (opt.options?.length) {
      for (const child of opt.options) out.push(child);
    } else {
      out.push(opt);
    }
  }
  return out;
}
function optionMatchesQuery(opt, q) {
  if (!q) return true;
  const label = String(opt.label ?? "").toLowerCase();
  const value = String(opt.value ?? "").toLowerCase();
  return label.includes(q) || value.includes(q);
}
function shouldUseFilterOnDemand(opts) {
  if (opts.filterOnDemand === true) return true;
  if (opts.filterOnDemand === false) return false;
  return opts.optionCount >= (opts.threshold ?? 200);
}
function windowSelectOptions(opts) {
  const all = opts.options ?? [];
  const q = String(opts.query ?? "").trim().toLowerCase();
  const max = Math.max(1, opts.maxVisible || 100);
  const selected = new Set(
    (Array.isArray(opts.value) ? opts.value : [opts.value]).filter((v) => v != null && v !== "").map(String)
  );
  const flat = flattenSelectOptions(all);
  const pinned = [];
  const rest = [];
  for (const opt of flat) {
    if (selected.has(String(opt.value))) pinned.push(opt);
    else if (optionMatchesQuery(opt, q)) rest.push(opt);
  }
  const out = [...pinned];
  for (const opt of rest) {
    if (out.length >= max) break;
    out.push(opt);
  }
  return out;
}
const _sfc_main$39 = /* @__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 },
    filterOnDemand: { type: Boolean, default: void 0 },
    filterOnDemandThreshold: { default: 200 },
    maxVisibleOptions: { default: 100 }
  },
  emits: ["update:value", "change", "search"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const mode2 = computed(() => props.mode);
    const searchQuery = ref("");
    const useFilterOnDemand = computed(
      () => shouldUseFilterOnDemand({
        filterOnDemand: props.filterOnDemand,
        optionCount: flattenSelectOptions(props.options).length,
        threshold: props.filterOnDemandThreshold
      })
    );
    const effectiveShowSearch = computed(
      () => props.showSearch !== false || useFilterOnDemand.value
    );
    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 (useFilterOnDemand.value) return false;
      if (props.filterOption === void 0) return defaultFilterOption;
      return props.filterOption;
    });
    const visibleOptions = computed(() => {
      const all = props.options ?? [];
      if (!useFilterOnDemand.value) return all;
      return windowSelectOptions({
        options: all,
        query: searchQuery.value,
        maxVisible: props.maxVisibleOptions ?? 100,
        value: props.value
      });
    });
    function onUpdate(v) {
      emit("update:value", v);
      emit("change", v);
    }
    function onSearch(v) {
      searchQuery.value = String(v ?? "");
      emit("search", searchQuery.value);
    }
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Select), mergeProps({
        class: "g-select",
        value: __props.value,
        options: visibleOptions.value ?? [],
        placeholder: __props.placeholder || "请选择",
        disabled: __props.disabled,
        "allow-clear": __props.allowClear,
        mode: mode2.value,
        "show-search": effectiveShowSearch.value,
        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
      }, toHandlers(effectiveShowSearch.value ? { search: onSearch } : {})), null, 16, ["value", "options", "placeholder", "disabled", "allow-clear", "mode", "show-search", "size", "filter-option", "data-testid", "aria-label", "virtual"]);
    };
  }
});
const GSelect = /* @__PURE__ */ _export_sfc(_sfc_main$39, [["__scopeId", "data-v-85453182"]]);
const _sfc_main$38 = /* @__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$2c = ["viewBox", "width", "height", "aria-hidden", "role", "aria-label", "data-icon-name", "innerHTML"];
const _hoisted_2$1K = ["title"];
const _sfc_main$37 = /* @__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$2c)) : !__props.strict ? (openBlock(), createElementBlock("span", {
        key: 1,
        class: "g-icon-missing",
        title: __props.name,
        "data-testid": "g-icon-missing"
      }, "?", 8, _hoisted_2$1K)) : createCommentVNode("v-if", true);
    };
  }
});
const GIcon = /* @__PURE__ */ _export_sfc(_sfc_main$37, [["__scopeId", "data-v-516413fe"]]);
const _sfc_main$36 = /* @__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$36, [["__scopeId", "data-v-b646af45"]]);
const _sfc_main$35 = /* @__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(), createElementBlock(
        Fragment,
        null,
        [
          createCommentVNode("\n    Grafana Switch (refs/.../Switch/Switch.tsx):\n    track input.bg; unchecked knob text.secondary; checked track accent/primary + white knob\n  "),
          createVNode(unref(Switch), {
            class: "g-switch",
            checked: __props.checked,
            disabled: __props.disabled,
            "data-testid": __props.testId,
            "onUpdate:checked": onChange
          }, null, 8, ["checked", "disabled", "data-testid"])
        ],
        2112
        /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
      );
    };
  }
});
const GSwitch = /* @__PURE__ */ _export_sfc(_sfc_main$35, [["__scopeId", "data-v-9ff90a34"]]);
const _sfc_main$34 = /* @__PURE__ */ defineComponent({
  __name: "GTooltip",
  props: {
    title: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        Fragment,
        null,
        [
          createCommentVNode(" Grafana Tooltip: elevated + weak border + z2/z3 "),
          createVNode(unref(Tooltip), {
            title: __props.title,
            "overlay-class-name": "g-tooltip-overlay",
            color: "transparent"
          }, {
            default: withCtx(() => [
              renderSlot(_ctx.$slots, "default")
            ]),
            _: 3
            /* FORWARDED */
          }, 8, ["title"])
        ],
        2112
        /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
      );
    };
  }
});
const GTABLE_VIRT = {
  OVERSCAN: 8,
  DEFAULT_ROW_HEIGHT: 36
};
const EMPTY = {
  start: 0,
  end: 0,
  offsetY: 0,
  bottomSpacer: 0,
  totalHeight: 0,
  windowCount: 0
};
function computeTableVisibleRange(scrollTop, viewportHeight, rowHeight, itemCount, overscan = GTABLE_VIRT.OVERSCAN) {
  if (itemCount <= 0 || rowHeight <= 0) return { ...EMPTY };
  const totalHeight = itemCount * rowHeight;
  const vh = Math.max(0, viewportHeight);
  const st = Math.max(0, Math.min(scrollTop, Math.max(0, totalHeight - vh)));
  const rawStart = Math.floor(st / rowHeight);
  const start = Math.max(0, rawStart - overscan);
  const visibleCount = Math.ceil(vh / rowHeight) + 1;
  const end = Math.min(itemCount, rawStart + visibleCount + overscan);
  const offsetY = start * rowHeight;
  const bottomSpacer = Math.max(0, totalHeight - end * rowHeight);
  return {
    start,
    end,
    offsetY,
    bottomSpacer,
    totalHeight,
    windowCount: Math.max(0, end - start)
  };
}
const _hoisted_1$2b = ["data-testid", "data-virtualized", "data-row-count", "data-row-height", "data-window-start", "data-window-count"];
const TOP_KEY = "__gtable_virt_top";
const BOTTOM_KEY = "__gtable_virt_bottom";
const _sfc_main$33 = /* @__PURE__ */ defineComponent({
  __name: "GTable",
  props: {
    columns: {},
    dataSource: { default: () => [] },
    loading: { type: Boolean },
    testId: {},
    pagination: { type: [Boolean, Object] },
    size: { default: "small" },
    bordered: { type: Boolean, default: false },
    showHeader: { type: Boolean, default: true },
    scroll: {},
    rowClassName: {},
    customRow: {},
    virtual: { type: Boolean, default: false },
    rowHeight: { default: GTABLE_VIRT.DEFAULT_ROW_HEIGHT },
    rowCount: {},
    getRow: {},
    rowsDep: {},
    rowKey: { type: [String, Function], default: "key" }
  },
  emits: ["change", "scroll"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const rootRef = ref(null);
    const scrollTop = ref(0);
    const bodyHeight = ref(0);
    let bodyEl = null;
    let restoreScroll = false;
    const paginationOpt = computed(() => {
      if (props.pagination === true) return {};
      if (props.pagination === false || props.pagination == null) return false;
      return props.pagination;
    });
    const totalRows = computed(() => {
      if (typeof props.rowCount === "number" && props.rowCount >= 0) {
        return props.rowCount;
      }
      return props.dataSource?.length ?? 0;
    });
    const viewportH = computed(() => {
      const y = props.scroll?.y;
      if (typeof y === "number" && y > 0) return y;
      if (typeof y === "string") {
        const n = Number.parseFloat(y);
        if (Number.isFinite(n) && n > 0) return n;
      }
      return bodyHeight.value > 0 ? bodyHeight.value : 280;
    });
    const virtEnabled = computed(
      () => !!props.virtual && paginationOpt.value === false && totalRows.value > 0
    );
    const range = computed(() => {
      if (!virtEnabled.value) {
        return {
          start: 0,
          end: totalRows.value,
          offsetY: 0,
          bottomSpacer: 0,
          totalHeight: totalRows.value * (props.rowHeight || GTABLE_VIRT.DEFAULT_ROW_HEIGHT),
          windowCount: totalRows.value
        };
      }
      return computeTableVisibleRange(
        scrollTop.value,
        viewportH.value,
        props.rowHeight || GTABLE_VIRT.DEFAULT_ROW_HEIGHT,
        totalRows.value
      );
    });
    function resolveRow(index2) {
      if (props.getRow) return props.getRow(index2);
      const row = props.dataSource?.[index2];
      if (row) return row;
      return { key: index2, __rowIndex: index2 };
    }
    const windowedData = computed(() => {
      void props.rowsDep;
      const n = totalRows.value;
      if (!virtEnabled.value) {
        if (props.getRow) {
          const all = new Array(n);
          for (let i = 0; i < n; i++) all[i] = resolveRow(i);
          return all;
        }
        return props.dataSource ?? [];
      }
      const { start, end, offsetY, bottomSpacer } = range.value;
      const out = [];
      if (offsetY > 0) {
        out.push({
          key: TOP_KEY,
          __gtableSpacer: true,
          __virtHeight: offsetY,
          __virtEdge: "top"
        });
      }
      for (let i = start; i < end; i++) {
        const row = resolveRow(i);
        out.push({
          ...row,
          key: row.key ?? i,
          __rowIndex: row.__rowIndex ?? i,
          __virtIndex: row.__virtIndex ?? i
        });
      }
      if (bottomSpacer > 0) {
        out.push({
          key: BOTTOM_KEY,
          __gtableSpacer: true,
          __virtHeight: bottomSpacer,
          __virtEdge: "bottom"
        });
      }
      return out;
    });
    const columnsResolved = computed(() => {
      const cols = props.columns ?? [];
      if (!virtEnabled.value) return cols;
      const colCount = Math.max(cols.length, 1);
      return cols.map((col2, ci) => {
        const prevRender = col2.customRender;
        const prevCell = col2.customCell;
        return {
          ...col2,
          // Fixed height path: force ellipsis unless caller disabled it explicitly.
          ellipsis: col2.ellipsis === false ? false : true,
          customCell: (record, rowIndex, column) => {
            const base = typeof prevCell === "function" ? prevCell(record, rowIndex, column) || {} : {};
            if (record?.__gtableSpacer) {
              if (ci === 0) {
                return {
                  ...base,
                  colSpan: colCount,
                  style: {
                    ...base.style || {},
                    padding: 0,
                    border: "none",
                    height: Number(record.__virtHeight || 0) + "px"
                  }
                };
              }
              return { ...base, colSpan: 0 };
            }
            return base;
          },
          customRender: (ctx) => {
            const rec = ctx?.record;
            if (rec?.__gtableSpacer) {
              if (ci !== 0) return null;
              return h("div", {
                class: "g-table-virt-spacer",
                "data-testid": rec.__virtEdge === "top" ? "table-virt-top" : "table-virt-bottom",
                style: {
                  height: Number(rec.__virtHeight || 0) + "px",
                  padding: 0,
                  margin: 0,
                  border: "none",
                  lineHeight: 0
                }
              });
            }
            if (typeof prevRender === "function") return prevRender(ctx);
            return ctx?.text;
          }
        };
      });
    });
    function mergedRowClassName(record, index2) {
      if (record?.__gtableSpacer) return "g-table-virt-spacer-row";
      if (typeof props.rowClassName === "function") {
        return props.rowClassName(record, index2);
      }
      return props.rowClassName || "";
    }
    function mergedCustomRow(record, index2) {
      if (record?.__gtableSpacer) {
        return {
          class: "g-table-virt-spacer-row",
          "aria-hidden": "true",
          style: {
            height: Number(record.__virtHeight || 0) + "px"
          }
        };
      }
      const base = typeof props.customRow === "function" ? props.customRow(record, index2) || {} : {};
      const logical = typeof record.__virtIndex === "number" ? record.__virtIndex : typeof record.__rowIndex === "number" ? record.__rowIndex : typeof index2 === "number" ? range.value.start + index2 : 0;
      return {
        ...base,
        "data-row-index": String(logical),
        "aria-rowindex": String(logical + 1)
      };
    }
    const scrollOpt = computed(() => {
      if (!props.scroll && !virtEnabled.value) return void 0;
      const y = props.scroll?.y ?? (virtEnabled.value ? Math.max(80, viewportH.value) : void 0);
      return {
        x: props.scroll?.x ?? "max-content",
        ...y != null ? { y } : {}
      };
    });
    function onTableChange(pagination, filters, sorter, extra) {
      emit("change", pagination, filters, sorter, extra);
    }
    function onBodyScroll() {
      if (!bodyEl) return;
      const next = bodyEl.scrollTop;
      if (Math.abs(next - scrollTop.value) < 0.5) return;
      scrollTop.value = next;
      bodyHeight.value = bodyEl.clientHeight || bodyHeight.value;
      emit("scroll", { scrollTop: next, clientHeight: bodyEl.clientHeight });
    }
    function bindBody() {
      const root = rootRef.value;
      if (!root) return;
      const next = root.querySelector(".ant-table-body");
      if (next === bodyEl) return;
      if (bodyEl) bodyEl.removeEventListener("scroll", onBodyScroll);
      bodyEl = next;
      if (bodyEl) {
        bodyEl.addEventListener("scroll", onBodyScroll, { passive: true });
        bodyHeight.value = bodyEl.clientHeight || bodyHeight.value;
        if (restoreScroll) {
          bodyEl.scrollTop = scrollTop.value;
          restoreScroll = false;
        }
      }
    }
    function unbindBody() {
      if (bodyEl) {
        bodyEl.removeEventListener("scroll", onBodyScroll);
        bodyEl = null;
      }
    }
    watch(
      () => [virtEnabled.value, totalRows.value, props.rowHeight, props.scroll?.y],
      () => {
        if (!virtEnabled.value) {
          scrollTop.value = 0;
          return;
        }
        const maxScroll = Math.max(
          0,
          range.value.totalHeight - viewportH.value
        );
        if (scrollTop.value > maxScroll) scrollTop.value = maxScroll;
        void nextTick(() => {
          restoreScroll = true;
          bindBody();
          if (bodyEl) bodyEl.scrollTop = scrollTop.value;
        });
      }
    );
    watch(windowedData, () => {
      restoreScroll = true;
      void nextTick(() => {
        bindBody();
        if (bodyEl) bodyEl.scrollTop = scrollTop.value;
      });
    });
    onMounted(() => {
      void nextTick(() => bindBody());
    });
    onUpdated(() => {
      bindBody();
    });
    onBeforeUnmount(() => unbindBody());
    __expose({
      /** Test / debug helpers */
      getVisibleRange: () => range.value,
      getScrollTop: () => scrollTop.value,
      setScrollTop: (v) => {
        scrollTop.value = Math.max(0, v);
        if (bodyEl) bodyEl.scrollTop = scrollTop.value;
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        ref_key: "rootRef",
        ref: rootRef,
        class: "g-table",
        "data-testid": __props.testId || "g-table",
        "data-virtualized": String(virtEnabled.value),
        "data-row-count": String(totalRows.value),
        "data-row-height": String(__props.rowHeight || unref(GTABLE_VIRT).DEFAULT_ROW_HEIGHT),
        "data-window-start": String(range.value.start),
        "data-window-count": String(range.value.windowCount)
      }, [
        createVNode(unref(Table), {
          columns: columnsResolved.value,
          "data-source": windowedData.value,
          loading: __props.loading,
          pagination: paginationOpt.value,
          size: __props.size,
          bordered: __props.bordered,
          "show-header": __props.showHeader,
          scroll: scrollOpt.value,
          "row-class-name": mergedRowClassName,
          "custom-row": mergedCustomRow,
          "row-key": __props.rowKey,
          onChange: onTableChange
        }, createSlots({
          _: 2
          /* DYNAMIC */
        }, [
          _ctx.$slots.footer ? {
            name: "footer",
            fn: withCtx(() => [
              renderSlot(_ctx.$slots, "footer", {}, void 0, true)
            ]),
            key: "0"
          } : void 0
        ]), 1032, ["columns", "data-source", "loading", "pagination", "size", "bordered", "show-header", "scroll", "row-class-name", "custom-row", "row-key", "onChange"])
      ], 8, _hoisted_1$2b);
    };
  }
});
const GTable = /* @__PURE__ */ _export_sfc(_sfc_main$33, [["__scopeId", "data-v-7b33e39a"]]);
const _hoisted_1$2a = ["data-testid"];
const _sfc_main$32 = /* @__PURE__ */ defineComponent({
  __name: "GQueryExpressionEditor",
  props: {
    modelValue: { default: "" },
    placeholder: { default: "" },
    readOnly: { type: Boolean, default: false },
    disabled: { type: Boolean, default: false },
    runOnEnter: { type: Boolean, default: false },
    completionSource: {},
    testId: {},
    invalid: { type: Boolean, default: false },
    chipPattern: { default: null },
    chipValidate: { type: [Function, null], default: null },
    embedded: { type: Boolean, default: false },
    fontSize: { default: 12 },
    ariaLabel: { default: "" }
  },
  emits: ["update:modelValue", "change", "run", "focus", "blur"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const host = ref(null);
    let view = null;
    let applyingExternal = false;
    const heightStyle = computed(() => ({
      minHeight: props.embedded ? "20px" : "28px"
    }));
    watch(
      () => [props.embedded, props.fontSize, props.chipPattern, props.placeholder],
      () => {
        mountEditor();
      }
    );
    function currentCompletionSource() {
      return props.completionSource;
    }
    function buildChipPlugin() {
      const pattern = props.chipPattern;
      if (!pattern) return null;
      const chipMark = Decoration.mark({ class: "gqe-chip" });
      const fnMark = Decoration.mark({ class: "gqe-fn-name" });
      return ViewPlugin.fromClass(
        class {
          decorations;
          constructor(view2) {
            this.decorations = this._build(view2);
          }
          update(u) {
            if (u.docChanged || u.viewportChanged) {
              this.decorations = this._build(u.view);
            }
          }
          _build(view2) {
            const builder = new RangeSetBuilder();
            const re = new RegExp(
              pattern.source,
              pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g"
            );
            const ranges = [];
            for (const { from, to } of view2.visibleRanges) {
              const text = view2.state.doc.sliceString(from, to);
              re.lastIndex = 0;
              let m;
              while ((m = re.exec(text)) !== null) {
                const matched = m[0];
                const groups = m.slice(1);
                if (props.chipValidate && !props.chipValidate(matched, groups)) {
                  continue;
                }
                const start = from + m.index;
                const end = start + matched.length;
                ranges.push({ from: start, to: end, mark: chipMark });
                if (groups[0]) {
                  const fnStart = start + matched.indexOf(groups[0]);
                  const fnEnd = fnStart + groups[0].length;
                  if (fnStart >= start && fnEnd <= end) {
                    ranges.push({ from: fnStart, to: fnEnd, mark: fnMark });
                  }
                }
              }
            }
            ranges.sort((a, b) => a.from - b.from || a.to - b.to);
            for (const r of ranges) builder.add(r.from, r.to, r.mark);
            return builder.finish();
          }
        },
        { decorations: (v) => v.decorations }
      );
    }
    function buildExtensions() {
      const extensions = [
        history(),
        EditorView.lineWrapping,
        EditorView.contentAttributes.of({
          "aria-label": props.ariaLabel || props.placeholder || "Query expression editor"
        }),
        EditorState.transactionFilter.of((tr) => {
          if (!tr.docChanged) return tr;
          let ok2 = true;
          tr.changes.iterChanges((_fromA, _toA, _fromB, _toB, inserted) => {
            if (inserted.toString().includes("\n")) ok2 = false;
          });
          if (!ok2) {
            return {
              changes: {
                from: 0,
                to: tr.startState.doc.length,
                insert: tr.newDoc.toString().replace(/\n/g, " ")
              },
              selection: tr.selection
            };
          }
          return tr;
        }),
        EditorView.updateListener.of((update) => {
          if (!update.docChanged || applyingExternal) return;
          const text = update.state.doc.toString();
          emit("update:modelValue", text);
          emit("change", text);
        }),
        EditorView.domEventHandlers({
          focus: () => {
            emit("focus");
            return false;
          },
          blur: () => {
            emit("blur");
            return false;
          }
        }),
        EditorView.theme({
          "&": {
            fontSize: `${props.fontSize || 12}px`,
            backgroundColor: props.embedded ? "transparent" : "var(--grafana-input-bg)",
            color: "var(--grafana-text)",
            border: props.embedded ? "0" : "1px solid var(--grafana-border-color-medium)",
            borderRadius: props.embedded ? "0" : "2px"
          },
          "&.cm-focused": {
            outline: props.embedded ? "none" : "1px solid var(--grafana-primary)",
            outlineOffset: "0"
          },
          ".cm-content": {
            padding: props.embedded ? "8px 10px" : "4px 8px",
            fontFamily: "SFMono-Regular, Consolas, Monaco, monospace",
            caretColor: props.embedded ? "var(--grafana-primary)" : "var(--grafana-text)",
            lineHeight: "20px",
            minHeight: "20px"
          },
          ".cm-line": { padding: "0" },
          ".cm-activeLine": { backgroundColor: "transparent" },
          ".cm-placeholder": {
            color: "var(--grafana-text-secondary)",
            fontFamily: "Inter, Helvetica Neue, Arial, sans-serif"
          },
          ".cm-scroller": {
            overflow: "hidden",
            fontFamily: "inherit"
          },
          ".cm-tooltip-autocomplete": {
            backgroundColor: "var(--grafana-bg-elevated)",
            border: "1px solid var(--grafana-border-color-medium)",
            color: "var(--grafana-text)"
          },
          ".cm-tooltip-autocomplete ul li[aria-selected]": {
            backgroundColor: "var(--grafana-hover)"
          },
          ".gqe-chip": {
            background: "var(--grafana-primary-transparent)",
            color: "var(--grafana-text)",
            borderRadius: "3px",
            padding: "1px 4px",
            marginRight: "4px"
          },
          ".gqe-fn-name": {
            color: "var(--grafana-primary)"
          }
        }),
        keymap.of([
          ...completionKeymap,
          ...historyKeymap,
          ...defaultKeymap.filter((k) => {
            const key = k.key;
            return key !== "Enter" && key !== "Shift-Enter";
          })
        ]),
        Prec.highest(
          keymap.of([
            {
              key: "Enter",
              run: (v) => {
                startCompletion(v);
                if (props.runOnEnter) {
                  emit("run");
                  return true;
                }
                return true;
              }
            },
            {
              key: "Shift-Enter",
              run: () => {
                return true;
              }
            },
            {
              key: "Escape",
              run: (v) => {
                closeCompletion(v);
                return true;
              }
            }
          ])
        ),
        autocompletion({
          override: [
            async (context) => {
              const src = currentCompletionSource();
              if (!src) return null;
              return src(context);
            }
          ],
          activateOnTyping: true,
          maxRenderedOptions: 50
        })
      ];
      if (props.placeholder) {
        extensions.push(placeholder(props.placeholder));
      }
      if (props.readOnly || props.disabled) {
        extensions.push(EditorState.readOnly.of(true));
      }
      const chip = buildChipPlugin();
      if (chip) extensions.push(chip);
      return extensions;
    }
    function mountEditor() {
      if (!host.value) return;
      view?.destroy();
      const state2 = EditorState.create({
        doc: props.modelValue || "",
        extensions: buildExtensions()
      });
      view = new EditorView({
        state: state2,
        parent: host.value
      });
    }
    function setDoc(text) {
      if (!view) return;
      const cur = view.state.doc.toString();
      if (cur === text) return;
      applyingExternal = true;
      view.dispatch({
        changes: { from: 0, to: cur.length, insert: text }
      });
      applyingExternal = false;
    }
    onMounted(() => {
      mountEditor();
    });
    onBeforeUnmount(() => {
      view?.destroy();
      view = null;
    });
    watch(
      () => props.modelValue,
      (v) => setDoc(v || "")
    );
    watch(
      () => [
        props.placeholder,
        props.readOnly,
        props.disabled,
        props.runOnEnter,
        props.chipPattern,
        props.chipValidate
      ],
      () => {
        mountEditor();
      }
    );
    __expose({
      focus: () => view?.focus(),
      getView: () => view,
      startCompletion: () => view && startCompletion(view),
      closeCompletion: () => view && closeCompletion(view)
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["g-query-expression-editor", {
          "g-query-expression-editor--invalid": __props.invalid,
          "g-query-expression-editor--disabled": __props.disabled
        }]),
        "data-testid": __props.testId,
        style: normalizeStyle(heightStyle.value)
      }, [
        createElementVNode(
          "div",
          {
            ref_key: "host",
            ref: host,
            class: "g-query-expression-editor__host"
          },
          null,
          512
          /* NEED_PATCH */
        )
      ], 14, _hoisted_1$2a);
    };
  }
});
const GQueryExpressionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$32, [["__scopeId", "data-v-cafaaec7"]]);
var BigValueColorMode = /* @__PURE__ */ ((BigValueColorMode2) => {
  BigValueColorMode2["Background"] = "background";
  BigValueColorMode2["BackgroundSolid"] = "background_solid";
  BigValueColorMode2["None"] = "none";
  BigValueColorMode2["Value"] = "value";
  return BigValueColorMode2;
})(BigValueColorMode || {});
var BigValueGraphMode = /* @__PURE__ */ ((BigValueGraphMode2) => {
  BigValueGraphMode2["None"] = "none";
  BigValueGraphMode2["Line"] = "line";
  BigValueGraphMode2["Area"] = "area";
  return BigValueGraphMode2;
})(BigValueGraphMode || {});
var BigValueJustifyMode = /* @__PURE__ */ ((BigValueJustifyMode2) => {
  BigValueJustifyMode2["Auto"] = "auto";
  BigValueJustifyMode2["Center"] = "center";
  return BigValueJustifyMode2;
})(BigValueJustifyMode || {});
var BigValueTextMode = /* @__PURE__ */ ((BigValueTextMode2) => {
  BigValueTextMode2["Auto"] = "auto";
  BigValueTextMode2["Value"] = "value";
  BigValueTextMode2["ValueAndName"] = "value_and_name";
  BigValueTextMode2["Name"] = "name";
  BigValueTextMode2["None"] = "none";
  return BigValueTextMode2;
})(BigValueTextMode || {});
const LINE_HEIGHT = 1.2;
const MAX_TITLE_SIZE = 30;
const VALUE_FONT_WEIGHT = 500;
let measureCanvas;
function estimateTextWidth(text, fontSize, weight = 400) {
  if (typeof document !== "undefined") {
    try {
      if (!measureCanvas) measureCanvas = document.createElement("canvas");
      const ctx = measureCanvas.getContext("2d");
      if (ctx) {
        ctx.font = `${weight} ${fontSize}px Inter, Helvetica, Arial, sans-serif`;
        const measured = ctx.measureText(String(text ?? "")).width;
        if (measured > 0) return measured;
      }
    } catch {
    }
  }
  const factor = weight >= 500 ? 0.62 : 0.55;
  return Math.max(1, String(text ?? "").length) * fontSize * factor;
}
function calculateFontSize(text, width2, height2, lineHeight = LINE_HEIGHT, maxSize, weight = 400) {
  if (!text) {
    const h2 = height2 / lineHeight;
    return maxSize != null ? Math.min(maxSize, h2) : h2;
  }
  const textSize14 = estimateTextWidth(text, 14, weight);
  const fontSizeBasedOnWidth = width2 / (textSize14 + 2) * 14;
  const fontSizeBasedOnHeight = height2 / lineHeight;
  const optimalSize = Math.min(fontSizeBasedOnHeight, fontSizeBasedOnWidth);
  return Math.min(optimalSize, maxSize ?? optimalSize);
}
function shouldJustifyCenter(mode2, title) {
  if (mode2 === BigValueJustifyMode.Center) return true;
  if (mode2 === BigValueJustifyMode.Auto) return !title;
  return !title;
}
function getTextValues(props) {
  const textMode = String(props.textMode ?? BigValueTextMode.Auto);
  const v = props.value;
  const pct = v.percentChange != null && Number.isFinite(v.percentChange) ? `${v.percentChange > 0 ? "+" : ""}${v.percentChange.toFixed(1)}%` : void 0;
  if (textMode === BigValueTextMode.None) {
    return { valueText: "" };
  }
  if (textMode === BigValueTextMode.Name) {
    return { valueText: v.title ?? "", title: void 0, percentText: pct };
  }
  if (textMode === BigValueTextMode.Value) {
    return { valueText: v.text, title: void 0, percentText: pct };
  }
  if (textMode === BigValueTextMode.ValueAndName) {
    return { valueText: v.text, title: v.title, percentText: pct };
  }
  if ((props.count ?? 1) === 1) {
    return { valueText: v.text, title: void 0, percentText: pct };
  }
  return { valueText: v.text, title: v.title, percentText: pct };
}
function mixToward(hex, toward, amount) {
  const parse = (h2) => {
    const m = String(h2).replace("#", "").match(/^([0-9a-f]{6})$/i);
    if (!m) return null;
    const n = parseInt(m[1], 16);
    return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
  };
  const a = parse(hex);
  const b = parse(toward) || { r: 0, g: 0, b: 0 };
  if (!a) return hex;
  const t2 = Math.max(0, Math.min(1, amount));
  const r = Math.round(a.r + (b.r - a.r) * t2);
  const g = Math.round(a.g + (b.g - a.g) * t2);
  const bl = Math.round(a.b + (b.b - a.b) * t2);
  return `#${[r, g, bl].map((x) => x.toString(16).padStart(2, "0")).join("")}`;
}
function computeBigValueLayout(props) {
  const width2 = Math.max(1, props.width || 100);
  const height2 = Math.max(1, props.height || 100);
  const valueColor = props.value.color ?? "var(--grafana-text)";
  const panelPadding = height2 > 100 ? 12 : 8;
  const textValues = getTextValues(props);
  const justifyCenter = shouldJustifyCenter(
    props.justifyMode,
    textValues.title
  );
  const maxTextWidth = width2 - panelPadding * 2;
  let maxTextHeight = height2 - panelPadding * 2;
  const wideLayout = props.wideLayout !== false && !props.disableWideLayout;
  const isWide = wideLayout && width2 / height2 > 2.5 && !!textValues.title;
  const hasSpark = (props.graphMode === "area" || props.graphMode === "line") && Array.isArray(props.sparkline) && props.sparkline.length > 1;
  let chartHeight = 0;
  let chartWidth = width2;
  let titleFontSize = props.text?.titleSize ?? 0;
  let valueFontSize = props.text?.valueSize ?? 0;
  let percentFontSize = props.text?.percentSize ?? 0;
  if (isWide && hasSpark && height2 > 50) {
    const chartHeightPercent = 0.5;
    const titleWidthPercent = 0.6;
    const valueWidthPercent = 1 - titleWidthPercent;
    const textHeightPercent = 0.4;
    chartHeight = Math.floor(height2 * chartHeightPercent);
    chartWidth = width2;
    if (textValues.title && !titleFontSize) {
      titleFontSize = calculateFontSize(
        textValues.title,
        maxTextWidth * titleWidthPercent,
        maxTextHeight * textHeightPercent,
        LINE_HEIGHT,
        MAX_TITLE_SIZE
      );
    }
    if (!valueFontSize && textValues.valueText) {
      valueFontSize = calculateFontSize(
        textValues.valueText,
        maxTextWidth * valueWidthPercent,
        maxTextHeight * chartHeightPercent,
        LINE_HEIGHT,
        void 0,
        VALUE_FONT_WEIGHT
      );
    }
  } else if (hasSpark && height2 > 50) {
    const titleHeightPercent = 0.15;
    const chartHeightPercent = 0.25;
    let titleHeight = 0;
    chartHeight = height2 * chartHeightPercent;
    chartWidth = width2;
    if (textValues.title && !titleFontSize) {
      titleFontSize = calculateFontSize(
        textValues.title,
        maxTextWidth,
        height2 * titleHeightPercent,
        LINE_HEIGHT,
        MAX_TITLE_SIZE
      );
      titleHeight = titleFontSize * LINE_HEIGHT;
    }
    if (!valueFontSize && textValues.valueText) {
      valueFontSize = calculateFontSize(
        textValues.valueText,
        maxTextWidth,
        maxTextHeight - chartHeight - titleHeight,
        LINE_HEIGHT,
        void 0,
        VALUE_FONT_WEIGHT
      );
    }
    if (textValues.title && titleFontSize) {
      titleFontSize = Math.min(valueFontSize * 0.7, titleFontSize);
    }
    chartHeight = Math.max(
      0,
      Math.floor(
        height2 - titleFontSize * LINE_HEIGHT - valueFontSize * LINE_HEIGHT
      )
    );
  } else {
    let titleHeight = 0;
    if (textValues.title && !titleFontSize) {
      titleFontSize = calculateFontSize(
        textValues.title,
        maxTextWidth * (isWide ? 0.6 : 1),
        height2 * 0.15,
        LINE_HEIGHT,
        MAX_TITLE_SIZE
      );
      titleHeight = titleFontSize * LINE_HEIGHT;
    }
    if (!valueFontSize && textValues.valueText) {
      let valueHeight = maxTextHeight - titleHeight;
      if (props.value.percentChange != null) valueHeight = valueHeight * 0.75;
      const valueWidthPercent = isWide && textValues.title ? 0.3 : 1;
      valueFontSize = calculateFontSize(
        textValues.valueText,
        maxTextWidth * valueWidthPercent,
        valueHeight,
        LINE_HEIGHT,
        void 0,
        VALUE_FONT_WEIGHT
      );
    }
    if (textValues.title && titleFontSize) {
      titleFontSize = Math.min(valueFontSize * 0.7, titleFontSize);
    }
  }
  if (textValues.percentText && !percentFontSize) {
    percentFontSize = Math.max(valueFontSize / 2.5, 12);
  }
  const colorMode = String(props.colorMode ?? BigValueColorMode.Value);
  let containerBackground;
  let containerColor;
  let valueColorCss = valueColor;
  let titleColorCss = "var(--grafana-text-secondary)";
  if (colorMode === BigValueColorMode.None) {
    valueColorCss = "var(--grafana-text)";
  } else if (colorMode === BigValueColorMode.Background || colorMode === BigValueColorMode.BackgroundSolid) {
    const isDark = typeof document !== "undefined" && (document.documentElement.dataset.theme === "dark" || document.documentElement.getAttribute("data-theme") === "dark" || document.documentElement.getAttribute("color-scheme") === "dark");
    const themeFactor = isDark ? 1 : -0.7;
    const g1 = mixToward(
      valueColor,
      themeFactor > 0 ? "#000000" : "#ffffff",
      Math.abs(0.15 * themeFactor)
    );
    const g2 = mixToward(
      valueColor,
      themeFactor > 0 ? "#000000" : "#ffffff",
      Math.abs(0.05 * themeFactor)
    );
    containerBackground = colorMode === BigValueColorMode.BackgroundSolid ? valueColor : `linear-gradient(120deg, ${g1}, ${g2})`;
    const rawContrast = getContrastText(valueColor).toLowerCase();
    const contrast = rawContrast === "#ffffff" || rawContrast === "#fff" ? "#fff" : rawContrast === "#000000" || rawContrast === "#000" ? "#000" : getContrastText(valueColor);
    containerColor = contrast;
    valueColorCss = contrast;
    titleColorCss = contrast === "#fff" ? "rgba(255,255,255,0.85)" : "rgba(0,0,0,0.7)";
  } else {
    valueColorCss = valueColor;
  }
  return {
    titleFontSize,
    valueFontSize,
    percentFontSize,
    chartHeight,
    chartWidth,
    valueColor,
    panelPadding,
    justifyCenter,
    maxTextWidth,
    maxTextHeight,
    title: textValues.title,
    valueText: textValues.valueText,
    percentText: textValues.percentText,
    isWide,
    valueColorCss,
    titleColorCss,
    containerBackground,
    containerColor
  };
}
const _hoisted_1$29 = {
  class: "big-value__text",
  "data-testid": "big-value-text"
};
const _sfc_main$31 = /* @__PURE__ */ defineComponent({
  __name: "BigValue",
  props: {
    width: { default: 100 },
    height: { default: 100 },
    value: {},
    sparkline: {},
    colorMode: { default: BigValueColorMode.Value },
    graphMode: { default: BigValueGraphMode.None },
    justifyMode: {},
    textMode: {},
    text: {},
    count: {},
    disableWideLayout: { type: Boolean },
    percentChangeColorMode: {},
    wideLayout: { type: Boolean, default: true }
  },
  setup(__props) {
    const props = __props;
    const layout = computed(() => computeBigValueLayout(props));
    const sparkHost = ref(null);
    let sparkCanvas = null;
    function colorWithAlpha2(color, alpha2) {
      const s = String(color).trim();
      let m = s.match(/^#([0-9a-f]{6})$/i);
      if (m) {
        const n = parseInt(m[1], 16);
        return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha2})`;
      }
      m = s.match(/^#([0-9a-f]{3})$/i);
      if (m) {
        const r = parseInt(m[1][0] + m[1][0], 16);
        const g = parseInt(m[1][1] + m[1][1], 16);
        const b = parseInt(m[1][2] + m[1][2], 16);
        return `rgba(${r}, ${g}, ${b}, ${alpha2})`;
      }
      m = s.match(
        /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*[\d.]+)?\s*\)$/i
      );
      if (m) {
        return `rgba(${m[1]}, ${m[2]}, ${m[3]}, ${alpha2})`;
      }
      return `rgba(115, 191, 105, ${alpha2})`;
    }
    function sparkColors() {
      const base = props.value.color || getClassicPalette$1(resolveThemeModeHint())[0];
      if (String(props.colorMode).startsWith("background")) {
        return {
          stroke: brightenColor(base, 40),
          fill: "rgba(255,255,255,0.4)"
        };
      }
      return { stroke: base, fill: colorWithAlpha2(base, 0.2) };
    }
    function brightenColor(color, amount) {
      const s = String(color).trim();
      let r = 115, g = 191, b = 105;
      let m = s.match(/^#([0-9a-f]{6})$/i);
      if (m) {
        const n = parseInt(m[1], 16);
        r = n >> 16 & 255;
        g = n >> 8 & 255;
        b = n & 255;
      } else {
        m = s.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);
        if (m) {
          r = Number(m[1]);
          g = Number(m[2]);
          b = Number(m[3]);
        }
      }
      const t2 = Math.max(0, Math.min(100, amount)) / 100;
      r = Math.round(r + (255 - r) * t2);
      g = Math.round(g + (255 - g) * t2);
      b = Math.round(b + (255 - b) * t2);
      return `rgb(${r}, ${g}, ${b})`;
    }
    function destroyPlot() {
      if (sparkCanvas?.parentNode) {
        sparkCanvas.parentNode.removeChild(sparkCanvas);
      }
      sparkCanvas = null;
      if (sparkHost.value) sparkHost.value.innerHTML = "";
    }
    function paintSpark() {
      const host = sparkHost.value;
      if (!host) return;
      const w = Math.max(1, Math.floor(layout.value.chartWidth));
      const h2 = Math.max(1, Math.floor(layout.value.chartHeight));
      const vals = (props.sparkline ?? []).filter(
        (n2) => Number.isFinite(n2)
      );
      destroyPlot();
      if (vals.length < 2 || w < 2 || h2 < 2) return;
      const mode2 = String(props.graphMode ?? "");
      const isArea = mode2 === BigValueGraphMode.Area || mode2 === "area";
      const isLine = mode2 === BigValueGraphMode.Line || mode2 === "line";
      if (!isArea && !isLine) return;
      let min = Math.min(...vals);
      let max = Math.max(...vals);
      if (min === max) {
        if (min === 0) max = 1;
        else if (min < 0) min *= 2;
        else max *= 2;
      }
      const pad = (max - min) * 0.05 || 1;
      min -= pad;
      max += pad;
      const { stroke, fill } = sparkColors();
      const dpr = typeof window !== "undefined" && window.devicePixelRatio ? window.devicePixelRatio : 1;
      const canvas = document.createElement("canvas");
      canvas.width = Math.max(1, Math.floor(w * dpr));
      canvas.height = Math.max(1, Math.floor(h2 * dpr));
      canvas.style.width = w + "px";
      canvas.style.height = h2 + "px";
      canvas.style.display = "block";
      const ctx = canvas.getContext("2d");
      if (!ctx) return;
      ctx.scale(dpr, dpr);
      const n = vals.length;
      const xAt = (i) => n <= 1 ? 0 : i / (n - 1) * (w - 1);
      const yAt = (v) => {
        const t2 = (v - min) / (max - min || 1);
        return (1 - t2) * (h2 - 1);
      };
      ctx.beginPath();
      ctx.moveTo(xAt(0), yAt(vals[0]));
      for (let i = 1; i < n; i++) {
        ctx.lineTo(xAt(i), yAt(vals[i]));
      }
      if (isArea) {
        ctx.lineTo(xAt(n - 1), h2);
        ctx.lineTo(xAt(0), h2);
        ctx.closePath();
        ctx.fillStyle = fill;
        ctx.fill();
        ctx.beginPath();
        ctx.moveTo(xAt(0), yAt(vals[0]));
        for (let i = 1; i < n; i++) {
          ctx.lineTo(xAt(i), yAt(vals[i]));
        }
      }
      ctx.strokeStyle = stroke;
      ctx.lineWidth = 1.5;
      ctx.lineJoin = "round";
      ctx.lineCap = "round";
      ctx.stroke();
      host.appendChild(canvas);
      sparkCanvas = canvas;
    }
    watch(
      () => [
        layout.value.chartWidth,
        layout.value.chartHeight,
        props.sparkline,
        props.graphMode,
        props.colorMode,
        props.value.color
      ],
      () => {
        nextTick(() => paintSpark());
      },
      { deep: true }
    );
    onMounted(() => {
      nextTick(() => paintSpark());
    });
    onBeforeUnmount(() => destroyPlot());
    function pctClass() {
      const p = props.value.percentChange;
      if (p == null) return "";
      const mode2 = String(props.percentChangeColorMode ?? "standard");
      if (mode2 === "inverted") return p >= 0 ? "is-down" : "is-up";
      if (mode2 === "same_as_value") return "is-same";
      return p >= 0 ? "is-up" : "is-down";
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["big-value", {
            "is-center": layout.value.justifyCenter,
            "is-wide": layout.value.isWide,
            "has-spark": layout.value.chartHeight > 0
          }]),
          "data-testid": "big-value",
          style: normalizeStyle({
            width: __props.width + "px",
            height: __props.height + "px",
            padding: layout.value.panelPadding + "px",
            background: layout.value.containerBackground,
            color: layout.value.containerColor
          })
        },
        [
          createElementVNode("div", _hoisted_1$29, [
            layout.value.title ? (openBlock(), createElementBlock(
              "div",
              {
                key: 0,
                class: "big-value__title",
                "data-testid": "big-value-title",
                style: normalizeStyle({
                  fontSize: layout.value.titleFontSize + "px",
                  color: layout.value.titleColorCss
                })
              },
              toDisplayString(layout.value.title),
              5
              /* TEXT, STYLE */
            )) : createCommentVNode("v-if", true),
            createElementVNode(
              "div",
              {
                class: "big-value__value",
                "data-testid": "big-value-value",
                style: normalizeStyle({
                  fontSize: layout.value.valueFontSize + "px",
                  color: layout.value.valueColorCss
                })
              },
              toDisplayString(layout.value.valueText),
              5
              /* TEXT, STYLE */
            ),
            layout.value.percentText ? (openBlock(), createElementBlock(
              "div",
              {
                key: 1,
                class: normalizeClass(["big-value__percent", pctClass()]),
                "data-testid": "big-value-percent",
                style: normalizeStyle({
                  fontSize: layout.value.percentFontSize + "px",
                  color: String(__props.percentChangeColorMode) === "same_as_value" && __props.value.color ? __props.value.color : void 0
                })
              },
              toDisplayString(layout.value.percentText),
              7
              /* TEXT, CLASS, STYLE */
            )) : createCommentVNode("v-if", true)
          ]),
          layout.value.chartHeight > 0 && (__props.sparkline?.length ?? 0) > 1 ? (openBlock(), createElementBlock(
            "div",
            {
              key: 0,
              ref_key: "sparkHost",
              ref: sparkHost,
              class: "big-value__spark",
              "data-testid": "big-value-spark",
              style: normalizeStyle({
                width: Math.floor(layout.value.chartWidth) + "px",
                height: Math.floor(layout.value.chartHeight) + "px"
              })
            },
            null,
            4
            /* STYLE */
          )) : createCommentVNode("v-if", true)
        ],
        6
        /* CLASS, STYLE */
      );
    };
  }
});
const BigValue = /* @__PURE__ */ _export_sfc(_sfc_main$31, [["__scopeId", "data-v-6f44baac"]]);
const _hoisted_1$28 = ["data-mode"];
const _hoisted_2$1J = { class: "viz-tooltip__wrapper" };
const _hoisted_3$1x = {
  key: 0,
  class: "viz-tooltip__header",
  "data-testid": "viz-tooltip-title"
};
const _hoisted_4$1k = { class: "viz-tooltip__row viz-tooltip__row--header" };
const _hoisted_5$19 = { class: "viz-tooltip__value-wrap" };
const _hoisted_6$10 = { class: "viz-tooltip__value viz-tooltip__value--header" };
const _hoisted_7$Z = ["data-testid"];
const _hoisted_8$Q = {
  key: 0,
  class: "viz-tooltip__color",
  "aria-hidden": "true"
};
const _hoisted_9$L = { class: "viz-tooltip__label" };
const _hoisted_10$F = { class: "viz-tooltip__value-wrap" };
const _hoisted_11$z = { class: "viz-tooltip__value" };
const _sfc_main$30 = /* @__PURE__ */ defineComponent({
  __name: "VizTooltip",
  props: {
    title: {},
    items: { default: () => [] },
    mode: { default: "single" },
    x: { default: 0 },
    y: { default: 0 },
    visible: { type: Boolean, default: true },
    floating: { type: Boolean, default: true },
    maxWidth: {},
    maxHeight: {}
  },
  setup(__props) {
    const props = __props;
    const rootStyle = () => {
      const style = {};
      if (props.floating) {
        style.left = `${props.x}px`;
        style.top = `${props.y}px`;
        style.position = "absolute";
      } else {
        style.position = "relative";
        style.left = "auto";
        style.top = "auto";
      }
      if (props.maxWidth != null) {
        style.maxWidth = typeof props.maxWidth === "number" ? `${props.maxWidth}px` : String(props.maxWidth);
      }
      if (props.maxHeight != null) {
        style.maxHeight = typeof props.maxHeight === "number" ? `${props.maxHeight}px` : String(props.maxHeight);
      }
      return style;
    };
    return (_ctx, _cache) => {
      return __props.visible && __props.mode !== "none" && (__props.title || __props.items.length) ? (openBlock(), createElementBlock("div", {
        key: 0,
        class: "viz-tooltip",
        "data-testid": "viz-tooltip",
        "data-mode": __props.mode,
        style: normalizeStyle(rootStyle()),
        "aria-live": "polite",
        "aria-atomic": "true"
      }, [
        createCommentVNode(" VizTooltipWrapper "),
        createElementVNode("div", _hoisted_2$1J, [
          createCommentVNode(" VizTooltipHeader: time as value, empty label (Grafana TimeSeriesTooltip) "),
          __props.title ? (openBlock(), createElementBlock("div", _hoisted_3$1x, [
            createElementVNode("div", _hoisted_4$1k, [
              createElementVNode("div", _hoisted_5$19, [
                createElementVNode(
                  "div",
                  _hoisted_6$10,
                  toDisplayString(__props.title),
                  1
                  /* TEXT */
                )
              ])
            ])
          ])) : createCommentVNode("v-if", true),
          createCommentVNode(" VizTooltipContent "),
          __props.items.length ? (openBlock(), createElementBlock(
            "div",
            {
              key: 1,
              class: normalizeClass(["viz-tooltip__content", { "viz-tooltip__content--solo": !__props.title }])
            },
            [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(__props.items, (item, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: `${item.label}-${i}`,
                    class: normalizeClass(["viz-tooltip__row", { active: item.isActive }]),
                    "data-testid": `viz-tooltip-row-${i}`
                  }, [
                    item.color ? (openBlock(), createElementBlock("div", _hoisted_8$Q, [
                      createCommentVNode(" SeriesIcon: 14×4 pill "),
                      createElementVNode(
                        "span",
                        {
                          class: "viz-tooltip__series-icon",
                          "data-testid": "series-icon",
                          style: normalizeStyle({ background: item.color })
                        },
                        null,
                        4
                        /* STYLE */
                      )
                    ])) : createCommentVNode("v-if", true),
                    item.label ? (openBlock(), createElementBlock(
                      "div",
                      {
                        key: 1,
                        class: normalizeClass(["viz-tooltip__label-wrap", { active: item.isActive }])
                      },
                      [
                        createElementVNode(
                          "span",
                          _hoisted_9$L,
                          toDisplayString(item.label),
                          1
                          /* TEXT */
                        )
                      ],
                      2
                      /* CLASS */
                    )) : createCommentVNode("v-if", true),
                    createElementVNode("div", _hoisted_10$F, [
                      createElementVNode(
                        "div",
                        _hoisted_11$z,
                        toDisplayString(item.value),
                        1
                        /* TEXT */
                      )
                    ])
                  ], 10, _hoisted_7$Z);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ],
            2
            /* CLASS */
          )) : createCommentVNode("v-if", true)
        ])
      ], 12, _hoisted_1$28)) : createCommentVNode("v-if", true);
    };
  }
});
const VizTooltip = /* @__PURE__ */ _export_sfc(_sfc_main$30, [["__scopeId", "data-v-1679ca26"]]);
const _hoisted_1$27 = {
  key: 0,
  class: "req"
};
const _hoisted_2$1I = ["title"];
const _hoisted_3$1w = { class: "g-inline-field__control" };
const _sfc_main$2$ = /* @__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$27, "*")) : createCommentVNode("v-if", true),
              __props.tooltip ? (openBlock(), createElementBlock("span", {
                key: 1,
                class: "tip",
                title: __props.tooltip
              }, "?", 8, _hoisted_2$1I)) : createCommentVNode("v-if", true)
            ],
            4
            /* STYLE */
          )) : createCommentVNode("v-if", true),
          createElementVNode("div", _hoisted_3$1w, [
            renderSlot(_ctx.$slots, "default", {}, void 0, true)
          ])
        ],
        2
        /* CLASS */
      );
    };
  }
});
const GInlineField = /* @__PURE__ */ _export_sfc(_sfc_main$2$, [["__scopeId", "data-v-be5ca155"]]);
const _hoisted_1$26 = { class: "g-alert__body" };
const _hoisted_2$1H = {
  key: 0,
  class: "g-alert__title"
};
const _hoisted_3$1v = { class: "g-alert__content" };
const _sfc_main$2_ = /* @__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$26, [
            __props.title ? (openBlock(), createElementBlock(
              "div",
              _hoisted_2$1H,
              toDisplayString(__props.title),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true),
            createElementVNode("div", _hoisted_3$1v, [
              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$2_, [["__scopeId", "data-v-09ae1b80"]]);
const _hoisted_1$25 = {
  class: "gs",
  "data-testid": "panel-gettingstarted"
};
const _hoisted_2$1G = { class: "content" };
const _hoisted_3$1u = { class: "setup" };
const _hoisted_4$1j = { class: "cards" };
const _hoisted_5$18 = ["href"];
const _hoisted_6$$ = { class: "card-content" };
const _hoisted_7$Y = { class: "type" };
const _hoisted_8$P = { class: "heading" };
const _hoisted_9$K = { class: "card-title-wrap" };
const _hoisted_10$E = { class: "card-title" };
const _hoisted_11$y = { class: "card-info" };
const _hoisted_12$s = { class: "card-content docs-content" };
const _hoisted_13$r = ["href"];
const _hoisted_14$p = { class: "card-title-wrap" };
const _hoisted_15$k = { class: "card-title" };
const _hoisted_16$j = { class: "learn" };
const _hoisted_17$i = ["href"];
const _hoisted_18$i = {
  type: "button",
  class: "nav forward",
  "aria-label": "前往高级教程",
  "data-testid": "gettingstarted-forward"
};
const _sfc_main$2Z = /* @__PURE__ */ defineComponent({
  __name: "GettingStartedRenderer",
  setup(__props) {
    const tutorial = {
      type: "tutorial",
      heading: "Data source and dashboards",
      title: "Grafana fundamentals",
      info: "Set up and understand Grafana if you have no prior experience. This tutorial guides you through the entire process and covers the “Data source” and “Dashboards” steps to the right.",
      href: "https://grafana.com/tutorials/grafana-fundamentals?utm_source=grafana_gettingstarted"
    };
    const docsCards = [
      {
        title: "Add your first data source",
        href: "datasources/new?utm_source=grafana_gettingstarted",
        learnHref: "https://grafana.com/docs/grafana/latest/features/datasources/add-a-data-source?utm_source=grafana_gettingstarted",
        done: true
      },
      {
        title: "Create your first dashboard",
        href: "dashboard/new?utm_source=grafana_gettingstarted",
        learnHref: "https://grafana.com/docs/grafana/latest/guides/getting_started/#create-a-dashboard?utm_source=grafana_gettingstarted",
        done: true
      }
    ];
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$25, [
        _cache[3] || (_cache[3] = createElementVNode(
          "button",
          {
            type: "button",
            class: "dismiss",
            "data-testid": "gettingstarted-dismiss"
          },
          " 移除此面板 ",
          -1
          /* CACHED */
        )),
        createElementVNode("div", _hoisted_2$1G, [
          createElementVNode("div", _hoisted_3$1u, [
            _cache[2] || (_cache[2] = createElementVNode(
              "div",
              { class: "info" },
              [
                createElementVNode("h2", { class: "step-title" }, "Basic"),
                createElementVNode("p", { class: "step-info" }, " The steps below will guide you to quickly finish setting up your Grafana installation. ")
              ],
              -1
              /* CACHED */
            )),
            createElementVNode("div", _hoisted_4$1j, [
              createElementVNode("a", {
                class: "card tutorial",
                href: tutorial.href,
                target: "_blank",
                rel: "noreferrer",
                "data-testid": "gettingstarted-tutorial"
              }, [
                createElementVNode("div", _hoisted_6$$, [
                  createElementVNode(
                    "div",
                    _hoisted_7$Y,
                    toDisplayString(tutorial.type),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "div",
                    _hoisted_8$P,
                    toDisplayString(tutorial.heading),
                    1
                    /* TEXT */
                  ),
                  createElementVNode("div", _hoisted_9$K, [
                    createElementVNode(
                      "h3",
                      _hoisted_10$E,
                      toDisplayString(tutorial.title),
                      1
                      /* TEXT */
                    )
                  ]),
                  createElementVNode(
                    "div",
                    _hoisted_11$y,
                    toDisplayString(tutorial.info),
                    1
                    /* TEXT */
                  )
                ])
              ], 8, _hoisted_5$18),
              (openBlock(), createElementBlock(
                Fragment,
                null,
                renderList(docsCards, (card) => {
                  return createElementVNode("div", {
                    key: card.title,
                    class: "card docs",
                    "data-testid": "gettingstarted-docs"
                  }, [
                    createElementVNode("div", _hoisted_12$s, [
                      createElementVNode("a", {
                        href: card.href,
                        class: "docs-url"
                      }, [
                        _cache[0] || (_cache[0] = createElementVNode(
                          "div",
                          { class: "heading complete" },
                          "完成",
                          -1
                          /* CACHED */
                        )),
                        createElementVNode("div", _hoisted_14$p, [
                          createElementVNode(
                            "h3",
                            _hoisted_15$k,
                            toDisplayString(card.title),
                            1
                            /* TEXT */
                          )
                        ])
                      ], 8, _hoisted_13$r)
                    ]),
                    createElementVNode("div", _hoisted_16$j, [
                      createElementVNode("a", {
                        href: card.learnHref,
                        target: "_blank",
                        rel: "noreferrer",
                        class: "learn-link"
                      }, [
                        _cache[1] || (_cache[1] = createTextVNode(
                          " 在文档中了解如何操作 ",
                          -1
                          /* CACHED */
                        )),
                        createVNode(unref(GIcon), {
                          name: "external-link-alt",
                          size: 16,
                          class: "ext"
                        })
                      ], 8, _hoisted_17$i)
                    ])
                  ]);
                }),
                64
                /* STABLE_FRAGMENT */
              ))
            ])
          ])
        ]),
        createElementVNode("button", _hoisted_18$i, [
          createVNode(unref(GIcon), {
            name: "angle-right",
            size: 16,
            class: "nav-icon"
          })
        ])
      ]);
    };
  }
});
const GettingStartedRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2Z, [["__scopeId", "data-v-bd3f6d30"]]);
const _sfc_main$2Y = /* @__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(GettingStartedRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "gettingstarted",
    name: "快速开始",
    state: "stable",
    skipDataQuery: true
  },
  _sfc_main$2Y
).setNoPadding().setPanelOptions(() => {
}).setRuntimeConsumedPaths([]).register();
const _hoisted_1$24 = {
  class: "welcome",
  "data-testid": "panel-welcome",
  "data-locale": "zh-Hans"
};
const _hoisted_2$1F = { class: "help" };
const _hoisted_3$1t = { class: "help-links" };
const _hoisted_4$1i = ["href"];
const _sfc_main$2X = /* @__PURE__ */ defineComponent({
  __name: "WelcomeRenderer",
  setup(__props) {
    const helpOptions = [
      { label: "Documentation", href: "https://grafana.com/docs/grafana/latest" },
      { label: "Tutorials", href: "https://grafana.com/tutorials" },
      { label: "Community", href: "https://community.grafana.com" },
      { label: "Public Slack", href: "http://slack.grafana.com" }
    ];
    function hrefWithUtm(href) {
      const join = href.includes("?") ? "&" : "?";
      return `${href}${join}utm_source=grafana_gettingstarted`;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$24, [
        _cache[1] || (_cache[1] = createElementVNode(
          "h1",
          { class: "title" },
          "欢迎使用 Grafana",
          -1
          /* CACHED */
        )),
        createElementVNode("div", _hoisted_2$1F, [
          _cache[0] || (_cache[0] = createElementVNode(
            "h2",
            { class: "help-text" },
            "需要帮助吗？",
            -1
            /* CACHED */
          )),
          createElementVNode("div", _hoisted_3$1t, [
            (openBlock(), createElementBlock(
              Fragment,
              null,
              renderList(helpOptions, (option, index2) => {
                return createElementVNode("a", {
                  key: `${option.label}-${index2}`,
                  class: "help-link",
                  href: hrefWithUtm(option.href),
                  target: "_blank",
                  rel: "noreferrer",
                  "data-testid": "welcome-help-link"
                }, [
                  createTextVNode(
                    toDisplayString(option.label),
                    1
                    /* TEXT */
                  ),
                  createVNode(unref(GIcon), {
                    name: "external-link-alt",
                    size: 16,
                    class: "ext-icon"
                  })
                ], 8, _hoisted_4$1i);
              }),
              64
              /* STABLE_FRAGMENT */
            ))
          ])
        ])
      ]);
    };
  }
});
const WelcomeRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2X, [["__scopeId", "data-v-b7cadef5"]]);
const _sfc_main$2W = /* @__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(WelcomeRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "welcome",
    name: "欢迎横幅",
    state: "stable",
    skipDataQuery: true
  },
  _sfc_main$2W
).setNoPadding().setPanelOptions(() => {
}).setRuntimeConsumedPaths([]).register();
function percentChange(values) {
  const nums = values.filter((n) => Number.isFinite(n));
  if (nums.length < 2) return null;
  const last = nums[nums.length - 1];
  const prev = nums[nums.length - 2];
  if (!Number.isFinite(prev) || prev === 0) return null;
  return (last - prev) / Math.abs(prev) * 100;
}
function prepareStatItems(input) {
  const o = input.options ?? {};
  const out = [];
  const calcs = o.reduceOptions?.calcs ?? [
    o.calc ?? "lastNotNull"
  ];
  const calc = String(calcs[0] ?? "lastNotNull");
  const fieldFilter = String(o.reduceOptions?.fields ?? "");
  const fieldRe = fieldFilter ? new RegExp(fieldFilter) : null;
  const showAllValues = o.reduceOptions?.values === true;
  const limit = o.reduceOptions?.limit != null ? Number(o.reduceOptions.limit) : showAllValues ? 25 : void 0;
  let textMode = String(o.textMode ?? "auto");
  const defaultsDisplayName = String(
    input.fieldConfig?.defaults?.displayName ?? ""
  );
  if (textMode === "auto" && defaultsDisplayName) textMode = "value_and_name";
  const graphMode = String(o.graphMode ?? "area");
  const showPct = o.showPercentChange === true;
  const allFrames = input.data?.series ?? [];
  for (const frame of allFrames) {
    for (const field of frame.fields.filter((f) => f.type === "number")) {
      if (fieldRe && !fieldRe.test(field.name) && !fieldRe.test(getFieldDisplayName(field, frame, allFrames))) {
        continue;
      }
      const cfg = { ...field.config, ...input.fieldConfig?.defaults ?? {} };
      const name = getFieldDisplayName(field, frame, allFrames);
      const nums = field.values.map(Number).filter((n) => Number.isFinite(n));
      const display = getDisplayProcessor({ field: { ...field, config: cfg } });
      if (showAllValues) {
        const values = field.values.map((v2) => v2).slice(-(limit ?? 25));
        for (const v2 of values) {
          const dv2 = display(v2);
          out.push({
            text: textMode === "name" ? name : textMode === "none" ? "" : formattedValueToString(dv2),
            name: textMode === "value" || textMode === "none" ? "" : name,
            color: dv2.color,
            spark: graphMode === "none" ? [] : nums.slice(-24),
            percentChange: showPct ? percentChange(nums) : null
          });
        }
        continue;
      }
      const r = reduceField(field, [calc]);
      const v = r[calc];
      const dv = display(v);
      const color = dv.color;
      const spark = graphMode === "none" ? [] : nums.slice(-24);
      const pct = showPct ? percentChange(nums) : null;
      const text = formattedValueToString(dv);
      if (textMode === "none") {
        out.push({ text: "", name: "", color, spark: [], percentChange: null });
      } else if (textMode === "name") {
        out.push({ text: name, name: "", color, spark, percentChange: pct });
      } else if (textMode === "value") {
        out.push({ text, name: "", color, spark, percentChange: pct });
      } else if (textMode === "value_and_name") {
        out.push({ text, name, color, spark, percentChange: pct });
      } else {
        out.push({ text, name, color, spark, percentChange: pct });
      }
    }
  }
  let result = limit != null && Number.isFinite(limit) && !showAllValues ? out.slice(0, limit) : out;
  if (textMode === "auto" && result.length === 1) {
    result = [{ ...result[0], name: "" }];
  }
  return result.map((it) => {
    const n = String(it.name || "");
    if (n === "Value" || /^Value\s*\{/.test(n)) return { ...it, name: "" };
    return it;
  });
}
const _hoisted_1$23 = ["data-orientation", "data-text-mode", "data-graph-mode", "data-color-mode", "data-percent-color-mode", "data-justify-mode", "data-reduce-values", "data-reduce-limit"];
const _hoisted_2$1E = {
  key: 0,
  class: "stat-empty",
  "data-testid": "stat-empty"
};
const _hoisted_3$1s = ["data-testid"];
const _hoisted_4$1h = { class: "stat-name sr-mirror" };
const _hoisted_5$17 = {
  class: "stat-value sr-mirror",
  "data-testid": "panel-stat-value"
};
const _hoisted_6$_ = {
  key: 0,
  class: "sr-mirror",
  "data-testid": "panel-stat-pct"
};
const _hoisted_7$X = {
  key: 1,
  class: "sr-mirror",
  "data-testid": "panel-stat-spark"
};
const _hoisted_8$O = {
  key: 2,
  class: "sr-mirror",
  "data-testid": "panel-stat-spark-area"
};
const _sfc_main$2V = /* @__PURE__ */ defineComponent({
  __name: "StatRenderer",
  props: {
    data: {},
    fieldConfig: {},
    options: {},
    replaceVariables: { type: Function },
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const items = computed(
      () => prepareStatItems({
        data: props.data,
        options: props.options,
        fieldConfig: props.fieldConfig
      })
    );
    const orientation = computed(() => String(opts.value.orientation ?? "auto"));
    const colorMode = computed(
      () => String(opts.value.colorMode ?? "value")
    );
    const graphMode = computed(() => {
      const g = String(opts.value.graphMode ?? "area");
      return g === "area" ? BigValueGraphMode.Area : g === "line" ? BigValueGraphMode.Line : BigValueGraphMode.None;
    });
    const justifyMode = computed(
      () => String(opts.value.justifyMode ?? "auto")
    );
    const textMode = computed(() => {
      let tm = String(opts.value.textMode ?? "auto");
      const defaultsDisplayName = String(
        props.fieldConfig?.defaults?.displayName ?? ""
      );
      if (tm === "auto" && defaultsDisplayName) tm = "value_and_name";
      return tm;
    });
    const wideLayout = computed(() => opts.value.wideLayout !== false);
    const textSizes = computed(
      () => opts.value.text ?? {}
    );
    function itemShellStyle(it) {
      const mode2 = String(opts.value.colorMode ?? "value");
      if ((mode2 === "background" || mode2 === "background_solid") && it.color) {
        if (mode2 === "background_solid") return { background: it.color };
        return { background: `linear-gradient(120deg, ${it.color}, ${it.color})` };
      }
      return {};
    }
    const cellSize = computed(() => {
      const n = Math.max(1, items.value.length);
      const W2 = props.width ?? 300;
      const H2 = props.height ?? 200;
      const orient = orientation.value;
      if (orient === "horizontal") {
        return { w: Math.floor(W2 / n), h: H2 };
      }
      if (orient === "vertical") {
        return { w: W2, h: Math.floor(H2 / n) };
      }
      const cols = Math.ceil(Math.sqrt(n));
      const rows = Math.ceil(n / cols);
      return { w: Math.floor(W2 / cols), h: Math.floor(H2 / rows) };
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "stat-renderer",
        "data-testid": "panel-stat",
        "data-orientation": orientation.value,
        "data-text-mode": String(textMode.value),
        "data-graph-mode": String(graphMode.value),
        "data-color-mode": String(colorMode.value),
        "data-percent-color-mode": String(opts.value.percentChangeColorMode ?? "standard"),
        "data-justify-mode": String(justifyMode.value),
        "data-reduce-values": String(!!opts.value.reduceOptions?.values),
        "data-reduce-limit": String(opts.value.reduceOptions?.limit ?? ""),
        style: { "width": "100%", "height": "100%" }
      }, [
        !items.value.length ? (openBlock(), createElementBlock("div", _hoisted_2$1E, " 暂无数据 ")) : createCommentVNode("v-if", true),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(items.value, (it, idx) => {
            return openBlock(), createElementBlock("div", {
              key: idx,
              class: "stat-item",
              "data-testid": "stat-item-" + idx,
              style: normalizeStyle(itemShellStyle(it))
            }, [
              createVNode(unref(BigValue), {
                width: cellSize.value.w,
                height: cellSize.value.h,
                value: {
                  text: it.text,
                  title: it.name,
                  color: it.color,
                  percentChange: it.percentChange
                },
                sparkline: it.spark,
                "color-mode": colorMode.value,
                "graph-mode": graphMode.value,
                "justify-mode": justifyMode.value,
                "text-mode": textMode.value,
                text: textSizes.value,
                count: items.value.length,
                "wide-layout": wideLayout.value,
                "percent-change-color-mode": String(opts.value.percentChangeColorMode ?? "standard")
              }, null, 8, ["width", "height", "value", "sparkline", "color-mode", "graph-mode", "justify-mode", "text-mode", "text", "count", "wide-layout", "percent-change-color-mode"]),
              createCommentVNode(" legacy selectors for unit tests "),
              createElementVNode(
                "span",
                _hoisted_4$1h,
                toDisplayString(it.name),
                1
                /* TEXT */
              ),
              createElementVNode(
                "span",
                _hoisted_5$17,
                toDisplayString(it.text),
                1
                /* TEXT */
              ),
              it.percentChange != null ? (openBlock(), createElementBlock(
                "span",
                _hoisted_6$_,
                toDisplayString(it.percentChange),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true),
              it.spark.length ? (openBlock(), createElementBlock("span", _hoisted_7$X)) : createCommentVNode("v-if", true),
              it.spark.length && String(opts.value.graphMode ?? "area") === "area" ? (openBlock(), createElementBlock("span", _hoisted_8$O)) : createCommentVNode("v-if", true)
            ], 12, _hoisted_3$1s);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ], 8, _hoisted_1$23);
    };
  }
});
const StatRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2V, [["__scopeId", "data-v-b9170033"]]);
const _sfc_main$2U = /* @__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(StatRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  { id: "stat", name: "统计值", state: "stable", skipDataQuery: false },
  _sfc_main$2U
).useFieldConfig().setPanelOptions((builder) => {
  builder.addCustom(
    {
      id: "reduceOptions.calcs",
      path: "reduceOptions.calcs",
      name: "计算",
      category: ["数值"],
      editor: "stats-picker",
      settings: {
        options: [
          { label: "Last *", value: "lastNotNull" },
          { label: "最后一个", value: "last" },
          { label: "First *", value: "firstNotNull" },
          { label: "第一个", value: "first" },
          { label: "最小值", value: "min" },
          { label: "最大值", value: "max" },
          { label: "平均值", value: "mean" },
          { label: "总和", value: "sum" },
          { label: "计数", value: "count" },
          { label: "范围", value: "range" },
          { label: "增量", value: "delta" },
          { label: "步长", value: "step" },
          { label: "差值", value: "diff" },
          { label: "Min (above zero)", value: "minAboveZero" },
          { label: "全部值", value: "allValues" }
        ]
      }
    },
    ["lastNotNull"]
  ).addText(
    {
      id: "reduceOptions.fields",
      path: "reduceOptions.fields",
      name: "字段",
      description: "字段名正则；留空表示数值字段",
      category: ["数值"],
      editor: "text"
    },
    ""
  ).addBoolean(
    {
      id: "reduceOptions.values",
      path: "reduceOptions.values",
      name: "显示全部值",
      category: ["数值"],
      editor: "boolean"
    },
    false
  ).addNumber(
    {
      id: "reduceOptions.limit",
      path: "reduceOptions.limit",
      name: "限制",
      category: ["数值"],
      editor: "number",
      showIf: (c) => !!c.reduceOptions?.values
    },
    25
  ).addRadio(
    {
      id: "orientation",
      path: "orientation",
      name: "方向",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "水平", value: "horizontal" },
          { label: "垂直", value: "vertical" }
        ]
      }
    },
    "auto"
  ).addRadio(
    {
      id: "textMode",
      path: "textMode",
      name: "文本模式",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "值", value: "value" },
          { label: "值与名称", value: "value_and_name" },
          { label: "名称", value: "name" },
          { label: "无", value: "none" }
        ]
      }
    },
    "auto"
  ).addRadio(
    {
      id: "colorMode",
      path: "colorMode",
      name: "颜色模式",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "值", value: "value" },
          { label: "背景渐变", value: "background" },
          { label: "背景纯色", value: "background_solid" }
        ]
      }
    },
    "value"
  ).addRadio(
    {
      id: "graphMode",
      path: "graphMode",
      name: "图表模式",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "面积", value: "area" }
        ]
      }
    },
    "area"
  ).addRadio(
    {
      id: "justifyMode",
      path: "justifyMode",
      name: "文本对齐",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "居中", value: "center" }
        ]
      }
    },
    "auto"
  ).addBoolean(
    {
      id: "wideLayout",
      path: "wideLayout",
      name: "宽布局",
      category: ["Stat 样式"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showPercentChange",
      path: "showPercentChange",
      name: "显示百分比变化",
      category: ["Stat 样式"],
      editor: "boolean"
    },
    false
  ).addRadio(
    {
      id: "percentChangeColorMode",
      path: "percentChangeColorMode",
      name: "百分比变化颜色模式",
      category: ["Stat 样式"],
      editor: "radio",
      settings: {
        options: [
          { label: "标准", value: "standard" },
          { label: "反转", value: "inverted" },
          { label: "与值相同", value: "same_as_value" }
        ]
      },
      showIf: (c) => !!c.showPercentChange
    },
    "standard"
  );
  addTextSizeOptions(builder, {
    withTitle: true,
    withValue: true,
    withPercentChange: true
  });
}).setNoPadding().setRuntimeConsumedPaths([
  "reduceOptions.calcs",
  "reduceOptions.fields",
  "reduceOptions.values",
  "reduceOptions.limit",
  "orientation",
  "textMode",
  "colorMode",
  "graphMode",
  "justifyMode",
  "wideLayout",
  "showPercentChange",
  "percentChangeColorMode"
]).register();
function classicPalette(mode2) {
  return getClassicPalette$1(mode2 ?? resolveThemeModeHint());
}
function classicColor(index2 = 0, mode2) {
  const palette2 = classicPalette(mode2);
  return palette2[(index2 % palette2.length + palette2.length) % palette2.length];
}
function classicGreen(mode2) {
  return classicColor(0, mode2);
}
function classicYellow(mode2) {
  return classicColor(1, mode2);
}
function classicBlue(mode2) {
  return classicColor(2, mode2);
}
function classicOrange(mode2) {
  return classicColor(3, mode2);
}
function classicRed(mode2) {
  return classicColor(4, mode2);
}
function classicPurple(mode2) {
  return classicColor(5, mode2);
}
function classicColorForKey(key, mode2) {
  const palette2 = classicPalette(mode2);
  let h2 = 0;
  const s = String(key ?? "");
  for (let i = 0; i < s.length; i++) h2 = h2 * 31 + s.charCodeAt(i) >>> 0;
  return palette2[h2 % palette2.length];
}
const FALLBACK_LCD = "#7d8085";
const DEFAULT_LCD_ITEM_SPACING = 8;
const DEFAULT_LCD_CELL_WIDTH = 12;
function colorWithAlpha(color, alpha2) {
  const m = String(color).match(/^#?([0-9a-f]{6})$/i);
  if (m) {
    const n = parseInt(m[1], 16);
    const r = n >> 16 & 255;
    const g = n >> 8 & 255;
    const b = n & 255;
    return `rgba(${r}, ${g}, ${b}, ${alpha2})`;
  }
  const rgb = String(color).match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
  if (rgb) return `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha2})`;
  return color;
}
function getCellColor(positionValue, valueNumeric, cellColor) {
  if (positionValue == null || Number.isNaN(positionValue)) {
    return { background: FALLBACK_LCD, border: FALLBACK_LCD, isLit: false };
  }
  const color = cellColor || FALLBACK_LCD;
  if (valueNumeric == null || Number.isNaN(valueNumeric) || positionValue != null && positionValue > valueNumeric) {
    return {
      background: colorWithAlpha(color, 0.18),
      border: "transparent",
      isLit: false
    };
  }
  return {
    background: colorWithAlpha(color, 0.95),
    backgroundShade: colorWithAlpha(color, 0.55),
    border: colorWithAlpha(color, 0.9),
    isLit: true
  };
}
function buildLcdCells(opts) {
  const lcdW = Math.max(
    2,
    Number(opts.lcdCellWidth ?? DEFAULT_LCD_CELL_WIDTH) || DEFAULT_LCD_CELL_WIDTH
  );
  const maxSize = Math.max(lcdW, Number(opts.maxSize ?? 180) || 180);
  const cellSpacing = Math.max(
    0,
    Number(opts.itemSpacing ?? DEFAULT_LCD_ITEM_SPACING) || DEFAULT_LCD_ITEM_SPACING
  );
  const cellCount = Math.max(1, Math.floor(maxSize / lcdW));
  const cellSize = Math.max(
    1,
    Math.floor((maxSize - cellSpacing * cellCount) / cellCount)
  );
  const min = Number(opts.min);
  const max = Number(opts.max);
  const valueRange = max - min || 1;
  const value = Number(opts.value);
  const fallback = opts.color || classicBlue();
  const out = [];
  for (let i = 0; i < cellCount; i++) {
    const positionValue = min + valueRange / cellCount * i;
    const posColor = opts.colorAt?.(positionValue) || fallback;
    const cell = getCellColor(positionValue, value, posColor);
    out.push({
      on: !!cell.isLit,
      color: cell.background,
      shade: cell.backgroundShade || colorWithAlpha(posColor, 0.55),
      size: cellSize,
      spacing: cellSpacing,
      positionValue
    });
  }
  return out;
}
const BAR_GAUGE_LAYOUT = {
  MIN_VALUE_HEIGHT: 18,
  MAX_VALUE_HEIGHT: 50,
  MAX_VALUE_WIDTH: 150,
  TITLE_LINE_HEIGHT: 1.5,
  VALUE_LINE_HEIGHT: 1,
  VALUE_LEFT_PADDING: 10,
  VALUE_RIGHT_OVERFLOW_PADDING: 15,
  DEFAULT_ITEM_SPACING: 8,
  DEFAULT_LCD_CELL_WIDTH: 12,
  MIN_VIZ_WIDTH: 8,
  /** option default minVizHeight in panel cfg is often 16; renderer floor stays 18 */
  OPTION_MIN_VIZ_HEIGHT: 16,
  /** Grafana title-to-left max width ratio */
  MAX_TITLE_WIDTH_RATIO: 0.4,
  /** Auto namePlacement: show above when height exceeds this */
  AUTO_ABOVE_HEIGHT: 40,
  AVG_CHAR_WIDTH: 7
};
function calculateTitleDimensions(args) {
  const title = args.title ?? "";
  const orientation = String(args.orientation ?? "horizontal");
  const namePlacement = String(args.namePlacement ?? "auto");
  const height2 = Math.max(0, Number(args.height) || 0);
  const width2 = Math.max(0, Number(args.width) || 0);
  if (!title) {
    return { fontSize: 0, width: 0, height: 0, placement: "above" };
  }
  if (namePlacement === "hidden") {
    return { fontSize: 0, width: 0, height: 0, placement: "hidden" };
  }
  if (orientation === "vertical") {
    const fontSize = args.titleSize ?? 14;
    return {
      fontSize,
      width: width2,
      height: fontSize * BAR_GAUGE_LAYOUT.TITLE_LINE_HEIGHT,
      placement: "below"
    };
  }
  const shouldDisplayAbove = height2 > BAR_GAUGE_LAYOUT.AUTO_ABOVE_HEIGHT && namePlacement === "auto" || namePlacement === "top";
  if (shouldDisplayAbove) {
    if (args.titleSize != null && Number.isFinite(args.titleSize)) {
      return {
        fontSize: Number(args.titleSize),
        width: 0,
        height: Number(args.titleSize) * BAR_GAUGE_LAYOUT.TITLE_LINE_HEIGHT,
        placement: "above"
      };
    }
    const maxTitleHeightRatio = 0.45;
    const titleHeight = Math.max(
      Math.min(height2 * maxTitleHeightRatio, BAR_GAUGE_LAYOUT.MAX_VALUE_HEIGHT),
      17
    );
    return {
      fontSize: titleHeight / BAR_GAUGE_LAYOUT.TITLE_LINE_HEIGHT,
      width: 0,
      height: titleHeight,
      placement: "above"
    };
  }
  if (namePlacement === "left" || namePlacement === "auto") {
    const maxTitleHeightRatio = 0.6;
    const titleHeight = Math.max(
      height2 * maxTitleHeightRatio,
      BAR_GAUGE_LAYOUT.MIN_VALUE_HEIGHT
    );
    const titleFontSize = titleHeight / BAR_GAUGE_LAYOUT.TITLE_LINE_HEIGHT;
    const textWidth = Math.min(
      title.length * BAR_GAUGE_LAYOUT.AVG_CHAR_WIDTH + 15,
      width2 * BAR_GAUGE_LAYOUT.MAX_TITLE_WIDTH_RATIO
    );
    return {
      fontSize: args.titleSize ?? titleFontSize,
      height: 0,
      width: textWidth,
      placement: "left"
    };
  }
  return {
    fontSize: 12,
    width: 0,
    height: 18,
    placement: "above"
  };
}
function calculateBarAndValueDimensions(args) {
  const height2 = Math.max(1, Number(args.height) || 100);
  const width2 = Math.max(1, Number(args.width) || 200);
  const orientation = String(args.orientation ?? "horizontal");
  const titleDim = calculateTitleDimensions({
    height: height2,
    width: width2,
    orientation,
    namePlacement: args.namePlacement,
    title: args.title,
    titleSize: args.titleSize
  });
  const valueString = args.valueText ?? "";
  const fontSizeToMeasureWith = args.valueSize ?? Math.max(titleDim.fontSize, 12);
  const realValueWidth = valueString.length * (fontSizeToMeasureWith * 0.55) + BAR_GAUGE_LAYOUT.VALUE_LEFT_PADDING * 2;
  let maxBarHeight = 0;
  let maxBarWidth = 0;
  let valueHeight = 0;
  let valueWidth = 0;
  let wrapperWidth = 0;
  let wrapperHeight = 0;
  const valueHidden = args.valueMode === "hidden";
  if (orientation === "vertical") {
    if (args.valueSize != null && Number.isFinite(args.valueSize)) {
      valueHeight = Number(args.valueSize) * BAR_GAUGE_LAYOUT.VALUE_LINE_HEIGHT;
    } else {
      valueHeight = Math.min(
        Math.max(height2 * 0.1, BAR_GAUGE_LAYOUT.MIN_VALUE_HEIGHT),
        BAR_GAUGE_LAYOUT.MAX_VALUE_HEIGHT
      );
    }
    valueWidth = width2;
    if (valueHidden) {
      valueHeight = 0;
      valueWidth = 0;
    }
    maxBarHeight = Math.max(1, height2 - (titleDim.height + valueHeight));
    maxBarWidth = width2;
    wrapperWidth = width2;
    wrapperHeight = Math.max(1, height2 - titleDim.height);
  } else {
    if (valueHidden) {
      valueHeight = 0;
      valueWidth = 0;
    } else {
      valueHeight = Math.max(1, height2 - titleDim.height);
      valueWidth = Math.max(
        Math.min(width2 * 0.2, BAR_GAUGE_LAYOUT.MAX_VALUE_WIDTH),
        realValueWidth
      );
      valueWidth = Math.min(BAR_GAUGE_LAYOUT.MAX_VALUE_WIDTH, valueWidth);
    }
    maxBarHeight = Math.max(1, height2 - titleDim.height);
    maxBarWidth = Math.max(1, width2 - valueWidth - titleDim.width);
    if (titleDim.placement === "above") {
      wrapperWidth = width2;
      wrapperHeight = Math.max(1, height2 - titleDim.height);
    } else {
      wrapperWidth = Math.max(1, width2 - titleDim.width);
      wrapperHeight = height2;
    }
  }
  return {
    valueWidth,
    valueHeight,
    maxBarWidth,
    maxBarHeight,
    wrapperHeight,
    wrapperWidth
  };
}
function resolveTitlePlacement(args) {
  if (!args.hasTitle) return "hidden";
  const dim = calculateTitleDimensions({
    height: args.panelHeight ?? 100,
    width: 200,
    orientation: args.orientation,
    namePlacement: args.namePlacement,
    title: !args.hasTitle ? "" : "x"
  });
  return dim.placement;
}
function toRad(angle) {
  return (angle - 90) * Math.PI / 180;
}
function drawRadialArcPathStable(startAngle, endAngle, radius, cx, cy) {
  let end = endAngle;
  if (end >= 360) end = 359.99;
  if (end <= 0) return "";
  const startRadians = toRad(startAngle);
  const endRadians = toRad(startAngle + end);
  const largeArc = end > 180 ? 1 : 0;
  const MAX_DECIMALS = 2;
  const x1 = parseFloat(
    (cx + radius * Math.cos(startRadians)).toFixed(MAX_DECIMALS)
  );
  const y1 = parseFloat(
    (cy + radius * Math.sin(startRadians)).toFixed(MAX_DECIMALS)
  );
  const x2 = parseFloat(
    (cx + radius * Math.cos(endRadians)).toFixed(MAX_DECIMALS)
  );
  const y2 = parseFloat(
    (cy + radius * Math.sin(endRadians)).toFixed(MAX_DECIMALS)
  );
  return `M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`;
}
const ARC_START = 250;
const ARC_END = 110;
function angleRangeForShape(shape) {
  if (shape === "circle") return 360;
  return 360 % ARC_START + ARC_END;
}
function startAngleForShape(shape) {
  return shape === "circle" ? 0 : ARC_START;
}
function getAngleBetweenSegments(segmentSpacing, segmentCount, range) {
  const maxAngleBetweenSegments = Math.max(
    range / 1.5 / Math.max(1, segmentCount),
    2
  );
  return segmentSpacing * maxAngleBetweenSegments;
}
function getOptimalSegmentCount(radius, barWidth, segmentSpacing, segmentCount, range) {
  const angleBetweenSegments = getAngleBetweenSegments(
    segmentSpacing,
    segmentCount,
    range
  );
  const innerRadius = radius - barWidth / 2;
  const circumference = Math.PI * innerRadius * 2 * (range / 360);
  const maxSegments = Math.floor(circumference / (angleBetweenSegments + 3));
  return Math.min(Math.max(1, maxSegments), Math.max(1, segmentCount));
}
function getValueAngleForValue(value, min, max, startAngle, endAngle, neutral) {
  const angleRange = 360 % (startAngle === 0 ? 1 : startAngle) + endAngle;
  const span = max - min || 1;
  const pct = (value - min) / span;
  const valueAngle = pct * angleRange;
  let startValueAngle = 0;
  let endValueAngle = valueAngle;
  if (typeof neutral === "number" && Number.isFinite(neutral)) {
    const clampedNeutral = Math.min(Math.max(min, neutral), max);
    const neutralAngle = (clampedNeutral - min) / span * angleRange;
    if (neutralAngle <= valueAngle) {
      startValueAngle = neutralAngle;
      endValueAngle = valueAngle - neutralAngle;
    } else {
      startValueAngle = valueAngle;
      endValueAngle = neutralAngle - valueAngle;
    }
  }
  const clampedEnd = Math.min(Math.max(endValueAngle, 0), angleRange);
  return { angleRange, startValueAngle, endValueAngle: clampedEnd };
}
const PANEL_GAUGE_VIEW = {
  width: 100,
  height: 90,
  cx: 50,
  cy: 46,
  radius: 32,
  stroke: 8
};
function calculateDimensions(width2, height2, endAngle = ARC_END, glow = false, roundedBars = false, barWidthFactor = 0.4, barIndex = 0, thresholdBar = false, showScaleLabels = false) {
  const yMaxAngle = endAngle > 180 ? 180 : endAngle;
  let margin = 0;
  if (glow) {
    margin = 0.02 * Math.min(width2, height2);
  }
  let maxRadiusW = width2 / 2 - margin;
  const heightRatioV = Math.sin(toRad(yMaxAngle));
  let maxRadiusH = (height2 - margin * 2) / (1 + heightRatioV);
  let maxRadius = Math.min(maxRadiusW, maxRadiusH);
  let maxRadiusIsLimitedByHeight = maxRadiusH === maxRadius;
  let outerRadius = maxRadius;
  const barWidth = Math.max(barWidthFactor * (maxRadius / 3), 2);
  const totalEndcapAdjustment = yMaxAngle < 180 && roundedBars ? barWidth * 0.5 : 0;
  const radiusEndcapAdjustment = totalEndcapAdjustment * 0.5;
  outerRadius -= radiusEndcapAdjustment;
  maxRadiusH -= radiusEndcapAdjustment;
  maxRadiusW -= radiusEndcapAdjustment;
  let scaleLabelsFontSize = 0;
  let scaleLabelsSpacing = 0;
  let scaleLabelsRadius = 0;
  if (showScaleLabels) {
    scaleLabelsRadius = outerRadius;
    const radiusToFontSizeFactor = 0.12;
    scaleLabelsFontSize = Math.max(
      radiusToFontSizeFactor * Math.pow(outerRadius, 0.92),
      10
    );
    scaleLabelsSpacing = scaleLabelsFontSize / 3;
    const labelsSize = scaleLabelsFontSize * 1.2 + scaleLabelsSpacing;
    outerRadius -= labelsSize;
    maxRadiusW -= labelsSize;
    maxRadiusH -= labelsSize;
    if (maxRadiusIsLimitedByHeight && endAngle < 180) {
      const amount = outerRadius * 0.07;
      scaleLabelsRadius -= amount;
      maxRadiusH -= amount;
      maxRadiusW -= amount;
      outerRadius -= amount;
    }
  }
  const thresholdsToBarWidth = 0.2 * Math.pow(barWidth, 0.92);
  const thresholdsBarWidth = thresholdBar ? Math.min(Math.max(thresholdsToBarWidth, 4), 12) : 0;
  const thresholdsBarSpacing = Math.min(
    Math.max(thresholdsBarWidth / 2, 2),
    12
  );
  let thresholdsBarRadius = 0;
  if (thresholdsBarWidth > 0) {
    thresholdsBarRadius = outerRadius - thresholdsBarWidth / 2;
    maxRadiusW -= thresholdsBarWidth + thresholdsBarSpacing;
    maxRadiusH -= thresholdsBarWidth + thresholdsBarSpacing;
    outerRadius = Math.min(maxRadiusW, maxRadiusH);
  }
  let innerRadius = outerRadius - barWidth / 2;
  const belowCenterY = maxRadius * Math.sin(toRad(yMaxAngle));
  const rest = height2 - belowCenterY - margin * 2 - maxRadius;
  const centerX = width2 / 2;
  const centerYEndcapAdjustment = totalEndcapAdjustment - radiusEndcapAdjustment;
  const centerY = maxRadius + margin + rest / 2 - centerYEndcapAdjustment;
  if (barIndex > 0) {
    innerRadius = innerRadius - (barWidth + 4) * barIndex;
  }
  return {
    vizWidth: width2,
    vizHeight: height2,
    margin,
    gaugeBottomY: centerY + belowCenterY,
    radius: Math.max(innerRadius, 2),
    centerX,
    centerY,
    barWidth,
    barIndex,
    thresholdsBarWidth,
    thresholdsBarSpacing,
    thresholdsBarRadius,
    scaleLabelsFontSize,
    scaleLabelsSpacing,
    scaleLabelsRadius
  };
}
function panelGaugeGeometry(opts) {
  const shape = opts?.shape ?? "gauge";
  const endAngle = shape === "circle" ? 180 : ARC_END;
  const f = Number(opts?.barWidthFactor ?? 0.5);
  const glow = !!opts?.glow;
  const rounded = !!opts?.roundedBars;
  const thresholdBar = !!opts?.thresholdBar;
  const showScaleLabels = !!opts?.showScaleLabels;
  const showName = !!opts?.showName;
  const sparkline = !!opts?.sparkline;
  const pw = Number(opts?.panelWidth);
  const ph = Number(opts?.panelHeight);
  const usePanelPx = Number.isFinite(pw) && pw > 0 && Number.isFinite(ph) && ph > 0;
  const viewW = usePanelPx ? pw : PANEL_GAUGE_VIEW.width;
  const viewH = usePanelPx ? ph : shape === "circle" ? 100 : PANEL_GAUGE_VIEW.height;
  const calcW = viewW;
  const calcH = viewH;
  const baseDims = calculateDimensions(
    calcW,
    calcH,
    endAngle,
    glow,
    rounded,
    f,
    0,
    false,
    false
  );
  const dims = calculateDimensions(
    calcW,
    calcH,
    endAngle,
    glow,
    rounded,
    f,
    0,
    thresholdBar,
    showScaleLabels
  );
  let cx = PANEL_GAUGE_VIEW.cx;
  let cy = PANEL_GAUGE_VIEW.cy;
  let r = PANEL_GAUGE_VIEW.radius;
  let stroke = Math.max(3, Math.min(14, PANEL_GAUGE_VIEW.stroke * (0.6 + f)));
  let gaugeBottomY = cy + r * Math.sin(toRad(Math.min(endAngle, 180)));
  if (usePanelPx && dims.radius > 0) {
    cx = dims.centerX;
    cy = dims.centerY;
    r = dims.radius;
    stroke = dims.barWidth;
    gaugeBottomY = dims.gaugeBottomY;
  } else if ((showScaleLabels || thresholdBar && showScaleLabels) && baseDims.radius > 0) {
    const rScale = dims.radius / baseDims.radius;
    r = Math.max(8, PANEL_GAUGE_VIEW.radius * rScale);
    if (baseDims.centerY > 0) {
      const cyShift = (dims.centerY - baseDims.centerY) * (viewH / calcH);
      cy = PANEL_GAUGE_VIEW.cy + cyShift;
    }
    gaugeBottomY = cy + r * Math.sin(toRad(Math.min(endAngle, 180)));
  }
  const scale = usePanelPx ? 1 : viewW / Math.max(calcW, 1);
  const scaleLabelsFontSize = showScaleLabels ? usePanelPx ? Math.max(10, dims.scaleLabelsFontSize) : Math.max(
    3.5,
    Math.min(8, dims.scaleLabelsFontSize * scale * (viewW / 100))
  ) : 0;
  const scaleLabelsRadius = showScaleLabels ? usePanelPx ? dims.scaleLabelsRadius || r + stroke : Math.max(
    r + stroke * 0.5 + 2,
    (dims.scaleLabelsRadius || 0) * (PANEL_GAUGE_VIEW.radius / Math.max(baseDims.radius, 1))
  ) : r + 10;
  const thresholdsBarRadius = thresholdBar && dims.thresholdsBarRadius > 0 ? usePanelPx ? dims.thresholdsBarRadius : r + stroke * 0.75 + 1.5 : r + stroke * 0.75 + 1.5;
  const thresholdsBarWidth = dims.thresholdsBarWidth > 0 ? usePanelPx ? dims.thresholdsBarWidth : Math.max(2, Math.min(6, dims.thresholdsBarWidth * scale)) : 0;
  const LINE_HEIGHT_FACTOR2 = 1.21;
  const VALUE_SPACE_PERCENTAGE2 = 0.7;
  const SPARKLINE_SPACING2 = 8;
  const VALUE_WIDTH_TO_RADIUS_FACTOR2 = 0.82;
  const LARGE_RADIUS_SCALING_DECAY2 = 0.86;
  const NAME_TO_HEIGHT_FACTOR2 = 0.45;
  const MAX_NAME_HEIGHT_DIVISOR2 = 4;
  let maxValueHeight = VALUE_WIDTH_TO_RADIUS_FACTOR2 * Math.pow(r, LARGE_RADIUS_SCALING_DECAY2);
  let maxNameHeight = r / MAX_NAME_HEIGHT_DIVISOR2;
  if (showName) {
    maxValueHeight = VALUE_WIDTH_TO_RADIUS_FACTOR2 * Math.pow(r, LARGE_RADIUS_SCALING_DECAY2);
    maxNameHeight = NAME_TO_HEIGHT_FACTOR2 * Math.pow(r, LARGE_RADIUS_SCALING_DECAY2);
  }
  const approxValueFont = Math.max(1, maxValueHeight / LINE_HEIGHT_FACTOR2);
  const approxNameFont = Math.max(
    usePanelPx ? 10 : 4.5,
    maxNameHeight / LINE_HEIGHT_FACTOR2
  );
  const valueHeight = approxValueFont * LINE_HEIGHT_FACTOR2;
  const nameHeight = showName ? approxNameFont * LINE_HEIGHT_FACTOR2 : 0;
  let valueY = showName ? cy - nameHeight * (1 - VALUE_SPACE_PERCENTAGE2) : cy;
  let nameY = showName ? valueY + valueHeight * VALUE_SPACE_PERCENTAGE2 : cy;
  let yOffset = 0;
  if (shape === "gauge") {
    yOffset += (valueHeight + nameHeight) / 4;
  }
  if (sparkline) {
    yOffset += SPARKLINE_SPACING2;
  }
  const valueTextY = usePanelPx ? valueY - yOffset : shape === "circle" ? cy : cy + r * 0.18;
  const nameTextY = usePanelPx ? nameY - yOffset : shape === "circle" ? cy + r * 0.38 : cy + r * 0.42;
  const SPARKLINE_HEIGHT_DIVISOR = 4;
  const SPARKLINE_WIDTH_FACTOR_ARC = 1.4;
  const SPARKLINE_WIDTH_FACTOR_CIRCLE = 1.6;
  const sparkHeight = r / SPARKLINE_HEIGHT_DIVISOR;
  const sparkWidth = r * (shape === "gauge" ? SPARKLINE_WIDTH_FACTOR_ARC : SPARKLINE_WIDTH_FACTOR_CIRCLE) - stroke;
  const sparkY1 = usePanelPx ? gaugeBottomY - SPARKLINE_SPACING2 : Math.min(viewH - 2, viewH - 6);
  const sparkY0 = usePanelPx ? sparkY1 - sparkHeight : Math.min(viewH - 4, cy + r * 0.55);
  return {
    viewW,
    viewH,
    cx,
    cy,
    r,
    stroke,
    valueTextY,
    nameTextY,
    sparkY0,
    sparkY1,
    sparkWidth: Math.max(8, sparkWidth),
    sparkHeight: Math.max(4, sparkHeight),
    scaleLabelsFontSize,
    scaleLabelsRadius,
    thresholdsBarRadius,
    thresholdsBarWidth,
    pixelSpace: usePanelPx,
    gaugeBottomY
  };
}
function cleanGaugeName(name) {
  const n = String(name || "").trim();
  if (!n || n === "Value" || /^Value\s*\{/.test(n)) return "";
  return n;
}
function fieldMinMax(field, cfg) {
  let min = cfg.min;
  let max = cfg.max;
  const hasMin = typeof min === "number" && Number.isFinite(min);
  const hasMax = typeof max === "number" && Number.isFinite(max);
  if (!hasMin || !hasMax) {
    const vals = (field.values ?? []).map((n) => Number(n)).filter((n) => Number.isFinite(n));
    if (vals.length) {
      if (!hasMin) min = Math.min(...vals);
      if (!hasMax) max = Math.max(...vals);
    } else {
      if (!hasMin) min = 0;
      if (!hasMax) max = 100;
    }
  }
  if (min === max) {
    min = min - min * 0.1;
    max = max + max * 0.1;
  }
  return { min: Number(min), max: Number(max) };
}
function fieldMatchesFilter(field, filter2) {
  if (!filter2 || !String(filter2).trim()) return true;
  const raw = String(filter2).trim();
  const name = field.name || "";
  if (raw.startsWith("/") && raw.lastIndexOf("/") > 0) {
    const last = raw.lastIndexOf("/");
    const body = raw.slice(1, last);
    const flags2 = raw.slice(last + 1);
    try {
      return new RegExp(body, flags2).test(name);
    } catch {
      return name.includes(body);
    }
  }
  return name === raw || name.includes(raw);
}
function thresholdSteps(cfg) {
  const rawSteps = cfg.thresholds?.steps ?? [];
  return rawSteps.length > 0 ? rawSteps : [
    { value: -Infinity, color: classicGreen() },
    { value: 80, color: classicRed() }
  ];
}
function rowDisplayName(frame, field, rowIndex, allFrames) {
  const configured = String(field.config?.displayName ?? "").trim();
  if (configured) return configured;
  const parts = [];
  let otherNumeric = 0;
  for (const other of frame.fields) {
    if (other === field) continue;
    if (other.type === "string") {
      const raw = other.values?.[rowIndex];
      const text = raw == null ? "" : String(raw).trim();
      if (text) parts.push(text);
    } else if (other.type === "number") {
      otherNumeric += 1;
    }
  }
  if (otherNumeric || parts.length === 0) {
    parts.push(getFieldDisplayName(field, frame, allFrames));
  }
  return parts.join(" ");
}
function pushGaugeItem(out, opts) {
  const { v, cfg, field, display, textMode, allFrames, spark } = opts;
  const { min, max } = fieldMinMax(field, cfg);
  const pct = Math.max(0, Math.min(1, (v - min) / (max - min || 1)));
  const steps = thresholdSteps(cfg);
  const name = cleanGaugeName(opts.forceName ?? display);
  const titleForLayout = opts.forceName || display || name || "Value";
  let text = formatValue(v, cfg);
  let showName = name;
  if (textMode === "name") {
    text = name || text;
    showName = "";
  } else if (textMode === "value") {
    showName = "";
  } else if (textMode === "none") {
    text = "";
    showName = "";
  } else if (textMode === "auto" && allFrames.length === 1) {
    const numFields = allFrames[0].fields.filter((f) => f.type === "number").length;
    if (numFields <= 1 && !opts.forceName) showName = "";
  }
  out.push({
    text,
    name: showName,
    titleForLayout,
    color: getFieldColor(v, cfg) ?? classicGreen(),
    pct,
    min,
    max,
    thresholds: steps.filter(
      (s) => Number.isFinite(Number(s.value)) && Number(s.value) !== -Infinity
    ),
    spark
  });
}
function prepareGaugeItems(input) {
  const out = [];
  const calc = String(input.reduceCalc ?? "lastNotNull");
  const textMode = String(input.textMode ?? "auto");
  const showAllValues = input.showAllValues === true;
  const allFrames = input.series ?? [];
  const DEFAULT_VALUES_LIMIT = 25;
  const limRaw = input.limit != null ? Number(input.limit) : void 0;
  const limit = limRaw != null && Number.isFinite(limRaw) && limRaw >= 0 ? Math.floor(limRaw) : showAllValues ? DEFAULT_VALUES_LIMIT : void 0;
  for (const frame of allFrames) {
    for (const field of frame.fields.filter((f) => f.type === "number")) {
      if (!fieldMatchesFilter(field, input.fieldsFilter)) continue;
      const cfg = { ...field.config, ...input.fieldDefaults ?? {} };
      const sparkAll = field.values.map((n) => Number(n)).filter((n) => Number.isFinite(n)).slice(-40);
      const display = cfg.displayNameFromDS || cfg.displayName || getFieldDisplayName(field, frame, allFrames);
      if (showAllValues) {
        const values = field.values ?? [];
        for (let j = 0; j < values.length; j++) {
          const raw = values[j];
          const v2 = Number(raw);
          if (!Number.isFinite(v2)) continue;
          const rowName = rowDisplayName(frame, field, j, allFrames);
          pushGaugeItem(out, {
            v: v2,
            cfg,
            field,
            display,
            textMode,
            allFrames,
            spark: sparkAll,
            forceName: cleanGaugeName(rowName) || rowName || String(j + 1)
          });
          if (limit != null && out.length >= limit) return out;
        }
        continue;
      }
      const r = reduceField(field, [calc]);
      const v = Number(r[calc] ?? r.lastNotNull ?? 0);
      pushGaugeItem(out, {
        v,
        cfg,
        field,
        display,
        textMode,
        allFrames,
        spark: sparkAll
      });
      if (limit != null && out.length >= limit) return out;
    }
  }
  return out;
}
function arcPathRelative(startDeg, lengthDeg, radius) {
  let end = lengthDeg;
  if (end >= 360) end = 359.99;
  const startRadians = toRad(startDeg);
  const endRadians = toRad(startDeg + end);
  const largeArc = end > 180 ? 1 : 0;
  const x1 = radius * Math.cos(startRadians);
  const y1 = radius * Math.sin(startRadians);
  const x2 = radius * Math.cos(endRadians);
  const y2 = radius * Math.sin(endRadians);
  return `M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`;
}
function arcPath(startDeg, lengthDeg, geom, radius) {
  return drawRadialArcPathStable(
    startDeg,
    lengthDeg,
    radius ?? geom.r,
    geom.cx,
    geom.cy
  );
}
function trackArcs(it, geom, neutral) {
  const start = startAngleForShape(geom.shape);
  const full = angleRangeForShape(geom.shape);
  const endAngle = geom.shape === "circle" ? 360 : ARC_END;
  const value = it.min + it.pct * (it.max - it.min || 1);
  const { startValueAngle, endValueAngle } = getValueAngleForValue(
    value,
    it.min,
    it.max,
    start,
    endAngle,
    neutral != null && Number.isFinite(Number(neutral)) ? Number(neutral) : void 0
  );
  const out = [];
  if (startValueAngle > 0.05) {
    out.push({ d: arcPath(start, startValueAngle, geom) });
  }
  const afterStart = start + startValueAngle + endValueAngle;
  const afterLen = full - endValueAngle - startValueAngle;
  if (afterLen > 0.05) {
    out.push({ d: arcPath(afterStart, afterLen, geom) });
  }
  return out;
}
function thresholdTicks(it, geom) {
  const start = startAngleForShape(geom.shape);
  const full = angleRangeForShape(geom.shape);
  const labelR = geom.scaleLabelsRadius || geom.r + 10;
  return it.thresholds.map((s) => {
    const t2 = Math.max(
      0,
      Math.min(1, (Number(s.value) - it.min) / (it.max - it.min || 1))
    );
    const ang = start + full * t2;
    const rad = toRad(ang);
    const r1 = geom.r - geom.stroke * 0.75;
    const r2 = geom.r + geom.stroke * 0.75;
    return {
      x1: geom.cx + r1 * Math.cos(rad),
      y1: geom.cy + r1 * Math.sin(rad),
      x2: geom.cx + r2 * Math.cos(rad),
      y2: geom.cy + r2 * Math.sin(rad),
      color: s.color || classicOrange(),
      label: String(s.value),
      lx: geom.cx + labelR * Math.cos(rad),
      ly: geom.cy + labelR * Math.sin(rad)
    };
  });
}
function segmentArcs(it, geom, requested, segmentSpacing, neutral) {
  if (requested <= 1) return [];
  const start = startAngleForShape(geom.shape);
  const full = angleRangeForShape(geom.shape);
  const n = getOptimalSegmentCount(
    geom.r,
    geom.stroke,
    segmentSpacing,
    requested,
    full
  );
  const angleBetween = getAngleBetweenSegments(segmentSpacing, n, full);
  const segmentArcLengthDeg = full / n - angleBetween;
  const angles = getValueAngleForValue(
    it.min + it.pct * (it.max - it.min || 1),
    it.min,
    it.max,
    start,
    geom.shape === "circle" ? 360 : ARC_END,
    neutral != null && Number.isFinite(Number(neutral)) ? Number(neutral) : void 0
  );
  const out = [];
  for (let i = 0; i < n; i++) {
    const segmentStartAngle = start + full / n * i + 0.01;
    const segmentAngle = i / n * full;
    const isTrack = segmentAngle < angles.startValueAngle - 1e-9 || segmentAngle >= angles.startValueAngle + angles.endValueAngle - 1e-9;
    const len = Math.max(0.5, segmentArcLengthDeg);
    out.push({
      d: arcPath(segmentStartAngle, len, geom),
      on: !isTrack,
      startAngle: segmentStartAngle
    });
  }
  return out;
}
function endpointPos(it, geom, endpointMarker, neutral) {
  const marker = String(endpointMarker ?? "point");
  if (marker === "none" || !marker) return null;
  const start = startAngleForShape(geom.shape);
  const full = angleRangeForShape(geom.shape);
  let pct = Math.max(0, Math.min(1, it.pct));
  if (neutral != null && Number.isFinite(Number(neutral))) {
    const n = Number(neutral);
    const nPct = Math.max(
      0,
      Math.min(1, (n - it.min) / (it.max - it.min || 1))
    );
    pct = Math.max(pct, nPct);
  }
  if (pct <= 0) return null;
  const ang = start + full * pct;
  const rad = toRad(ang);
  return {
    x: geom.cx + geom.r * Math.cos(rad),
    y: geom.cy + geom.r * Math.sin(rad)
  };
}
function valueArcAngles(it, shape, neutral) {
  const start = startAngleForShape(shape);
  const endAngle = shape === "circle" ? 360 : ARC_END;
  const value = it.min + it.pct * (it.max - it.min || 1);
  const { startValueAngle, endValueAngle } = getValueAngleForValue(
    value,
    it.min,
    it.max,
    start,
    endAngle,
    neutral != null && Number.isFinite(Number(neutral)) ? Number(neutral) : void 0
  );
  return { start: start + startValueAngle, startValueAngle, endValueAngle };
}
function thresholdBarArcs(it, geom, showThresholdMarkers) {
  if (showThresholdMarkers === false) return [];
  const baseColor = it.color || classicGreen();
  const raw = [
    { value: it.min, color: baseColor },
    ...it.thresholds.map((s) => ({ value: Number(s.value), color: s.color || baseColor })).filter((s) => Number.isFinite(s.value))
  ].sort((a, b) => a.value - b.value);
  const clamped = [];
  let lastColor = baseColor;
  for (const s of raw) {
    if (s.value <= it.min) {
      lastColor = s.color;
      continue;
    }
    if (s.value >= it.max) {
      break;
    }
    if (!clamped.length) clamped.push({ value: it.min, color: lastColor });
    clamped.push({ value: s.value, color: lastColor });
    lastColor = s.color;
  }
  if (!clamped.length) clamped.push({ value: it.min, color: lastColor });
  if (clamped[clamped.length - 1].value < it.max) {
    clamped.push({ value: it.max, color: lastColor });
  }
  if (clamped.length < 2) return [];
  const start = startAngleForShape(geom.shape);
  const full = angleRangeForShape(geom.shape);
  const range = it.max - it.min || 1;
  const out = [];
  const outerR = geom.thresholdsBarRadius || geom.r + geom.stroke * 0.75 + 1.5;
  for (let i = 1; i < clamped.length; i++) {
    const a0pct = Math.max(
      0,
      Math.min(1, (clamped[i - 1].value - it.min) / range)
    );
    const a1pct = Math.max(0, Math.min(1, (clamped[i].value - it.min) / range));
    const len = (a1pct - a0pct) * full;
    if (len <= 0.05) continue;
    out.push({
      d: arcPath(start + a0pct * full, len, geom, outerR),
      dRel: arcPathRelative(start + a0pct * full, len, outerR),
      color: clamped[i].color || baseColor
    });
  }
  return out;
}
function hexAlpha$1(hex, a) {
  const m = String(hex).match(/^#?([0-9a-f]{6})$/i);
  if (!m) return hex;
  const n = parseInt(m[1], 16);
  const r = n >> 16 & 255;
  const g = n >> 8 & 255;
  const b = n & 255;
  return `rgba(${r},${g},${b},${a})`;
}
function thresholdGradient(it, vertical) {
  const cssDir = vertical ? "0deg" : "90deg";
  const color = it.color || classicGreen();
  const steps = [...it.thresholds ?? []].map((s) => ({ value: Number(s.value), color: s.color || color })).filter((s) => Number.isFinite(s.value)).sort((a, b) => a.value - b.value);
  if (!steps.length) {
    return `linear-gradient(${cssDir}, ${hexAlpha$1(color, 0.35)} 0%, ${color} 100%)`;
  }
  const range = it.max - it.min || 1;
  const parts = [`${color} 0%`];
  let lastColor = color;
  for (const s of steps) {
    if (s.value <= it.min) {
      lastColor = s.color;
      continue;
    }
    if (s.value >= it.max) break;
    const pct = (s.value - it.min) / range * 100;
    parts.push(`${lastColor} ${pct}%`);
    parts.push(`${s.color} ${pct}%`);
    lastColor = s.color;
  }
  parts.push(`${lastColor} 100%`);
  return `linear-gradient(${cssDir}, ${parts.join(", ")})`;
}
function barFillStyle(it, displayMode = "gradient") {
  const mode2 = String(displayMode ?? "gradient");
  const color = it.color || classicBlue();
  const pct = `${Math.max(it.pct * 100, 0.5)}%`;
  if (mode2 === "basic") {
    return {
      background: hexAlpha$1(color, 0.35),
      borderRight: `2px solid ${color}`,
      width: pct,
      height: "100%"
    };
  }
  return {
    background: thresholdGradient(it, false),
    width: pct,
    height: "100%"
  };
}
function barFillStyleV(it, displayMode = "gradient") {
  const mode2 = String(displayMode ?? "gradient");
  const color = it.color || classicBlue();
  const pct = `${Math.max(it.pct * 100, 0.5)}%`;
  if (mode2 === "basic") {
    return {
      background: hexAlpha$1(color, 0.35),
      borderTop: `2px solid ${color}`,
      height: pct,
      width: "100%"
    };
  }
  return {
    background: thresholdGradient(it, true),
    height: pct,
    width: "100%"
  };
}
function lcdCellStyle(cell, isVertical, defaultSpacing = 8) {
  const size = Math.max(1, Number(cell.size ?? 8));
  const spacing = Math.max(0, Number(cell.spacing ?? defaultSpacing));
  const base = {
    borderRadius: "2px",
    flex: "0 0 auto"
  };
  if (isVertical) {
    base.height = `${size}px`;
    base.width = "100%";
    base.marginTop = `${spacing}px`;
  } else {
    base.width = `${size}px`;
    base.height = "100%";
    base.marginRight = `${spacing}px`;
  }
  if (cell.on) {
    base.backgroundImage = `radial-gradient(${cell.color} 10%, ${cell.shade})`;
  } else {
    base.backgroundColor = cell.color;
  }
  return base;
}
function barGlowStyle(color, enabled) {
  if (!enabled) return void 0;
  const c = color || classicBlue();
  return { filter: `drop-shadow(0 0 2px ${c}) drop-shadow(0 0 4px ${c})` };
}
function conicValueStyle(input) {
  const color = input.color || classicGreen();
  const css = input.shape === "circle" ? `conic-gradient(from 0deg, ${color} 0deg, ${color} 360deg)` : `conic-gradient(from ${input.startDeg}deg, ${color} ${(-input.fullDeg / 2).toFixed(0)}deg, ${color} ${input.fullDeg}deg, rgba(0, 0, 0, 0) 0deg, rgba(0, 0, 0, 0) ${input.fullDeg}deg)`;
  const box = Math.ceil((input.r + input.stroke) * 2);
  return {
    width: box + "px",
    height: box + "px",
    backgroundImage: css
  };
}
function hexToRgba(hex, alpha2) {
  const m = String(hex).replace("#", "").match(/^([0-9a-f]{6})$/i);
  if (!m) return `rgba(115, 191, 105, ${alpha2})`;
  const n = parseInt(m[1], 16);
  return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha2})`;
}
const LINE_HEIGHT_FACTOR = 1.21;
const VALUE_WIDTH_TO_RADIUS_FACTOR = 0.82;
const LARGE_RADIUS_SCALING_DECAY = 0.86;
const MAX_TEXT_WIDTH_DIVISOR = 7;
const MAX_NAME_HEIGHT_DIVISOR = 4;
const NAME_TO_HEIGHT_FACTOR = 0.45;
const VALUE_SPACE_PERCENTAGE = 0.7;
const SPARKLINE_SPACING = 8;
const MIN_NAME_FONT_SIZE = 10;
const VALUE_TEXT_COLOR = "var(--grafana-text)";
const NAME_TEXT_COLOR = "var(--grafana-text-secondary)";
function radialValueFontSize(text, r, barW) {
  const maxTextWidth = r * 2 - barW - r / MAX_TEXT_WIDTH_DIVISOR;
  const maxValueHeight = VALUE_WIDTH_TO_RADIUS_FACTOR * Math.pow(r, LARGE_RADIUS_SCALING_DECAY);
  const size = calculateFontSize(
    String(text ?? ""),
    maxTextWidth,
    maxValueHeight,
    LINE_HEIGHT_FACTOR,
    void 0,
    400
  );
  return Math.max(1, size);
}
function radialNameFontSize(title, r, barW, showValue, showName) {
  const maxTextWidth = r * 2 - barW - r / MAX_TEXT_WIDTH_DIVISOR;
  let maxNameHeight = r / MAX_NAME_HEIGHT_DIVISOR;
  if (showValue && showName) {
    maxNameHeight = NAME_TO_HEIGHT_FACTOR * Math.pow(r, LARGE_RADIUS_SCALING_DECAY);
  }
  const size = calculateFontSize(
    title,
    maxTextWidth,
    maxNameHeight,
    LINE_HEIGHT_FACTOR,
    void 0,
    400
  );
  return Math.max(MIN_NAME_FONT_SIZE, size);
}
function radialValueTextY(input) {
  if (!input.pixelSpace) return input.fallbackY;
  const valueHeight = input.valueFontSize * LINE_HEIGHT_FACTOR;
  const nameHeight = input.nameFontSize * LINE_HEIGHT_FACTOR;
  let valueY = input.showName ? input.cy - nameHeight * (1 - VALUE_SPACE_PERCENTAGE) : input.cy;
  let yOffset = 0;
  if (input.shape === "gauge") {
    yOffset += (valueHeight + nameHeight) / 4;
  }
  if (input.showSparkline && input.sparkLen > 1) {
    yOffset += SPARKLINE_SPACING;
  }
  return valueY - yOffset;
}
function radialNameTextY(input) {
  if (!input.pixelSpace) return input.fallbackY;
  const valueHeight = input.valueFontSize * LINE_HEIGHT_FACTOR;
  const nameHeight = input.nameFontSize * LINE_HEIGHT_FACTOR;
  let valueY = input.cy - nameHeight * (1 - VALUE_SPACE_PERCENTAGE);
  let nameY = input.showValue ? valueY + valueHeight * VALUE_SPACE_PERCENTAGE : input.cy;
  let yOffset = 0;
  if (input.shape === "gauge") {
    yOffset += (valueHeight + nameHeight) / 4;
  }
  if (input.showSparkline && input.sparkLen > 1) {
    yOffset += SPARKLINE_SPACING;
  }
  return nameY - yOffset;
}
const _hoisted_1$22 = ["data-reduce-calcs", "data-reduce-values", "data-multi", "data-legend-show", "data-display-mode", "data-name-placement", "data-title-placement", "data-value-mode", "data-orientation", "data-show-unfilled", "data-sizing", "data-min-viz-height", "data-min-viz-width", "data-item-spacing", "data-max-value-width", "data-min-value-height", "data-max-bar-height", "data-max-bar-width", "data-value-width", "data-max-viz-height"];
const _hoisted_2$1D = ["data-title-placement"];
const _hoisted_3$1r = {
  class: "bargauge-body",
  "data-testid": "bargauge-body"
};
const _hoisted_4$1g = { class: "bargauge-track-wrap" };
const _hoisted_5$16 = {
  key: 0,
  class: "empty"
};
const _hoisted_6$Z = ["data-reduce-fields", "data-reduce-values", "data-reduce-limit", "data-panel-w", "data-panel-h", "data-display-mode", "data-show-threshold-labels", "data-show-threshold-markers", "data-gauge-r", "data-gauge-cy", "data-scale-labels-r", "data-sizing", "data-shape", "data-text-mode", "data-bar-shape", "data-neutral", "data-endpoint", "data-segment-count", "data-segment-spacing", "data-min-viz-width", "data-min-viz-height", "data-bar-width-factor", "data-multi", "data-sparkline", "data-bar-glow", "data-center-glow", "data-gradient-effect"];
const _hoisted_7$W = {
  key: 0,
  class: "empty"
};
const _hoisted_8$N = ["data-bar-glow", "data-center-glow", "data-sparkline"];
const _hoisted_9$J = ["viewBox", "preserveAspectRatio"];
const _hoisted_10$D = ["d", "stroke-width", "stroke-linecap"];
const _hoisted_11$x = {
  key: 0,
  "data-testid": "gauge-thresholds-bar"
};
const _hoisted_12$r = ["id"];
const _hoisted_13$q = ["width", "height"];
const _hoisted_14$o = ["d", "stroke-width"];
const _hoisted_15$j = ["x", "width", "height", "mask"];
const _hoisted_16$i = ["cx", "cy", "r", "fill"];
const _hoisted_17$h = ["d", "stroke", "stroke-width", "stroke-linecap", "data-testid"];
const _hoisted_18$h = ["id"];
const _hoisted_19$g = ["width", "height"];
const _hoisted_20$f = ["d", "stroke-width", "stroke-linecap"];
const _hoisted_21$c = ["x", "y", "width", "height", "mask"];
const _hoisted_22$a = ["cx", "cy", "r", "fill", "opacity"];
const _hoisted_23$8 = ["x1", "y1", "x2", "y2", "stroke"];
const _hoisted_24$8 = ["x", "y", "font-size"];
const _hoisted_25$8 = ["x", "y", "fill", "font-size"];
const _hoisted_26$7 = ["x", "y", "fill", "font-size"];
const TRACK_COLOR = "var(--grafana-hover)";
const _sfc_main$2T = /* @__PURE__ */ defineComponent({
  __name: "GaugeRenderer",
  props: {
    data: {},
    fieldConfig: {},
    options: {},
    mode: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const reduceFieldsAttr = computed(
      () => String(opts.value.reduceOptions?.fields ?? "")
    );
    const reduceLimitAttr = computed(
      () => String(opts.value.reduceOptions?.limit ?? "")
    );
    const gaugeRootEl = ref(null);
    const panelSize = ref({ w: 0, h: 0 });
    let gaugeRo = null;
    function measureGaugePanel() {
      const el = gaugeRootEl.value;
      if (!el) return;
      const w = el.clientWidth || 0;
      const h2 = el.clientHeight || 0;
      if (w !== panelSize.value.w || h2 !== panelSize.value.h) {
        panelSize.value = { w, h: h2 };
      }
    }
    onMounted(() => {
      nextTick(() => {
        measureGaugePanel();
        if (typeof ResizeObserver !== "undefined" && gaugeRootEl.value) {
          gaugeRo = new ResizeObserver(() => {
            measureGaugePanel();
            paintSparklines();
          });
          gaugeRo.observe(gaugeRootEl.value);
        }
        paintSparklines();
      });
    });
    onBeforeUnmount(() => {
      gaugeRo?.disconnect();
      gaugeRo = null;
      for (const p of sparkPlots.values()) p.destroy();
      sparkPlots.clear();
    });
    const itemsCountHint = computed(() => {
      const frames = props.data?.series ?? [];
      let n = 0;
      for (const f of frames) {
        for (const field of f.fields ?? []) {
          if (field.type === "number") n += 1;
        }
      }
      return Math.max(1, n);
    });
    const geom = computed(() => {
      const labels = !!opts.value.showThresholdLabels;
      const pw = panelSize.value.w;
      const ph = panelSize.value.h;
      const textMode = String(opts.value.textMode ?? "auto");
      const showName = textMode === "name" || textMode === "value_and_name" || textMode === "auto" && itemsCountHint.value > 1;
      return panelGaugeGeometry({
        barWidthFactor: Number(opts.value.barWidthFactor ?? 0.5),
        roundedBars: opts.value.barShape == null ? false : String(opts.value.barShape) === "rounded",
        thresholdBar: opts.value.showThresholdMarkers !== false,
        showScaleLabels: labels,
        glow: !!opts.value.effects?.barGlow || !!opts.value.effects?.centerGlow,
        shape: String(opts.value.shape ?? "gauge"),
        panelWidth: pw > 40 ? pw : void 0,
        panelHeight: ph > 40 ? ph : void 0,
        showName,
        sparkline: opts.value.sparkline === true
      });
    });
    const CX = computed(() => geom.value.cx);
    const CY = computed(() => geom.value.cy);
    const R = computed(() => geom.value.r);
    const VIEW_W = computed(() => geom.value.viewW);
    const VIEW_H = computed(() => geom.value.viewH);
    const MIN_VALUE_HEIGHT = BAR_GAUGE_LAYOUT.MIN_VALUE_HEIGHT;
    const MAX_VALUE_HEIGHT = BAR_GAUGE_LAYOUT.MAX_VALUE_HEIGHT;
    const DEFAULT_ITEM_SPACING = BAR_GAUGE_LAYOUT.DEFAULT_ITEM_SPACING;
    const items = computed(
      () => prepareGaugeItems({
        series: props.data?.series ?? [],
        fieldDefaults: props.fieldConfig?.defaults ?? {},
        reduceCalc: opts.value.reduceOptions?.calcs?.[0],
        textMode: opts.value.textMode,
        fieldsFilter: opts.value.reduceOptions?.fields,
        showAllValues: opts.value.reduceOptions?.values === true,
        limit: opts.value.reduceOptions?.limit
      })
    );
    const multi = computed(() => items.value.length > 1);
    const shape = computed(() => String(opts.value.shape ?? "gauge"));
    function arcPath$1(startDeg, lengthDeg, radius) {
      return arcPath(startDeg, lengthDeg, arcGeom(), radius);
    }
    function trackArcs$1(it) {
      return trackArcs(
        it,
        arcGeom(),
        opts.value.neutral
      );
    }
    function thresholdTicks$1(it) {
      return thresholdTicks(it, arcGeom());
    }
    const showValueText = (it) => opts.value.textMode !== "name" && !!it.text;
    const showNameText = (it) => opts.value.textMode !== "value" && opts.value.textMode !== "none" && !!it.name;
    function lcdCells(it, cellCount) {
      const lcdW = Number(opts.value.lcdCellWidth ?? DEFAULT_LCD_CELL_WIDTH) || DEFAULT_LCD_CELL_WIDTH;
      const maxSize = Number(
        opts.value.minVizWidth ?? opts.value.maxVizWidth ?? (isVertical.value ? barTrackHeight.value * 4 : 180)
      ) || 180;
      const spacingRaw = Number(opts.value.itemSpacing);
      const spacing = Number.isFinite(spacingRaw) && spacingRaw >= 0 ? spacingRaw : DEFAULT_ITEM_SPACING;
      const value = it.min + it.pct * (it.max - it.min || 1);
      const colorAt = (pos) => {
        if (it.thresholds?.length) {
          const steps = [...it.thresholds].sort(
            (a, b) => Number(a.value) - Number(b.value)
          );
          let c = steps[0]?.color || it.color;
          for (const s of steps) {
            if (pos >= Number(s.value)) c = s.color || c;
          }
          return c || it.color;
        }
        return it.color;
      };
      let cells = buildLcdCells({
        min: it.min,
        max: it.max,
        value,
        color: it.color,
        colorAt,
        lcdCellWidth: lcdW,
        maxSize,
        itemSpacing: spacing
      });
      return cells.map((c) => ({
        on: c.on,
        color: c.color,
        shade: c.shade,
        size: c.size,
        spacing: c.spacing
      }));
    }
    function lcdCellStyle$1(cell) {
      return lcdCellStyle(cell, isVertical.value, DEFAULT_ITEM_SPACING);
    }
    function barFillStyle$1(it) {
      return barFillStyle(it, String(opts.value.displayMode ?? "gradient"));
    }
    function barFillStyleV$1(it) {
      return barFillStyleV(it, String(opts.value.displayMode ?? "gradient"));
    }
    const strokeW = computed(() => geom.value.stroke);
    function arcGeom() {
      return {
        shape: shape.value,
        r: R.value,
        cx: CX.value,
        cy: CY.value,
        stroke: strokeW.value,
        scaleLabelsRadius: geom.value.scaleLabelsRadius,
        thresholdsBarRadius: geom.value.thresholdsBarRadius
      };
    }
    const segmentCount = computed(
      () => Math.max(1, Math.floor(Number(opts.value.segmentCount ?? 1)))
    );
    const segmentSpacing = computed(
      () => Math.max(0, Number(opts.value.segmentSpacing ?? 0.3))
    );
    function segmentArcs$1(it) {
      return segmentArcs(
        it,
        arcGeom(),
        segmentCount.value,
        segmentSpacing.value,
        opts.value.neutral
      );
    }
    function endpointPos$1(it) {
      return endpointPos(
        it,
        arcGeom(),
        opts.value.endpointMarker,
        opts.value.neutral
      );
    }
    function valueArcAngles$1(it) {
      return valueArcAngles(
        it,
        shape.value,
        opts.value.neutral
      );
    }
    const itemSpacing = computed(() => {
      const n = Number(opts.value.itemSpacing);
      return Number.isFinite(n) && n >= 0 ? n : DEFAULT_ITEM_SPACING;
    });
    const isManualSizing = computed(
      () => String(opts.value.sizing ?? "auto") === "manual"
    );
    const barTrackHeight = computed(() => {
      const minH = isManualSizing.value ? Number(opts.value.minVizHeight) : NaN;
      const maxH = isManualSizing.value ? Number(opts.value.maxVizHeight) : NaN;
      let h2 = Number.isFinite(minH) && minH > 0 ? Math.max(MIN_VALUE_HEIGHT, Math.min(MAX_VALUE_HEIGHT, minH)) : MIN_VALUE_HEIGHT + 4;
      if (Number.isFinite(maxH) && maxH > 0) h2 = Math.min(h2, maxH);
      return h2;
    });
    const barTrackWidth = computed(() => {
      if (!isManualSizing.value) return 80;
      const minW = Number(opts.value.minVizWidth);
      if (Number.isFinite(minW) && minW > 0) return minW;
      return 80;
    });
    const isVertical = computed(() => {
      const o = String(opts.value.orientation ?? "auto");
      if (o === "vertical") return true;
      if (o === "horizontal") return false;
      const w = panelSize.value.w || 0;
      const h2 = panelSize.value.h || 0;
      if (w > 0 && h2 > 0) return w > h2;
      return false;
    });
    const isLcd = computed(() => String(opts.value.displayMode ?? "") === "lcd");
    const linecap = computed(
      () => String(opts.value.barShape ?? "") === "rounded" ? "round" : "butt"
    );
    function itemBarLayout(it) {
      const pw = panelSize.value.w > 40 ? panelSize.value.w : 0;
      const ph = panelSize.value.h > 40 ? panelSize.value.h : 0;
      const n = Math.max(1, items.value.length);
      const spacing = itemSpacing.value;
      let height2 = ph || (isVertical.value ? 200 : 36);
      let width2 = pw || (isVertical.value ? 80 : 400);
      if (ph && pw) {
        if (isVertical.value && n > 1) {
          width2 = Math.max(1, (pw - spacing * (n - 1)) / n);
          height2 = ph;
        } else if (!isVertical.value && n > 1) {
          height2 = Math.max(1, (ph - spacing * (n - 1)) / n);
          width2 = pw;
        }
      }
      if (isManualSizing.value) {
        if (!isVertical.value) {
          const minH = Number(opts.value.minVizHeight);
          const maxH = Number(opts.value.maxVizHeight);
          if (Number.isFinite(minH) && minH > 0) height2 = Math.max(height2, minH);
          if (Number.isFinite(maxH) && maxH > 0) height2 = Math.min(height2, maxH);
        } else {
          const minW = Number(opts.value.minVizWidth);
          if (Number.isFinite(minW) && minW > 0) width2 = Math.max(width2, minW);
        }
      }
      const title = it?.name ?? "";
      return calculateBarAndValueDimensions({
        height: height2,
        width: width2,
        orientation: isVertical.value ? "vertical" : "horizontal",
        namePlacement: String(opts.value.namePlacement ?? "auto"),
        title,
        valueText: it?.text ?? items.value[0]?.text ?? "0",
        valueMode: String(opts.value.valueMode ?? "color"),
        titleSize: Number(opts.value.text?.titleSize) || void 0,
        valueSize: Number(opts.value.text?.valueSize) || void 0
      });
    }
    const barItemLayout = computed(() => itemBarLayout(items.value[0]));
    const titlePlacement = computed(() => {
      const minH = Number(opts.value.minVizHeight);
      const panelHeight = panelSize.value.h > 40 ? panelSize.value.h : Number.isFinite(minH) && minH > 0 ? minH : isVertical.value ? 200 : 36;
      const hasTitle = items.value.some((it) => !!it.name);
      return resolveTitlePlacement({
        orientation: isVertical.value ? "vertical" : "horizontal",
        namePlacement: String(opts.value.namePlacement ?? "auto"),
        panelHeight,
        hasTitle
      });
    });
    function itemTitlePlacement(it) {
      if (!it.name || opts.value.namePlacement === "hidden") return "hidden";
      return titlePlacement.value;
    }
    function barValueStyle(it) {
      const layout = itemBarLayout(it);
      const mode2 = String(opts.value.valueMode ?? "color");
      const color = mode2 === "text" ? VALUE_TEXT_COLOR : mode2 === "hidden" ? "transparent" : it.color || classicGreen();
      const fixedSize = Number(opts.value.text?.valueSize);
      if (isVertical.value) {
        const fontSize2 = Number.isFinite(fixedSize) && fixedSize > 0 ? fixedSize : calculateFontSize(
          String(it.text ?? ""),
          layout.valueWidth,
          layout.valueHeight,
          BAR_GAUGE_LAYOUT.VALUE_LINE_HEIGHT
        );
        return {
          color,
          height: `${layout.valueHeight}px`,
          width: `${layout.valueWidth}px`,
          maxWidth: "100%",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          fontSize: `${Math.max(1, fontSize2)}px`,
          lineHeight: String(BAR_GAUGE_LAYOUT.VALUE_LINE_HEIGHT),
          paddingLeft: "0",
          textAlign: "center",
          overflow: "hidden",
          whiteSpace: "nowrap"
        };
      }
      const fontSize = Number.isFinite(fixedSize) && fixedSize > 0 ? fixedSize : calculateFontSize(
        String(it.text ?? ""),
        Math.max(
          1,
          layout.valueWidth - BAR_GAUGE_LAYOUT.VALUE_LEFT_PADDING * 2
        ),
        layout.valueHeight,
        BAR_GAUGE_LAYOUT.VALUE_LINE_HEIGHT
      );
      return {
        color,
        height: `${layout.valueHeight}px`,
        maxWidth: `${BAR_GAUGE_LAYOUT.MAX_VALUE_WIDTH}px`,
        minWidth: `${Math.min(40, layout.valueWidth)}px`,
        display: "flex",
        alignItems: "center",
        justifyContent: "flex-end",
        fontSize: `${Math.max(1, fontSize)}px`,
        lineHeight: String(BAR_GAUGE_LAYOUT.VALUE_LINE_HEIGHT),
        paddingLeft: `${BAR_GAUGE_LAYOUT.VALUE_LEFT_PADDING}px`,
        overflow: "hidden",
        whiteSpace: "nowrap"
      };
    }
    function barTrackBoxStyle(it) {
      const layout = itemBarLayout(it);
      if (isVertical.value) {
        const h2 = Math.max(1, layout.maxBarHeight);
        return {
          "--bar-h": `${h2}px`,
          height: `${h2}px`,
          width: "100%",
          // Grafana emptyBar: theme.colors.background.secondary (dark gray15)
          background: opts.value.showUnfilled === false ? "transparent" : "var(--grafana-hover)"
        };
      }
      return {
        "--bar-h": `${barTrackHeight.value}px`,
        height: `${barTrackHeight.value}px`,
        background: opts.value.showUnfilled === false ? "transparent" : "var(--grafana-hover)"
      };
    }
    function barLcdBoxStyle(it) {
      const layout = itemBarLayout(it);
      if (isVertical.value) {
        return {
          height: `${Math.max(1, layout.maxBarHeight)}px`,
          width: `${Math.max(12, layout.maxBarWidth || 40)}px`
        };
      }
      return {
        height: `${opts.value.minVizHeight || barTrackHeight.value}px`,
        width: "100%"
      };
    }
    const effects = computed(() => {
      const e = opts.value.effects ?? {};
      return {
        gradient: e.gradient === true,
        barGlow: e.barGlow === true,
        centerGlow: e.centerGlow === true
      };
    });
    const showSparkline = computed(() => opts.value.sparkline === true);
    const sparkHosts = ref({});
    const sparkPlots = /* @__PURE__ */ new Map();
    function setSparkHost(i, el) {
      sparkHosts.value[i] = el || null;
    }
    function paintSparklines() {
      if (!showSparkline.value) {
        for (const p of sparkPlots.values()) p.destroy();
        sparkPlots.clear();
        return;
      }
      const list = items.value;
      for (let i = 0; i < list.length; i++) {
        const it = list[i];
        const host = sparkHosts.value[i];
        const prev = sparkPlots.get(i);
        if (prev) {
          prev.destroy();
          sparkPlots.delete(i);
        }
        if (!host || it.spark.length < 2) {
          if (host) host.innerHTML = "";
          continue;
        }
        const w = Math.max(2, Math.floor(geom.value.sparkWidth));
        const h2 = Math.max(2, Math.floor(geom.value.sparkHeight));
        host.innerHTML = "";
        host.style.width = w + "px";
        host.style.height = h2 + "px";
        let min = Math.min(...it.spark);
        let max = Math.max(...it.spark);
        if (min === max) {
          if (min === 0) max = 1;
          else if (min < 0) min *= 2;
          else max *= 2;
        }
        const stroke = it.color || classicGreen();
        const fillColor = stroke.startsWith("#") ? stroke : classicGreen();
        const opacity = 0.4;
        const xs = it.spark.map((_, idx) => idx);
        const ys = it.spark.slice();
        const rangePad = 3;
        const plot = new uPlot(
          {
            width: w,
            height: h2,
            pxAlign: false,
            cursor: { show: false, x: false, y: false },
            legend: { show: false },
            padding: [rangePad, rangePad, rangePad, rangePad],
            scales: {
              x: { time: false, range: [0, Math.max(1, it.spark.length - 1)] },
              y: { range: [min, max] }
            },
            axes: [
              { show: false, scale: "x" },
              { show: false, scale: "y" }
            ],
            series: [
              {},
              {
                stroke,
                width: 1.5,
                // Grafana getOpacityGradientFn — vertical fade line→transparent
                fill: (u) => {
                  const { top, height: height2 } = u.bbox;
                  const g = u.ctx.createLinearGradient(
                    0,
                    top,
                    0,
                    top + height2
                  );
                  g.addColorStop(0, hexToRgba(fillColor, opacity));
                  g.addColorStop(1, hexToRgba(fillColor, 0));
                  return g;
                },
                // Grafana showHighlights + lastNotNull → last point size 6
                points: {
                  show: (_u, _s, i2) => i2 === it.spark.length - 1,
                  size: 6,
                  width: 0,
                  fill: stroke,
                  stroke
                },
                pxAlign: false,
                // Grafana LineInterpolation.Smooth
                paths: uPlot.paths?.spline?.() ?? void 0
              }
            ]
          },
          [xs, ys],
          host
        );
        sparkPlots.set(i, plot);
      }
      for (const key of [...sparkPlots.keys()]) {
        if (key >= list.length) {
          sparkPlots.get(key)?.destroy();
          sparkPlots.delete(key);
        }
      }
    }
    watch(
      () => [
        items.value,
        geom.value.sparkWidth,
        geom.value.sparkHeight,
        showSparkline.value,
        panelSize.value.w,
        panelSize.value.h
      ],
      () => nextTick(() => paintSparklines()),
      { deep: true }
    );
    function valueFontSize(it) {
      return radialValueFontSize(String(it.text ?? ""), R.value, strokeW.value);
    }
    function nameFontSize(it) {
      const title = it.name || it.titleForLayout || "";
      return radialNameFontSize(
        title,
        R.value,
        strokeW.value,
        showValueText(it),
        !!it.name
      );
    }
    function valueTextYFor(it) {
      return radialValueTextY({
        cx: CX.value,
        cy: CY.value,
        shape: shape.value,
        showName: !!it.name,
        valueFontSize: valueFontSize(it),
        nameFontSize: nameFontSize(it),
        pixelSpace: !!geom.value.pixelSpace,
        fallbackY: geom.value.valueTextY,
        showSparkline: showSparkline.value,
        sparkLen: it.spark.length
      });
    }
    function nameTextYFor(it) {
      return radialNameTextY({
        cy: CY.value,
        shape: shape.value,
        showValue: showValueText(it),
        valueFontSize: valueFontSize(it),
        nameFontSize: nameFontSize(it),
        pixelSpace: !!geom.value.pixelSpace,
        fallbackY: geom.value.nameTextY,
        showSparkline: showSparkline.value,
        sparkLen: it.spark.length
      });
    }
    function thresholdBarArcs$1(it) {
      return thresholdBarArcs(
        it,
        arcGeom(),
        opts.value.showThresholdMarkers
      );
    }
    function conicValueStyle$1(it) {
      return conicValueStyle({
        shape: shape.value,
        color: it.color,
        startDeg: startAngleForShape(shape.value),
        fullDeg: angleRangeForShape(shape.value),
        r: R.value,
        stroke: strokeW.value
      });
    }
    function barGlowStyle$1(it) {
      return barGlowStyle(it.color, !!effects.value.barGlow);
    }
    return (_ctx, _cache) => {
      return __props.mode === "bargauge" ? (openBlock(), createElementBlock("div", {
        key: 0,
        ref_key: "gaugeRootEl",
        ref: gaugeRootEl,
        class: normalizeClass(["bargauge-list", {
          vertical: isVertical.value,
          ["name-" + titlePlacement.value]: true
        }]),
        "data-testid": "panel-bargauge",
        "data-reduce-calcs": String((opts.value.reduceOptions?.calcs ?? []).join(",")),
        "data-reduce-values": String(!!opts.value.reduceOptions?.values),
        "data-multi": String(multi.value),
        "data-legend-show": String(opts.value.legend?.showLegend !== false),
        style: normalizeStyle({ gap: itemSpacing.value + "px" }),
        "data-display-mode": String(opts.value.displayMode ?? "basic"),
        "data-name-placement": String(opts.value.namePlacement ?? "auto"),
        "data-title-placement": String(titlePlacement.value),
        "data-value-mode": String(opts.value.valueMode ?? "color"),
        "data-orientation": String(opts.value.orientation ?? "horizontal"),
        "data-show-unfilled": String(opts.value.showUnfilled !== false),
        "data-sizing": String(opts.value.sizing ?? "auto"),
        "data-min-viz-height": String(opts.value.minVizHeight ?? barTrackHeight.value),
        "data-min-viz-width": String(opts.value.minVizWidth ?? barTrackWidth.value),
        "data-item-spacing": String(itemSpacing.value),
        "data-max-value-width": String(unref(BAR_GAUGE_LAYOUT).MAX_VALUE_WIDTH),
        "data-min-value-height": String(unref(MIN_VALUE_HEIGHT)),
        "data-max-bar-height": String(Math.round(barItemLayout.value.maxBarHeight)),
        "data-max-bar-width": String(Math.round(barItemLayout.value.maxBarWidth)),
        "data-value-width": String(Math.round(barItemLayout.value.valueWidth)),
        "data-max-viz-height": String(opts.value.maxVizHeight ?? "")
      }, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(items.value, (it, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: normalizeClass(["bargauge", ["name-" + itemTitlePlacement(it), { vertical: isVertical.value }]]),
              "data-title-placement": itemTitlePlacement(it),
              style: normalizeStyle(
                isVertical.value ? {
                  // Grafana VizRepeater vertical: each item gets vizWidth ≈ panelWidth/n
                  height: "100%",
                  width: Math.max(barItemLayout.value.wrapperWidth || panelSize.value.w || 80, 40) + "px",
                  flex: "1 1 auto",
                  maxWidth: "100%"
                } : {
                  minHeight: Math.max(barTrackHeight.value, barItemLayout.value.wrapperHeight * 0.3) + "px",
                  width: "100%"
                }
              )
            }, [
              itemTitlePlacement(it) !== "hidden" && it.name ? (openBlock(), createElementBlock(
                "div",
                {
                  key: 0,
                  class: "bargauge-label",
                  "data-testid": "bargauge-name",
                  style: normalizeStyle(
                    itemTitlePlacement(it) === "left" ? {
                      width: Math.max(
                        48,
                        Math.min(120, barItemLayout.value.wrapperWidth * 0.35)
                      ) + "px",
                      maxWidth: "40%",
                      textAlign: "right",
                      paddingRight: "10px"
                    } : void 0
                  )
                },
                toDisplayString(it.name),
                5
                /* TEXT, STYLE */
              )) : createCommentVNode("v-if", true),
              createElementVNode("div", _hoisted_3$1r, [
                opts.value.valueMode !== "hidden" && isVertical.value ? (openBlock(), createElementBlock(
                  "div",
                  {
                    key: 0,
                    class: normalizeClass(["bargauge-value", {
                      "value-text": opts.value.valueMode === "text",
                      "value-color": opts.value.valueMode === "color" || !opts.value.valueMode
                    }]),
                    "data-testid": "bargauge-value",
                    style: normalizeStyle(barValueStyle(it))
                  },
                  toDisplayString(it.text),
                  7
                  /* TEXT, CLASS, STYLE */
                )) : createCommentVNode("v-if", true),
                createElementVNode("div", _hoisted_4$1g, [
                  isLcd.value ? (openBlock(), createElementBlock(
                    "div",
                    {
                      key: 0,
                      class: normalizeClass(["bargauge-lcd", { vertical: isVertical.value }]),
                      style: normalizeStyle(barLcdBoxStyle(it)),
                      "data-testid": "bargauge-lcd"
                    },
                    [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(lcdCells(it), (cell, ci) => {
                          return openBlock(), createElementBlock(
                            "div",
                            {
                              key: ci,
                              class: normalizeClass(["lcd-cell", { on: cell.on }]),
                              style: normalizeStyle(lcdCellStyle$1(cell)),
                              "data-testid": "bargauge-lcd-cell"
                            },
                            null,
                            6
                            /* CLASS, STYLE */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ],
                    6
                    /* CLASS, STYLE */
                  )) : (openBlock(), createElementBlock(
                    "div",
                    {
                      key: 1,
                      class: normalizeClass(["bargauge-track", [
                        String(opts.value.displayMode ?? "basic"),
                        {
                          "no-unfilled": opts.value.showUnfilled === false,
                          vertical: isVertical.value
                        }
                      ]]),
                      style: normalizeStyle(barTrackBoxStyle(it)),
                      "data-testid": "bargauge-track"
                    },
                    [
                      createElementVNode(
                        "div",
                        {
                          class: "bargauge-fill",
                          style: normalizeStyle(isVertical.value ? barFillStyleV$1(it) : barFillStyle$1(it))
                        },
                        null,
                        4
                        /* STYLE */
                      )
                    ],
                    6
                    /* CLASS, STYLE */
                  ))
                ]),
                opts.value.valueMode !== "hidden" && !isVertical.value ? (openBlock(), createElementBlock(
                  "div",
                  {
                    key: 1,
                    class: normalizeClass(["bargauge-value", {
                      "value-text": opts.value.valueMode === "text",
                      "value-color": opts.value.valueMode === "color" || !opts.value.valueMode
                    }]),
                    "data-testid": "bargauge-value",
                    style: normalizeStyle(barValueStyle(it))
                  },
                  toDisplayString(it.text),
                  7
                  /* TEXT, CLASS, STYLE */
                )) : createCommentVNode("v-if", true)
              ])
            ], 14, _hoisted_2$1D);
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        !items.value.length ? (openBlock(), createElementBlock("div", _hoisted_5$16, "暂无数据")) : createCommentVNode("v-if", true)
      ], 14, _hoisted_1$22)) : (openBlock(), createElementBlock("div", {
        key: 1,
        ref_key: "gaugeRootEl",
        ref: gaugeRootEl,
        class: "gauge-root",
        "data-testid": "panel-gauge",
        "data-reduce-fields": reduceFieldsAttr.value,
        "data-reduce-values": String(!!opts.value.reduceOptions?.values),
        "data-reduce-limit": reduceLimitAttr.value,
        "data-panel-w": String(panelSize.value.w),
        "data-panel-h": String(panelSize.value.h),
        "data-display-mode": String(opts.value.displayMode ?? "gradient"),
        "data-show-threshold-labels": String(!!opts.value.showThresholdLabels),
        "data-show-threshold-markers": String(opts.value.showThresholdMarkers !== false),
        "data-gauge-r": String(R.value),
        "data-gauge-cy": String(CY.value),
        "data-scale-labels-r": String(geom.value.scaleLabelsRadius),
        "data-sizing": String(opts.value.sizing ?? "auto"),
        "data-shape": String(opts.value.shape ?? "gauge"),
        "data-text-mode": String(opts.value.textMode ?? "auto"),
        "data-bar-shape": String(opts.value.barShape ?? ""),
        "data-neutral": String(opts.value.neutral ?? ""),
        "data-endpoint": String(opts.value.endpointMarker ?? ""),
        "data-segment-count": String(segmentCount.value),
        "data-segment-spacing": String(segmentSpacing.value),
        "data-min-viz-width": String(opts.value.minVizWidth ?? ""),
        "data-min-viz-height": String(opts.value.minVizHeight ?? ""),
        "data-bar-width-factor": String(opts.value.barWidthFactor ?? 0.5),
        "data-multi": String(multi.value),
        "data-sparkline": String(!!opts.value.sparkline),
        "data-bar-glow": String(!!opts.value.effects?.barGlow),
        "data-center-glow": String(!!opts.value.effects?.centerGlow),
        "data-gradient-effect": String(!!opts.value.effects?.gradient)
      }, [
        !items.value.length ? (openBlock(), createElementBlock("div", _hoisted_7$W, "暂无数据")) : (openBlock(), createElementBlock(
          "div",
          {
            key: 1,
            class: normalizeClass(["gauge-grid", { multi: multi.value }])
          },
          [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(items.value, (it, i) => {
                return openBlock(), createElementBlock("div", {
                  key: i,
                  class: "gauge",
                  "data-bar-glow": String(effects.value.barGlow),
                  "data-center-glow": String(effects.value.centerGlow),
                  "data-sparkline": String(showSparkline.value)
                }, [
                  (openBlock(), createElementBlock("svg", {
                    viewBox: `0 0 ${VIEW_W.value} ${VIEW_H.value}`,
                    class: "gauge-svg",
                    "aria-hidden": "true",
                    preserveAspectRatio: geom.value.pixelSpace ? "none" : "xMidYMid meet"
                  }, [
                    createCommentVNode(" Track (unfilled only — Grafana RadialBar) "),
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(trackArcs$1(it), (tr, tri) => {
                        return openBlock(), createElementBlock("path", {
                          key: "track" + tri,
                          d: tr.d,
                          fill: "none",
                          stroke: TRACK_COLOR,
                          "stroke-width": strokeW.value,
                          "stroke-linecap": linecap.value,
                          "data-testid": "gauge-track"
                        }, null, 8, _hoisted_10$D);
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    )),
                    createCommentVNode(" ThresholdsBar (outer multi-stop ring) "),
                    opts.value.showThresholdMarkers !== false && thresholdBarArcs$1(it).length ? (openBlock(), createElementBlock("g", _hoisted_11$x, [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(thresholdBarArcs$1(it), (tb, tbi) => {
                          return openBlock(), createElementBlock(
                            Fragment,
                            {
                              key: "tb" + tbi
                            },
                            [
                              createElementVNode("defs", null, [
                                createElementVNode("mask", {
                                  id: "gauge-th-mask-" + i + "-" + tbi,
                                  maskUnits: "userSpaceOnUse",
                                  maskContentUnits: "userSpaceOnUse"
                                }, [
                                  createElementVNode("rect", {
                                    x: "0",
                                    y: "0",
                                    width: VIEW_W.value,
                                    height: VIEW_H.value,
                                    fill: "black"
                                  }, null, 8, _hoisted_13$q),
                                  createElementVNode("path", {
                                    d: tb.d,
                                    fill: "none",
                                    stroke: "white",
                                    "stroke-width": geom.value.thresholdsBarWidth > 0 ? geom.value.thresholdsBarWidth : Math.max(2, strokeW.value * 0.35),
                                    "stroke-linecap": "butt"
                                  }, null, 8, _hoisted_14$o)
                                ], 8, _hoisted_12$r)
                              ]),
                              (openBlock(), createElementBlock("foreignObject", {
                                x: Math.round(
                                  CX.value - (geom.value.thresholdsBarRadius || R.value) - (geom.value.thresholdsBarWidth || 4)
                                ),
                                y: "0",
                                width: VIEW_W.value,
                                height: Math.max(
                                  VIEW_H.value,
                                  Math.ceil(
                                    ((geom.value.thresholdsBarRadius || R.value) + (geom.value.thresholdsBarWidth || 4)) * 2
                                  )
                                ),
                                mask: "url(#gauge-th-mask-" + i + "-" + tbi + ")"
                              }, [
                                createElementVNode(
                                  "div",
                                  {
                                    xmlns: "http://www.w3.org/1999/xhtml",
                                    style: normalizeStyle({
                                      width: Math.ceil(
                                        ((geom.value.thresholdsBarRadius || R.value) + (geom.value.thresholdsBarWidth || 4)) * 2
                                      ) + "px",
                                      height: Math.ceil(
                                        ((geom.value.thresholdsBarRadius || R.value) + (geom.value.thresholdsBarWidth || 4)) * 2
                                      ) + "px",
                                      backgroundImage: `conic-gradient(from ${unref(startAngleForShape)(shape.value)}deg, ${tb.color} ${-unref(angleRangeForShape)(shape.value) / 2}deg, ${tb.color} ${unref(angleRangeForShape)(shape.value)}deg, rgba(0,0,0,0) 0deg, rgba(0,0,0,0) ${unref(angleRangeForShape)(shape.value)}deg)`
                                    })
                                  },
                                  null,
                                  4
                                  /* STYLE */
                                )
                              ], 8, _hoisted_15$j))
                            ],
                            64
                            /* STABLE_FRAGMENT */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])) : createCommentVNode("v-if", true),
                    createCommentVNode(" Center glow (effects.centerGlow) "),
                    effects.value.centerGlow ? (openBlock(), createElementBlock("circle", {
                      key: 1,
                      cx: CX.value,
                      cy: CY.value,
                      r: R.value * 0.42,
                      fill: it.color || "var(--grafana-primary)",
                      opacity: "0.18",
                      "data-testid": "gauge-center-glow"
                    }, null, 8, _hoisted_16$i)) : createCommentVNode("v-if", true),
                    createCommentVNode(" Segmented bars when segmentCount > 1 "),
                    segmentCount.value > 1 ? (openBlock(true), createElementBlock(
                      Fragment,
                      { key: 2 },
                      renderList(segmentArcs$1(it), (seg, si) => {
                        return openBlock(), createElementBlock("path", {
                          key: "seg" + si,
                          d: seg.d,
                          fill: "none",
                          stroke: seg.on ? it.color || "var(--grafana-primary)" : TRACK_COLOR,
                          "stroke-width": strokeW.value,
                          "stroke-linecap": linecap.value,
                          "data-testid": seg.on ? "gauge-segment-on" : "gauge-segment-off",
                          style: normalizeStyle(seg.on ? barGlowStyle$1(it) : void 0)
                        }, null, 12, _hoisted_17$h);
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    )) : createCommentVNode("v-if", true),
                    createCommentVNode(" Grafana RadialArcPath: mask (relative path + translate) + conic FO "),
                    valueArcAngles$1(it).endValueAngle > 0.05 ? (openBlock(), createElementBlock(
                      Fragment,
                      { key: 3 },
                      [
                        createElementVNode("defs", null, [
                          createElementVNode("mask", {
                            id: "gauge-val-mask-" + i,
                            maskUnits: "userSpaceOnUse",
                            maskContentUnits: "userSpaceOnUse"
                          }, [
                            createElementVNode("rect", {
                              x: "0",
                              y: "0",
                              width: VIEW_W.value,
                              height: VIEW_H.value,
                              fill: "black"
                            }, null, 8, _hoisted_19$g),
                            createElementVNode("path", {
                              d: arcPath$1(
                                valueArcAngles$1(it).start,
                                valueArcAngles$1(it).endValueAngle
                              ),
                              fill: "none",
                              stroke: "white",
                              "stroke-width": strokeW.value,
                              "stroke-linecap": linecap.value
                            }, null, 8, _hoisted_20$f)
                          ], 8, _hoisted_18$h)
                        ]),
                        (openBlock(), createElementBlock("foreignObject", {
                          x: Math.round(CX.value - R.value - strokeW.value),
                          y: Math.max(0, Math.round(CY.value - R.value - strokeW.value)),
                          width: VIEW_W.value,
                          height: Math.max(VIEW_H.value, Math.ceil((R.value + strokeW.value) * 2)),
                          mask: "url(#gauge-val-mask-" + i + ")",
                          "data-testid": "gauge-value-arc",
                          style: normalizeStyle(barGlowStyle$1(it))
                        }, [
                          createElementVNode(
                            "div",
                            {
                              xmlns: "http://www.w3.org/1999/xhtml",
                              style: normalizeStyle(conicValueStyle$1(it))
                            },
                            null,
                            4
                            /* STYLE */
                          )
                        ], 12, _hoisted_21$c))
                      ],
                      64
                      /* STABLE_FRAGMENT */
                    )) : createCommentVNode("v-if", true),
                    createCommentVNode(" Grafana: endpointMarker only when roundedBars (barShape=rounded) "),
                    endpointPos$1(it) && String(opts.value.barShape) === "rounded" && String(opts.value.endpointMarker ?? "point") !== "none" ? (openBlock(), createElementBlock("circle", {
                      key: 4,
                      cx: endpointPos$1(it)?.x,
                      cy: endpointPos$1(it)?.y,
                      r: String(opts.value.endpointMarker) === "glow" ? Math.max(2, strokeW.value * 0.35) : Math.max(2, strokeW.value * 0.25),
                      fill: it.color || "var(--grafana-primary)",
                      opacity: String(opts.value.endpointMarker) === "glow" ? 0.85 : 1,
                      "data-testid": "gauge-endpoint"
                    }, null, 8, _hoisted_22$a)) : createCommentVNode("v-if", true),
                    opts.value.showThresholdMarkers !== false ? (openBlock(), createElementBlock(
                      Fragment,
                      { key: 5 },
                      [
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(thresholdTicks$1(it), (tk, ti) => {
                            return openBlock(), createElementBlock("line", {
                              key: "t" + ti,
                              x1: tk.x1,
                              y1: tk.y1,
                              x2: tk.x2,
                              y2: tk.y2,
                              stroke: tk.color,
                              "stroke-width": "1.5"
                            }, null, 8, _hoisted_23$8);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        )),
                        opts.value.showThresholdLabels ? (openBlock(true), createElementBlock(
                          Fragment,
                          { key: 0 },
                          renderList(thresholdTicks$1(it), (tk, ti) => {
                            return openBlock(), createElementBlock("text", {
                              key: "l" + ti,
                              x: tk.lx,
                              y: tk.ly,
                              "font-size": geom.value.scaleLabelsFontSize || 3.5,
                              fill: "var(--grafana-text-secondary)",
                              "text-anchor": "middle",
                              "dominant-baseline": "middle",
                              "data-testid": "gauge-threshold-label"
                            }, toDisplayString(tk.label), 9, _hoisted_24$8);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        )) : createCommentVNode("v-if", true)
                      ],
                      64
                      /* STABLE_FRAGMENT */
                    )) : createCommentVNode("v-if", true),
                    showValueText(it) ? (openBlock(), createElementBlock("text", {
                      key: 6,
                      x: CX.value,
                      y: valueTextYFor(it),
                      "text-anchor": "middle",
                      "dominant-baseline": "middle",
                      class: "gauge-svg-value",
                      fill: unref(VALUE_TEXT_COLOR),
                      "font-size": String(valueFontSize(it)),
                      "font-weight": "400",
                      "font-family": "Inter, Helvetica, Arial, sans-serif"
                    }, toDisplayString(it.text), 9, _hoisted_25$8)) : createCommentVNode("v-if", true),
                    showNameText(it) ? (openBlock(), createElementBlock("text", {
                      key: 7,
                      x: CX.value,
                      y: nameTextYFor(it),
                      "text-anchor": "middle",
                      "dominant-baseline": "middle",
                      class: "gauge-svg-name",
                      fill: unref(NAME_TEXT_COLOR),
                      "font-size": String(nameFontSize(it)),
                      "font-family": "Inter, Helvetica, Arial, sans-serif"
                    }, toDisplayString(it.name), 9, _hoisted_26$7)) : createCommentVNode("v-if", true)
                  ], 8, _hoisted_9$J)),
                  createCommentVNode(" Grafana RadialSparkline: absolute uPlot under horseshoe "),
                  showSparkline.value && it.spark.length > 1 ? (openBlock(), createElementBlock(
                    "div",
                    {
                      key: 0,
                      class: "gauge-sparkline",
                      "data-testid": "gauge-sparkline",
                      ref_for: true,
                      ref: (el) => setSparkHost(i, el),
                      style: normalizeStyle({
                        top: geom.value.sparkY0 + "px",
                        left: "50%",
                        width: geom.value.sparkWidth + "px",
                        height: geom.value.sparkHeight + "px",
                        marginLeft: -geom.value.sparkWidth / 2 + "px"
                      })
                    },
                    null,
                    4
                    /* STYLE */
                  )) : createCommentVNode("v-if", true)
                ], 8, _hoisted_8$N);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ],
          2
          /* CLASS */
        ))
      ], 8, _hoisted_6$Z));
    };
  }
});
const GaugeRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2T, [["__scopeId", "data-v-7daf99ee"]]);
const _sfc_main$2S = /* @__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(GaugeRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "gauge",
    name: "仪表",
    description: "径向仪表盘",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2S
).useFieldConfig().setPanelOptions((builder) => {
  const cat = ["仪表"];
  builder.addRadio(
    {
      id: "reduceOptions.values",
      path: "reduceOptions.values",
      name: "显示",
      category: ["数值选项"],
      editor: "radio",
      settings: {
        options: [
          { label: "计算", value: false },
          { label: "全部值", value: true }
        ]
      }
    },
    false
  ).addNumber(
    {
      id: "reduceOptions.limit",
      path: "reduceOptions.limit",
      name: "限制",
      category: ["数值选项"],
      editor: "number",
      showIf: (c) => !!c.reduceOptions?.values
    },
    25
  ).addCustom(
    {
      id: "reduceOptions.calcs",
      path: "reduceOptions.calcs",
      name: "计算",
      category: ["数值选项"],
      editor: "stats-picker",
      settings: {
        options: [
          { label: "Last *", value: "lastNotNull" },
          { label: "最后一个", value: "last" },
          { label: "最小值", value: "min" },
          { label: "最大值", value: "max" },
          { label: "平均值", value: "mean" },
          { label: "总和", value: "sum" }
        ]
      },
      showIf: (c) => !c.reduceOptions?.values
    },
    ["lastNotNull"]
  ).addText(
    {
      id: "reduceOptions.fields",
      path: "reduceOptions.fields",
      name: "字段",
      category: ["数值选项"],
      editor: "text"
    },
    ""
  ).addRadio(
    {
      id: "shape",
      path: "shape",
      name: "样式",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "圆形", value: "circle" },
          { label: "弧形", value: "gauge" }
        ]
      }
    },
    "gauge"
  ).addRadio(
    {
      id: "orientation",
      path: "orientation",
      name: "方向",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "水平", value: "horizontal" },
          { label: "垂直", value: "vertical" }
        ]
      }
    },
    "auto"
  ).addRadio(
    {
      id: "sizing",
      path: "sizing",
      name: "仪表尺寸",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "手动", value: "manual" }
        ]
      },
      showIf: (c) => c.orientation && c.orientation !== "auto"
    },
    "auto"
  ).addNumber(
    {
      id: "minVizWidth",
      path: "minVizWidth",
      name: "最小宽度",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 600 },
      showIf: (c) => c.sizing === "manual" && c.orientation === "vertical"
    },
    75
  ).addNumber(
    {
      id: "minVizHeight",
      path: "minVizHeight",
      name: "最小高度",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 600 },
      showIf: (c) => c.sizing === "manual" && c.orientation === "horizontal"
    },
    75
  ).addNumber(
    {
      id: "barWidthFactor",
      path: "barWidthFactor",
      name: "条宽因子",
      category: cat,
      editor: "number",
      settings: { min: 0.1, max: 1, step: 0.01 }
    },
    0.5
  ).addNumber(
    {
      id: "segmentCount",
      path: "segmentCount",
      name: "分段数",
      category: cat,
      editor: "number",
      settings: { min: 1, max: 100, step: 1 }
    },
    1
  ).addNumber(
    {
      id: "segmentSpacing",
      path: "segmentSpacing",
      name: "分段间距",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 1, step: 0.01 },
      showIf: (c) => Number(c.segmentCount) > 1
    },
    0.3
  ).addRadio(
    {
      id: "barShape",
      path: "barShape",
      name: "条形样式",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "扁平", value: "flat" },
          { label: "圆角", value: "rounded" }
        ]
      },
      showIf: (c) => Number(c.segmentCount ?? 1) === 1
    },
    "flat"
  ).addRadio(
    {
      id: "endpointMarker",
      path: "endpointMarker",
      name: "端点标记",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "点", value: "point" },
          { label: "光晕", value: "glow" },
          { label: "无", value: "none" }
        ]
      },
      showIf: (c) => c.barShape === "rounded" && Number(c.segmentCount ?? 1) === 1
    },
    "point"
  ).addSelect(
    {
      id: "textMode",
      path: "textMode",
      name: "文本模式",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "值与名称", value: "value_and_name" },
          { label: "值", value: "value" },
          { label: "名称", value: "name" },
          { label: "无", value: "none" }
        ]
      }
    },
    "auto"
  ).addNumber(
    {
      id: "neutral",
      path: "neutral",
      name: "中性值",
      category: cat,
      editor: "number"
    },
    void 0
  ).addBoolean(
    {
      id: "sparkline",
      path: "sparkline",
      name: "迷你图",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showThresholdMarkers",
      path: "showThresholdMarkers",
      name: "显示阈值标记",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showThresholdLabels",
      path: "showThresholdLabels",
      name: "显示阈值标签",
      category: cat,
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "effects",
      path: "effects",
      name: "特效",
      description: "Grafana EffectsEditor：gradient / barGlow / centerGlow",
      category: cat,
      editor: "text"
    },
    // Live Grafana 13.2 RadialGauge applies defaultGaugePanelEffects.gradient=true (conic-gradient FO).
    { gradient: true, barGlow: false, centerGlow: false }
  ).addBoolean(
    {
      id: "effects.gradient",
      path: "effects.gradient",
      name: "渐变",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "effects.barGlow",
      path: "effects.barGlow",
      name: "条形光晕",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "effects.centerGlow",
      path: "effects.centerGlow",
      name: "中心光晕",
      category: cat,
      editor: "boolean"
    },
    false
  );
  addTextSizeOptions(builder, { withTitle: true, withValue: true });
}).setRuntimeConsumedPaths([
  "reduceOptions.calcs",
  "reduceOptions.fields",
  "reduceOptions.values",
  "reduceOptions.limit",
  "shape",
  "orientation",
  "sizing",
  "minVizWidth",
  "minVizHeight",
  "barWidthFactor",
  "segmentCount",
  "segmentSpacing",
  "barShape",
  "endpointMarker",
  "textMode",
  "neutral",
  "sparkline",
  "showThresholdMarkers",
  "showThresholdLabels",
  "effects",
  "effects",
  "effects.gradient",
  "effects.barGlow",
  "effects.centerGlow"
]).register();
const _sfc_main$2R = /* @__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(GaugeRenderer, {
        mode: "bargauge",
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "bargauge",
    name: "条形仪表",
    description: "水平/垂直条形仪表",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2R
).useFieldConfig().setPanelOptions((builder) => {
  const cat = ["条形仪表"];
  builder.addRadio(
    {
      id: "reduceOptions.values",
      path: "reduceOptions.values",
      name: "显示",
      category: ["数值选项"],
      editor: "radio",
      settings: {
        options: [
          { label: "计算", value: false },
          { label: "全部值", value: true }
        ]
      }
    },
    false
  ).addCustom(
    {
      id: "reduceOptions.calcs",
      path: "reduceOptions.calcs",
      name: "计算",
      category: ["数值选项"],
      editor: "stats-picker",
      settings: {
        options: [
          { label: "Last *", value: "lastNotNull" },
          { label: "最后一个", value: "last" },
          { label: "最小值", value: "min" },
          { label: "最大值", value: "max" },
          { label: "平均值", value: "mean" },
          { label: "总和", value: "sum" }
        ]
      },
      showIf: (c) => !c.reduceOptions?.values
    },
    ["lastNotNull"]
  ).addText(
    {
      id: "reduceOptions.fields",
      path: "reduceOptions.fields",
      name: "字段",
      category: ["数值选项"],
      editor: "text"
    },
    ""
  ).addRadio(
    {
      id: "orientation",
      path: "orientation",
      name: "方向",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "水平", value: "horizontal" },
          { label: "垂直", value: "vertical" }
        ]
      }
    },
    "auto"
  );
  addLegendOptions(builder, true, false);
  builder.addRadio(
    {
      id: "displayMode",
      path: "displayMode",
      name: "显示模式",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "渐变", value: "gradient" },
          { label: "复古 LCD", value: "lcd" },
          { label: "基本", value: "basic" }
        ]
      }
    },
    "gradient"
  ).addRadio(
    {
      id: "valueMode",
      path: "valueMode",
      name: "数值显示",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "值颜色", value: "color" },
          { label: "文本颜色", value: "text" },
          { label: "隐藏", value: "hidden" }
        ]
      }
    },
    "color"
  ).addRadio(
    {
      id: "namePlacement",
      path: "namePlacement",
      name: "名称位置",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "顶部", value: "top" },
          { label: "左侧", value: "left" },
          { label: "隐藏", value: "hidden" }
        ]
      },
      showIf: (c) => c.orientation !== "vertical"
    },
    "auto"
  ).addRadio(
    {
      id: "namePlacementV",
      path: "namePlacement",
      name: "名称位置",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "隐藏", value: "hidden" }
        ]
      },
      showIf: (c) => c.orientation === "vertical"
    },
    "auto"
  ).addBoolean(
    {
      id: "showUnfilled",
      path: "showUnfilled",
      name: "显示未填充区域",
      category: cat,
      editor: "boolean",
      showIf: (c) => c.displayMode !== "lcd"
    },
    true
  ).addRadio(
    {
      id: "sizing",
      path: "sizing",
      name: "条尺寸",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "手动", value: "manual" }
        ]
      }
    },
    "auto"
  ).addNumber(
    {
      id: "minVizWidth",
      path: "minVizWidth",
      name: "最小宽度",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 600 },
      showIf: (c) => c.sizing === "manual" && c.orientation === "vertical"
    },
    8
  ).addNumber(
    {
      id: "minVizHeight",
      path: "minVizHeight",
      name: "最小高度",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 600 },
      showIf: (c) => c.sizing === "manual" && c.orientation !== "vertical"
    },
    16
  ).addNumber(
    {
      id: "maxVizHeight",
      path: "maxVizHeight",
      name: "最大高度",
      category: cat,
      editor: "number",
      settings: { min: 0, max: 600 },
      showIf: (c) => c.sizing === "manual" && c.orientation !== "vertical"
    },
    300
  );
  addTextSizeOptions(builder, { withTitle: true, withValue: true });
}).setRuntimeConsumedPaths([
  "reduceOptions.calcs",
  "reduceOptions.fields",
  "reduceOptions.values",
  "orientation",
  "displayMode",
  "valueMode",
  "namePlacement",
  "showUnfilled",
  "sizing",
  "minVizWidth",
  "minVizHeight",
  "maxVizHeight",
  "legend.showLegend"
]).register();
function migrateTableDisplayModeToCellOptions(displayMode) {
  switch (displayMode) {
    case "basic":
    case "gradient-gauge":
    case "lcd-gauge":
    case "gauge": {
      let gaugeMode = "gradient";
      if (displayMode === "basic") gaugeMode = "basic";
      if (displayMode === "lcd-gauge") gaugeMode = "lcd";
      if (displayMode === "gauge" || displayMode === "gradient-gauge")
        gaugeMode = "gradient";
      return { type: "gauge", mode: gaugeMode };
    }
    case "color-background":
      return { type: "color-background", mode: "gradient" };
    case "color-background-solid":
      return { type: "color-background", mode: "basic" };
    case "color-text":
      return { type: "color-text" };
    case "json-view":
    case "json":
      return { type: "json-view" };
    case "image":
      return { type: "image" };
    case "markdown":
      return { type: "markdown" };
    case "pill":
      return { type: "pill" };
    case "sparkline":
      return { type: "sparkline" };
    case "geo":
      return { type: "geo" };
    case "data-links":
      return { type: "data-links" };
    case "actions":
      return { type: "actions" };
    case "auto":
    default:
      return { type: displayMode || "auto" };
  }
}
function getCellOptions(field, panelCellOptions) {
  const custom = field.config?.custom ?? {};
  if (custom.cellOptions && typeof custom.cellOptions === "object") {
    return custom.cellOptions;
  }
  if (custom.displayMode) {
    return migrateTableDisplayModeToCellOptions(String(custom.displayMode));
  }
  if (panelCellOptions && typeof panelCellOptions === "object") {
    return panelCellOptions;
  }
  if (typeof panelCellOptions === "string" && panelCellOptions) {
    return migrateTableDisplayModeToCellOptions(panelCellOptions);
  }
  return { type: "auto" };
}
function cellTypeFromOptions(opts) {
  return String(opts?.type ?? "auto");
}
const REDUCER_DISPLAY_NAME = {
  sum: "Total",
  mean: "Mean",
  min: "Min",
  max: "Max",
  last: "Last",
  lastNotNull: "Last *",
  first: "First",
  firstNotNull: "First *",
  count: "Count",
  range: "Range",
  delta: "Delta",
  diff: "Difference",
  variance: "Variance",
  stdDev: "StdDev",
  allValues: "All values",
  allIsZero: "All Zeros",
  allIsNull: "All Nulls",
  changeCount: "Change Count",
  distinctCount: "Distinct Count"
};
function reducerDisplayName(id) {
  return REDUCER_DISPLAY_NAME[id] || id;
}
function getFooterItems(fields, options, formatCfg) {
  const panelReducers = Array.isArray(options.reducers) && options.reducers.length ? options.reducers : ["sum"];
  const countRows = options.countRows === true;
  const fieldFilter = options.fields?.length ? new Set(options.fields) : null;
  return fields.map((f, i) => {
    const fieldReducers = f.config?.custom?.footer?.reducers;
    const reducers = fieldReducers?.length ? fieldReducers : panelReducers;
    if (f.type !== "number") {
      if (i === 0 && reducers.length) {
        return reducerDisplayName(reducers[0]);
      }
      return void 0;
    }
    if (fieldFilter && !fieldFilter.has(f.name)) {
      return void 0;
    }
    if (countRows) {
      const r2 = reduceField(f, ["count"]);
      const c = r2.count;
      if (c == null) return void 0;
      return [{ [reducerDisplayName("count")]: String(c) }];
    }
    if (!reducers.length) return void 0;
    const r = reduceField(f, reducers);
    const cfg = formatCfg?.(f) ?? f.config ?? {};
    const items = [];
    for (const name of reducers) {
      const v = r[name];
      if (v == null || typeof v === "number" && Number.isNaN(v)) continue;
      const label = reducerDisplayName(name);
      if (name === "count") {
        items.push({ [label]: String(v) });
      } else {
        items.push({ [label]: formatValue(Number(v), cfg) });
      }
    }
    return items.length ? items : void 0;
  });
}
function shouldShowFooter(options, fields) {
  const show = options?.show === true;
  const anyField = fields.some(
    (f) => Array.isArray(f.config?.custom?.footer?.reducers) && f.config.custom.footer.reducers.length
  );
  return show || anyField;
}
function isNestedFramesField(f) {
  if (!f) return false;
  return String(f.type) === "nestedFrames" || f.name === "__nestedFrames" || f.name === "nested";
}
function findNestedFramesField(fields) {
  return fields.find((f) => isNestedFramesField(f));
}
function displayFieldsExcludingNested(fields) {
  return fields.filter((f) => {
    if (isNestedFramesField(f)) return false;
    const hide = f.config?.custom?.hideFrom;
    if (hide === true || hide?.viz === true) return false;
    return true;
  });
}
function computeTableRowIndices(input) {
  const fields = input.fields ?? [];
  const fieldDisplay = input.fieldDisplay ?? ((f) => f.name);
  let idxs = Array.from({ length: input.length }, (_, i) => i);
  const q = String(input.filterText).trim().toLowerCase();
  if (q) {
    idxs = idxs.filter(
      (i) => fields.some(
        (field) => String(field.values[i] ?? "").toLowerCase().includes(q)
      )
    );
  }
  for (const [name, fq] of Object.entries(input.colFilters ?? {})) {
    const t2 = String(fq).trim().toLowerCase();
    if (!t2) continue;
    const field = fields.find(
      (x) => x.name === name || fieldDisplay(x) === name
    );
    if (!field) continue;
    idxs = idxs.filter(
      (i) => String(field.values[i] ?? "").toLowerCase().includes(t2)
    );
  }
  if (input.sortKey) {
    const field = fields.find((x) => x.name === input.sortKey) || fields.find((x) => fieldDisplay(x) === input.sortKey);
    if (field) {
      const dir = input.sortDir === "desc" ? -1 : 1;
      idxs.sort((a, b) => {
        const av = field.values[a];
        const bv = field.values[b];
        const an = Number(av);
        const bn = Number(bv);
        let cmp = 0;
        if (Number.isFinite(an) && Number.isFinite(bn)) cmp = an - bn;
        else cmp = String(av ?? "").localeCompare(String(bv ?? ""));
        return dir * cmp;
      });
    }
  }
  return idxs;
}
function formatGeoCell(value) {
  if (value == null || value === "") return { label: "" };
  if (typeof value === "object" && value) {
    const o = value;
    if (o.type === "Point" && Array.isArray(o.coordinates)) {
      const [lon, lat] = o.coordinates;
      return {
        label: `${Number(lat).toFixed(5)}, ${Number(lon).toFixed(5)}`,
        lat: Number(lat),
        lon: Number(lon)
      };
    }
    if (o.lat != null && (o.lon != null || o.lng != null)) {
      const lat = Number(o.lat);
      const lon = Number(o.lon ?? o.lng);
      return { label: `${lat.toFixed(5)}, ${lon.toFixed(5)}`, lat, lon };
    }
  }
  const s = String(value).trim();
  const m = s.match(/^\s*(-?\d+(?:\.\d+)?)\s*[,\s]\s*(-?\d+(?:\.\d+)?)\s*$/);
  if (m) {
    const a = Number(m[1]);
    const b = Number(m[2]);
    if (Math.abs(a) <= 90)
      return { label: `${a.toFixed(5)}, ${b.toFixed(5)}`, lat: a, lon: b };
    return { label: `${b.toFixed(5)}, ${a.toFixed(5)}`, lat: b, lon: a };
  }
  return { label: s };
}
function formatJsonCell(value) {
  if (value == null) return "";
  if (typeof value === "string") {
    try {
      return JSON.stringify(JSON.parse(value), null, 2);
    } catch {
      return value;
    }
  }
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}
function typeIcon(field) {
  switch (field.type) {
    case "time":
      return "⏱";
    case "number":
      return "#";
    case "boolean":
      return "☑";
    case "string":
      return "T";
    default:
      return "·";
  }
}
function displayCellValue(field, value, input) {
  const mode2 = input.cellType;
  if (value == null || value === "") return input.noValue;
  if (mode2 === "json-view") return formatJsonCell(value);
  if (mode2 === "pill") return String(value);
  if (mode2 === "geo") return formatGeoCell(value).label || input.noValue;
  if (mode2 === "markdown") return String(value);
  if (mode2 === "data-links" || mode2 === "actions") return "";
  if (input.hideValue) return "•";
  if (mode2 === "image" && typeof value === "string") return "";
  if (mode2 === "sparkline") return "";
  const processor = getDisplayProcessor({
    field: {
      ...field,
      config: { ...field.config, ...input.fieldDefaults ?? {} }
    },
    timeZone: input.timeZone || "browser"
  });
  return formattedValueToString(processor(value));
}
const TABLE_VIRT = {
  CELL_PADDING: 6,
  LINE_HEIGHT: 22,
  MAX_CELL_HEIGHT: 48,
  HEADER_HEIGHT: 34,
  /** Rows above/below viewport (react-window overscanCount default-ish) */
  OVERSCAN: 8,
  /** Grafana TableRT pagination soft limit when pagination is off historically */
  PAGINATION_LIMIT: 750,
  /** Average char width estimate when OffscreenCanvas is unavailable (~12px body) */
  AVG_CHAR_WIDTH: 7,
  LINE_SCALE_FACTOR: 1.17,
  LOW_LINE_PAD: 42,
  SINGLE_LINE_ESTIMATE_THRESHOLD: 18.5
};
function getDefaultRowHeight(cellHeight) {
  switch (String(cellHeight ?? "sm").toLowerCase()) {
    case "md":
      return 42;
    case "lg":
      return TABLE_VIRT.MAX_CELL_HEIGHT;
    case "sm":
    default:
      return 36;
  }
}
const _hoisted_1$21 = ["data-show-header", "data-footer", "data-pagination", "data-freeze", "data-frozen", "data-inspect", "data-style-field", "data-filterable", "data-custom-filterable", "data-column-min-width", "data-sort-by", "data-custom-align", "data-custom-min-width", "data-has-nested", "data-hide-value", "data-show-type-icons", "data-max-row-height", "data-tooltip-field", "data-wrap-text", "data-wrap-header-text", "data-custom-width", "data-cell-options", "data-tooltip-placement", "data-cell-height", "data-virtualized", "data-row-count", "data-row-height", "data-overscan"];
const _hoisted_2$1C = {
  key: 0,
  class: "table-toolbar",
  "data-testid": "table-frame-select"
};
const _hoisted_3$1q = ["value"];
const _hoisted_4$1f = {
  key: 1,
  class: "table-col-filters",
  "data-testid": "table-col-filters"
};
const _hoisted_5$15 = ["placeholder", "value", "onInput"];
const _hoisted_6$Y = {
  class: "table-footer-row",
  "data-testid": "table-footer"
};
const _hoisted_7$V = {
  key: 3,
  class: "table-empty",
  "data-testid": "table-empty"
};
const _hoisted_8$M = {
  key: 4,
  class: "table-inspect",
  "data-testid": "table-inspect"
};
const _sfc_main$2Q = /* @__PURE__ */ defineComponent({
  __name: "TableRenderer.antd",
  props: {
    data: {},
    fieldConfig: {},
    options: {},
    replaceVariables: {},
    width: {},
    height: {},
    nestDepth: { default: 0 }
  },
  setup(__props) {
    const props = __props;
    const sortKey = ref(null);
    const sortDir = ref("asc");
    const frameIndex = ref(0);
    const colFilters = ref({});
    const inspectCell = ref(null);
    const opts = computed(() => props.options ?? {});
    const hideValue = computed(() => !!opts.value.hideValue);
    const maxRowHeight = computed(() => {
      const n = Number(opts.value.maxRowHeight);
      return Number.isFinite(n) && n > 0 ? n : null;
    });
    const tooltipField = computed(
      () => String(opts.value.tooltip?.field ?? opts.value["tooltip.field"] ?? "").trim()
    );
    const tooltipPlacement = computed(() => {
      const p = String(
        opts.value.tooltip?.placement ?? opts.value["tooltip.placement"] ?? "top"
      ).trim();
      return p || "top";
    });
    const showTypeIcons = computed(() => !!opts.value.showTypeIcons);
    function applySortByOption() {
      const sb = opts.value.sortBy;
      if (!Array.isArray(sb) || !sb.length) return;
      const first = sb[0];
      const key = first?.displayName ?? first?.name ?? first?.field ?? null;
      if (key) {
        sortKey.value = String(key);
        sortDir.value = first?.desc || first?.direction === "desc" ? "desc" : "asc";
      }
    }
    watch(
      () => opts.value.sortBy,
      () => applySortByOption(),
      { immediate: true, deep: true }
    );
    const frames = computed(() => props.data?.series ?? []);
    const frame = computed(() => {
      const list = frames.value;
      if (!list.length) return void 0;
      const i = Math.min(Math.max(0, frameIndex.value), list.length - 1);
      return list[i];
    });
    const fields = computed(() => frame.value?.fields ?? []);
    const nestedField = computed(() => findNestedFramesField(fields.value));
    const displayFields = computed(() => displayFieldsExcludingNested(fields.value));
    const noValue = computed(() => {
      const nv = props.fieldConfig?.defaults?.noValue;
      return nv != null && String(nv) !== "" ? String(nv) : "-";
    });
    watch(frames, (f) => {
      if (frameIndex.value >= f.length) frameIndex.value = 0;
    });
    function fieldDisplay(f) {
      return getFieldDisplayName(f, frame.value, frames.value);
    }
    function cellType(f) {
      const panel2 = opts.value.cellOptions;
      const co = getCellOptions(f, panel2);
      if ((!co.type || co.type === "auto") && opts.value.displayMode) {
        return cellTypeFromOptions(
          migrateTableDisplayModeToCellOptions(String(opts.value.displayMode))
        );
      }
      return cellTypeFromOptions(co);
    }
    function isFilterable(f) {
      if (opts.value.filterable === true) return true;
      return f.config?.custom?.filterable === true;
    }
    function cfgFor(f) {
      return { ...props.fieldConfig?.defaults ?? {}, ...f.config ?? {} };
    }
    function formatCell(f, row) {
      const v = f.values?.[row];
      if (v == null || v === "") return noValue.value;
      try {
        return displayCellValue(f, v, {
          noValue: noValue.value,
          cellType: cellType(f),
          fieldDefaults: cfgFor(f),
          hideValue: hideValue.value
        });
      } catch {
        if (hideValue.value) return "•";
        if (f.type === "number") return formatValue(Number(v), cfgFor(f));
        return String(v);
      }
    }
    const rowIndices = computed(() => {
      const f = frame.value;
      if (!f) return [];
      return computeTableRowIndices({
        length: f.length,
        fields: fields.value,
        filterText: "",
        colFilters: colFilters.value,
        sortKey: sortKey.value,
        sortDir: sortDir.value,
        fieldDisplay
      });
    });
    const styleFieldName = computed(() => String(opts.value.styleField ?? "").trim());
    const cellCache = shallowRef(/* @__PURE__ */ new Map());
    function clearCellCache() {
      cellCache.value = /* @__PURE__ */ new Map();
    }
    watch(
      [frame, sortKey, sortDir, colFilters, hideValue, noValue, () => opts.value.cellOptions],
      () => clearCellCache(),
      { deep: true }
    );
    function formatCellCached(f, row) {
      let byRow = cellCache.value.get(f.name);
      if (!byRow) {
        byRow = /* @__PURE__ */ new Map();
        cellCache.value.set(f.name, byRow);
      }
      const hit = byRow.get(row);
      if (hit !== void 0) return hit;
      const text = formatCell(f, row);
      byRow.set(row, text);
      return text;
    }
    function materializeRow(viewIndex) {
      const ri = rowIndices.value[viewIndex] ?? viewIndex;
      const record = {
        key: ri,
        __rowIndex: ri,
        __virtIndex: viewIndex
      };
      for (const f of displayFields.value) {
        record[f.name] = formatCellCached(f, ri);
        record["__raw_" + f.name] = f.values?.[ri];
      }
      if (styleFieldName.value) {
        const sf = displayFields.value.find(
          (f) => f.name === styleFieldName.value || fieldDisplay(f) === styleFieldName.value
        ) || fields.value.find(
          (f) => f.name === styleFieldName.value || fieldDisplay(f) === styleFieldName.value
        );
        if (sf) {
          const raw = sf.values?.[ri];
          const color = getFieldColor(Number(raw), cfgFor(sf));
          if (color) record.__rowBg = color + "33";
        }
      }
      return record;
    }
    const freezeCols = computed(() => {
      const raw = opts.value.frozenColumns?.left ?? opts.value.freezeColumns ?? opts.value.frozenColumns ?? 0;
      return Math.max(0, Number(raw) || 0);
    });
    function isTooltipField(f) {
      const tf = tooltipField.value;
      if (!tf) return false;
      return f.name === tf || fieldDisplay(f) === tf;
    }
    function renderColumnTitle(f) {
      const label = fieldDisplay(f);
      if (!showTypeIcons.value) return label;
      return h("span", { class: "gv-table-col-title" }, [
        h(
          "span",
          { class: "type-icon", title: f.type, "data-testid": "table-type-icon" },
          typeIcon(f)
        ),
        label
      ]);
    }
    function renderCell(f, text, record) {
      const style = {};
      style.overflow = "hidden";
      style.textOverflow = "ellipsis";
      style.whiteSpace = "nowrap";
      if (maxRowHeight.value) {
        style.maxHeight = maxRowHeight.value + "px";
      }
      if (hideValue.value) {
        style.color = "transparent";
      }
      const content = h(
        "span",
        {
          class: "gv-table-cell",
          style,
          title: text == null ? "" : String(text),
          "data-hide-value": hideValue.value ? "true" : "false"
        },
        text == null ? "" : String(text)
      );
      if (!isTooltipField(f)) return content;
      const tip = String(record["__raw_" + f.name] ?? text ?? "");
      return h(
        Tooltip,
        {
          title: tip,
          placement: tooltipPlacement.value
        },
        { default: () => content }
      );
    }
    const columns = computed(
      () => displayFields.value.map((f, fi) => {
        const custom = f.config?.custom ?? {};
        const width2 = Number(custom.width) > 0 ? Number(custom.width) : Math.max(
          Number(custom.minWidth) || Number(opts.value.columnMinWidth) || 80,
          80
        );
        const filterable = isFilterable(f);
        const uniqueVals = filterable ? Array.from(
          new Set(
            (f.values ?? []).slice(0, 200).map((v) => v == null ? "" : String(v)).filter(Boolean)
          )
        ).slice(0, 50) : [];
        return {
          title: () => renderColumnTitle(f),
          dataIndex: f.name,
          key: f.name,
          width: width2,
          ellipsis: true,
          className: maxRowHeight.value ? "gv-table-max-row" : void 0,
          fixed: fi < freezeCols.value ? "left" : void 0,
          sorter: true,
          filters: filterable ? uniqueVals.map((v) => ({ text: v, value: v })) : void 0,
          // Filtering is applied via rowIndices (full set); do not filter the window.
          customRender: ({
            text,
            record
          }) => renderCell(f, text, record)
        };
      })
    );
    const pagination = computed(() => {
      if (!opts.value.enablePagination) return false;
      const ps = Number(opts.value.pageSize) > 0 ? Number(opts.value.pageSize) : 50;
      return { pageSize: ps, size: "small", showSizeChanger: false };
    });
    const showFooter = computed(
      () => shouldShowFooter(opts.value.footer, displayFields.value)
    );
    const footerMap = computed(() => {
      if (!showFooter.value || !frame.value) return null;
      const footerOpts = {
        reducers: opts.value.footer?.reducers ?? ["sum"],
        countRows: opts.value.footer?.countRows,
        fields: opts.value.footer?.fields
      };
      const items = getFooterItems(displayFields.value, footerOpts, (f) => cfgFor(f));
      const map = {};
      displayFields.value.forEach((f, i) => {
        const it = items[i];
        if (it == null) return;
        if (typeof it === "string") {
          map[fieldDisplay(f)] = it;
          return;
        }
        if (Array.isArray(it)) {
          map[fieldDisplay(f)] = it.map((kv) => {
            const k = Object.keys(kv)[0];
            return k ? `${k}: ${kv[k]}` : "";
          }).filter(Boolean).join(", ");
        }
      });
      return Object.keys(map).length ? map : null;
    });
    const cellHeightKey = computed(
      () => String(opts.value.cellHeight ?? "sm")
    );
    const rowHeightPx = computed(() => getDefaultRowHeight(cellHeightKey.value));
    const wrapTextEnabled = computed(() => {
      if (opts.value.wrapText) return true;
      const defaults2 = props.fieldConfig?.defaults?.custom || {};
      if (defaults2.wrapText) return true;
      return (props.data?.series || []).some(
        (fr) => (fr.fields || []).some((f) => f?.config?.custom?.wrapText)
      );
    });
    const wrapHeaderTextEnabled = computed(() => {
      if (opts.value.wrapHeaderText) return true;
      const defaults2 = props.fieldConfig?.defaults?.custom || {};
      if (defaults2.wrapHeaderText) return true;
      return (props.data?.series || []).some(
        (fr) => (fr.fields || []).some((f) => f?.config?.custom?.wrapHeaderText)
      );
    });
    const useVirtual = computed(() => pagination.value === false);
    function rowClassName(record) {
      const base = `table-row-${cellHeightKey.value}`;
      return record?.__rowBg ? `${base} table-row-styled` : base;
    }
    function customRow(record) {
      return {
        onClick: () => onRowClick(record),
        style: record?.__rowBg ? { background: String(record.__rowBg) } : void 0
      };
    }
    function onChange(_pag, filters, sorter) {
      if (filters && typeof filters === "object") {
        const next = { ...colFilters.value };
        for (const [k, vals] of Object.entries(filters)) {
          if (Array.isArray(vals) && vals.length) next[k] = String(vals[0]);
          else if (vals == null) delete next[k];
        }
        colFilters.value = next;
      }
      if (!sorter || Array.isArray(sorter)) return;
      if (sorter.field || sorter.columnKey) {
        sortKey.value = String(sorter.field || sorter.columnKey);
        sortDir.value = sorter.order === "descend" ? "desc" : "asc";
      }
    }
    function onRowClick(record) {
      if (!opts.value.inspect) return;
      const entries = Object.entries(record).filter(
        ([k]) => !k.startsWith("__") && k !== "key"
      );
      const [field, value] = entries[0] ?? ["", ""];
      inspectCell.value = { field: String(field), value: String(value ?? "") };
    }
    const scrollY = computed(() => {
      if (!props.height || props.height < 80) {
        return useVirtual.value ? 320 : void 0;
      }
      return Math.max(80, props.height - 48);
    });
    function scrubSorterAria(root) {
      if (!root) return;
      root.querySelectorAll(
        '.ant-table-column-sorter [role="presentation"][aria-label], .anticon[role="presentation"][aria-label], span[role="presentation"][aria-label]'
      ).forEach((el) => el.removeAttribute("aria-label"));
    }
    const tableRoot = ref(null);
    let _mo = null;
    onMounted(() => {
      scrubSorterAria(tableRoot.value);
      void nextTick(() => scrubSorterAria(tableRoot.value));
      if (tableRoot.value && typeof MutationObserver !== "undefined") {
        _mo = new MutationObserver(() => scrubSorterAria(tableRoot.value));
        _mo.observe(tableRoot.value, {
          subtree: true,
          childList: true,
          attributes: true,
          attributeFilter: ["aria-label", "role"]
        });
      }
    });
    onUpdated(() => scrubSorterAria(tableRoot.value));
    onBeforeUnmount(() => {
      _mo?.disconnect();
      _mo = null;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        ref_key: "tableRoot",
        ref: tableRoot,
        class: normalizeClass(["table-renderer", {
          "gv-table-wrap-header": wrapHeaderTextEnabled.value,
          "gv-table-wrap-text": wrapTextEnabled.value
        }]),
        "data-testid": "panel-table",
        "data-show-header": String(opts.value.showHeader !== false),
        "data-footer": String(!!showFooter.value),
        "data-pagination": String(!!opts.value.enablePagination),
        "data-freeze": String(freezeCols.value),
        "data-frozen": String(freezeCols.value),
        "data-inspect": String(!!opts.value.inspect),
        "data-style-field": String(opts.value.styleField ?? ""),
        "data-filterable": String(!!opts.value.filterable),
        "data-custom-filterable": String(!!__props.fieldConfig?.defaults?.custom?.filterable),
        "data-column-min-width": String(opts.value.columnMinWidth ?? ""),
        "data-sort-by": String(
          Array.isArray(opts.value.sortBy) ? opts.value.sortBy.map((s) => s?.displayName ?? s?.name ?? s).join(",") : opts.value.sortBy ?? ""
        ),
        "data-custom-align": String(__props.fieldConfig?.defaults?.custom?.align ?? ""),
        "data-custom-min-width": String(__props.fieldConfig?.defaults?.custom?.minWidth ?? ""),
        "data-has-nested": String(!!nestedField.value),
        "data-hide-value": String(!!opts.value.hideValue),
        "data-show-type-icons": String(!!opts.value.showTypeIcons),
        "data-max-row-height": String(opts.value.maxRowHeight ?? ""),
        "data-tooltip-field": String(tooltipField.value),
        "data-wrap-text": String(wrapTextEnabled.value),
        "data-wrap-header-text": String(wrapHeaderTextEnabled.value),
        "data-custom-width": String(__props.fieldConfig?.defaults?.custom?.width ?? ""),
        "data-cell-options": String(__props.fieldConfig?.defaults?.custom?.cellOptions ? JSON.stringify(__props.fieldConfig.defaults.custom.cellOptions) : opts.value.cellOptions ? JSON.stringify(opts.value.cellOptions) : ""),
        "data-tooltip-placement": String(tooltipPlacement.value),
        "data-cell-height": String(opts.value.cellHeight ?? "sm"),
        "data-virtualized": String(useVirtual.value),
        "data-row-count": String(rowIndices.value.length),
        "data-row-height": String(rowHeightPx.value),
        "data-variable-heights": false,
        "data-overscan": String(unref(TABLE_VIRT).OVERSCAN),
        style: normalizeStyle({
          width: __props.width ? __props.width + "px" : "100%",
          height: __props.height ? __props.height + "px" : "100%"
        })
      }, [
        frames.value.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_2$1C, [
          createElementVNode("label", null, [
            _cache[1] || (_cache[1] = createTextVNode(
              " 数据帧 ",
              -1
              /* CACHED */
            )),
            withDirectives(createElementVNode(
              "select",
              {
                "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => frameIndex.value = $event)
              },
              [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(frames.value, (fr, i) => {
                    return openBlock(), createElementBlock("option", {
                      key: i,
                      value: i
                    }, toDisplayString(fr.name || fr.refId || `Frame ${i + 1}`), 9, _hoisted_3$1q);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ],
              512
              /* NEED_PATCH */
            ), [
              [
                vModelSelect,
                frameIndex.value,
                void 0,
                { number: true }
              ]
            ])
          ])
        ])) : createCommentVNode("v-if", true),
        displayFields.value.some((f) => isFilterable(f)) ? (openBlock(), createElementBlock("div", _hoisted_4$1f, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(displayFields.value.filter((x) => isFilterable(x)), (f) => {
              return openBlock(), createElementBlock("input", {
                key: f.name,
                class: "table-filter",
                placeholder: fieldDisplay(f),
                "data-testid": "table-col-filter",
                value: colFilters.value[f.name] || "",
                onInput: ($event) => colFilters.value = {
                  ...colFilters.value,
                  [f.name]: $event.target.value
                }
              }, null, 40, _hoisted_5$15);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true),
        displayFields.value.length ? (openBlock(), createBlock(unref(GTable), {
          key: 2,
          "test-id": "table-antd",
          size: "small",
          bordered: "",
          columns: columns.value,
          pagination: pagination.value,
          "show-header": opts.value.showHeader !== false,
          "row-class-name": rowClassName,
          "custom-row": customRow,
          scroll: { x: "max-content", y: scrollY.value },
          virtual: useVirtual.value,
          "row-height": rowHeightPx.value,
          "row-count": rowIndices.value.length,
          "get-row": materializeRow,
          "rows-dep": rowIndices.value,
          onChange
        }, createSlots({
          _: 2
          /* DYNAMIC */
        }, [
          footerMap.value ? {
            name: "footer",
            fn: withCtx(() => [
              createElementVNode("div", _hoisted_6$Y, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(footerMap.value, (val, key) => {
                    return openBlock(), createElementBlock(
                      "span",
                      {
                        key,
                        class: "table-footer-cell",
                        "data-testid": "table-footer-cell"
                      },
                      toDisplayString(key) + ": " + toDisplayString(val),
                      1
                      /* TEXT */
                    );
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])
            ]),
            key: "0"
          } : void 0
        ]), 1032, ["columns", "pagination", "show-header", "scroll", "virtual", "row-height", "row-count", "rows-dep"])) : (openBlock(), createElementBlock("div", _hoisted_7$V, "暂无数据")),
        inspectCell.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_8$M,
          toDisplayString(inspectCell.value.field) + ": " + toDisplayString(inspectCell.value.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ], 14, _hoisted_1$21);
    };
  }
});
const TableRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2Q, [["__scopeId", "data-v-081863d0"]]);
const _sfc_main$2P = /* @__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(TableRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  { id: "table", name: "表格", state: "stable", skipDataQuery: false },
  _sfc_main$2P
).useFieldConfig({
  useCustomConfig: (builder) => {
    const cat = ["单元格选项"];
    builder.addCustom({
      id: "custom.align",
      path: "custom.align",
      name: "对齐",
      category: cat,
      editor: "radio",
      isCustom: true,
      override: true,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "左", value: "left" },
          { label: "中", value: "center" },
          { label: "右", value: "right" }
        ]
      },
      defaultValue: "auto"
    }).addCustom({
      id: "custom.wrapText",
      path: "custom.wrapText",
      name: "自动换行",
      category: cat,
      editor: "boolean",
      isCustom: true,
      override: true,
      defaultValue: false
    }).addCustom({
      id: "custom.wrapHeaderText",
      path: "custom.wrapHeaderText",
      name: "表头换行",
      category: cat,
      editor: "boolean",
      isCustom: true,
      override: true,
      defaultValue: false
    }).addCustom({
      id: "custom.filterable",
      path: "custom.filterable",
      name: "可过滤",
      category: cat,
      editor: "boolean",
      isCustom: true,
      override: true,
      defaultValue: false
    }).addCustom({
      id: "custom.minWidth",
      path: "custom.minWidth",
      name: "最小宽度",
      category: cat,
      editor: "number",
      isCustom: true,
      override: true,
      defaultValue: 150
    }).addCustom({
      id: "custom.width",
      path: "custom.width",
      name: "列宽",
      category: cat,
      editor: "number",
      isCustom: true,
      override: true
    }).addCustom({
      id: "custom.hideFrom.viz",
      path: "custom.hideFrom.viz",
      name: "从可视化隐藏",
      category: cat,
      editor: "boolean",
      isCustom: true,
      override: true,
      defaultValue: false
    }).addCustom({
      id: "custom.cellOptions",
      path: "custom.cellOptions",
      name: "单元格类型",
      category: cat,
      editor: "select",
      isCustom: true,
      override: true,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "彩色文本", value: "color-text" },
          { label: "彩色背景", value: "color-background" },
          { label: "仪表", value: "gauge" },
          { label: "JSON", value: "json-view" }
        ]
      },
      defaultValue: "auto"
    });
  }
}).setPanelOptions((builder) => {
  builder.addBoolean(
    {
      id: "showHeader",
      path: "showHeader",
      name: "显示表头",
      category: ["表格"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "filterable",
      path: "filterable",
      name: "列过滤",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addNumber(
    {
      id: "columnMinWidth",
      path: "columnMinWidth",
      name: "列最小宽度",
      category: ["表格"],
      editor: "number"
    },
    150
  ).addRadio(
    {
      id: "cellHeight",
      path: "cellHeight",
      name: "行高",
      category: ["表格"],
      editor: "radio",
      settings: {
        options: [
          { label: "小", value: "sm" },
          { label: "中", value: "md" },
          { label: "大", value: "lg" }
        ]
      }
    },
    "sm"
  ).addBoolean(
    {
      id: "footer.show",
      path: "footer.show",
      name: "显示页脚",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addSelect(
    {
      id: "footer.reducers",
      path: "footer.reducers",
      name: "页脚计算",
      category: ["表格"],
      editor: "multi-select",
      settings: {
        options: [
          { label: "求和", value: "sum" },
          { label: "平均", value: "mean" },
          { label: "计数", value: "count" },
          { label: "最小", value: "min" },
          { label: "最大", value: "max" }
        ]
      },
      showIf: (c) => !!c.footer?.show
    },
    ["sum"]
  ).addBoolean(
    {
      id: "enablePagination",
      path: "enablePagination",
      name: "启用分页",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addNumber(
    {
      id: "pageSize",
      path: "pageSize",
      name: "每页行数",
      category: ["表格"],
      editor: "number",
      settings: { min: 5, max: 500 },
      showIf: (c) => !!c.enablePagination
    },
    50
  ).addNumber(
    {
      id: "frozenColumns.left",
      path: "frozenColumns.left",
      name: "冻结左侧列",
      category: ["表格"],
      editor: "number",
      settings: { min: 0, max: 20 }
    },
    0
  ).addSelect(
    {
      id: "cellOptions",
      path: "cellOptions",
      name: "单元格类型",
      description: "默认单元格显示类型",
      category: ["表格"],
      editor: "select",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "彩色文本", value: "color-text" },
          { label: "彩色背景", value: "color-background" },
          { label: "彩色背景（纯色）", value: "color-background-solid" },
          { label: "仪表", value: "gauge" },
          { label: "渐变仪表", value: "gradient-gauge" },
          { label: "LCD 仪表", value: "lcd-gauge" },
          { label: "基础条", value: "basic" },
          { label: "迷你图", value: "sparkline" },
          { label: "图片", value: "image" },
          { label: "JSON 视图", value: "json-view" },
          { label: "胶囊", value: "pill" }
        ]
      }
    },
    "auto"
  ).addBoolean(
    {
      id: "hideValue",
      path: "hideValue",
      name: "隐藏值",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "inspect",
      path: "inspect",
      name: "检查单元格值",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "styleField",
      path: "styleField",
      name: "样式字段",
      category: ["表格"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "tooltip.field",
      path: "tooltip.field",
      name: "提示字段",
      category: ["提示"],
      editor: "text"
    },
    ""
  ).addRadio(
    {
      id: "tooltip.placement",
      path: "tooltip.placement",
      name: "提示位置",
      category: ["提示"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "上方", value: "top" },
          { label: "下方", value: "bottom" }
        ]
      }
    },
    "auto"
  ).addBoolean(
    {
      id: "showTypeIcons",
      path: "showTypeIcons",
      name: "显示类型图标",
      category: ["表格"],
      editor: "boolean"
    },
    false
  ).addNumber(
    {
      id: "maxRowHeight",
      path: "maxRowHeight",
      name: "最大行高",
      category: ["表格"],
      editor: "number",
      settings: { min: 0 }
    },
    void 0
  ).addCustom(
    {
      id: "sortBy",
      path: "sortBy",
      name: "默认排序",
      description: "表格初始排序字段（与 Grafana JSON sortBy 兼容）",
      category: ["表格"],
      editor: "custom"
    },
    []
  );
}).setRuntimeConsumedPaths([
  "showHeader",
  "filterable",
  "columnMinWidth",
  "cellHeight",
  "footer.show",
  "footer.reducers",
  "enablePagination",
  "pageSize",
  "frozenColumns.left",
  "cellOptions",
  "hideValue",
  "inspect",
  "styleField",
  "tooltip.field",
  "tooltip.placement",
  "showTypeIcons",
  "maxRowHeight",
  "sortBy",
  "custom.align",
  "custom.wrapText",
  "custom.wrapHeaderText",
  "custom.filterable",
  "custom.minWidth",
  "custom.width",
  "custom.hideFrom.viz",
  "custom.cellOptions"
]).register();
const _hoisted_1$20 = {
  class: "panel-data-error",
  "data-testid": "panel-data-error"
};
const _hoisted_2$1B = { class: "panel-data-error__msg" };
const _sfc_main$2O = /* @__PURE__ */ defineComponent({
  __name: "PanelDataErrorView",
  props: {
    data: {},
    fieldConfig: {},
    needsStringField: { type: Boolean, default: false },
    needsTimeField: { type: Boolean, default: false },
    needsNumberField: { type: Boolean, default: false },
    message: {}
  },
  setup(__props) {
    const props = __props;
    const text = computed(() => {
      if (props.message) return props.message;
      const noValue = props.fieldConfig?.defaults?.noValue;
      if (typeof noValue === "string" && noValue) return noValue;
      const series = props.data?.series ?? [];
      const hasAnyValues = series.some(
        (f) => (f.length ?? f.fields?.[0]?.values?.length ?? 0) > 0
      );
      if (!series.length || !hasAnyValues) return "无数据";
      const fields = series.flatMap((f) => f.fields ?? []);
      const hasString = fields.some((f) => f.type === "string");
      const hasTime = fields.some((f) => f.type === "time");
      const hasNumber = fields.some((f) => f.type === "number");
      if (props.needsStringField && !hasString) return "数据缺少一个字符串字段";
      if (props.needsTimeField && !hasTime) return "数据缺少一个时间字段";
      if (props.needsNumberField && !hasNumber) return "数据缺少一个数字字段";
      return "无法可视化数据";
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$20, [
        createElementVNode(
          "div",
          _hoisted_2$1B,
          toDisplayString(text.value),
          1
          /* TEXT */
        )
      ]);
    };
  }
});
const PanelDataErrorView = /* @__PURE__ */ _export_sfc(_sfc_main$2O, [["__scopeId", "data-v-d4b74297"]]);
function computeVirtualWindow(total, scrollTop, viewportHeight, rowHeight, overscan = 8) {
  const rh = Math.max(1, rowHeight);
  const totalHeight = total * rh;
  if (total <= 0) {
    return { start: 0, end: 0, offsetY: 0, totalHeight, visibleCount: 0 };
  }
  const effectiveViewport = viewportHeight > 0 ? viewportHeight : Math.min(total, 40) * rh;
  const first = Math.max(0, Math.floor(scrollTop / rh) - overscan);
  const visible = Math.ceil(effectiveViewport / rh) + overscan * 2;
  const end = Math.min(total, first + visible);
  return {
    start: first,
    end,
    offsetY: first * rh,
    totalHeight,
    visibleCount: end - first
  };
}
function sliceVirtualRows(rows, win) {
  return rows.slice(win.start, win.end);
}
const SEV_COLORS = {
  critical: "var(--grafana-error)",
  fatal: "var(--grafana-error)",
  error: "var(--grafana-error)",
  warn: "var(--grafana-warning)",
  warning: "var(--grafana-warning)",
  info: "var(--grafana-primary)",
  debug: "var(--grafana-text-secondary)",
  trace: "var(--grafana-secondary-main, var(--grafana-primary))",
  unknown: "var(--grafana-text-secondary)"
};
function normalizeLevel(raw) {
  const s = String(raw ?? "").toLowerCase().trim();
  if (!s) return "unknown";
  if (s === "critical" || s === "fatal") return s === "fatal" ? "fatal" : "critical";
  if (s === "error" || s === "err") return "error";
  if (s === "warn" || s === "warning") return "warning";
  if (s === "info" || s === "information") return "info";
  if (s === "debug") return "debug";
  if (s === "trace") return "trace";
  return s;
}
function detectLevelFromMessage(msg) {
  const m = String(msg ?? "").toLowerCase();
  if (m.includes("critical") || m.includes("fatal")) return "critical";
  if (m.includes("error") || /\berr\b/.test(m)) return "error";
  if (m.includes("warn")) return "warning";
  if (m.includes("trace")) return "trace";
  if (m.includes("debug")) return "debug";
  if (m.includes("info")) return "info";
  return "unknown";
}
function severityColor(level) {
  return SEV_COLORS[normalizeLevel(level)] ?? SEV_COLORS.unknown;
}
function severityBadgeStyle(level) {
  const c = severityColor(level);
  return {
    color: c,
    backgroundColor: `color-mix(in srgb, ${c} 14%, transparent)`,
    border: `1px solid color-mix(in srgb, ${c} 35%, transparent)`
  };
}
function formatLogTimestamp(ms, resolution = "ms") {
  if (!Number.isFinite(ms)) return "";
  let epoch = ms;
  if (resolution === "ns") epoch = ms / 1e6;
  else if (resolution === "us" || resolution === "µs") epoch = ms / 1e3;
  else if (resolution === "s") epoch = ms * 1e3;
  if (epoch > 1e17) epoch = epoch / 1e6;
  else if (epoch > 1e14) epoch = epoch / 1e3;
  const d = new Date(epoch);
  if (Number.isNaN(d.getTime())) return "";
  return d.toISOString().replace("T", " ").replace("Z", "").slice(0, 23);
}
function formatLabelValue(val) {
  if (val == null) return "";
  if (typeof val === "string" || typeof val === "number" || typeof val === "boolean")
    return String(val);
  if (Array.isArray(val)) return val.map(formatLabelValue).join(",");
  try {
    return JSON.stringify(val);
  } catch {
    return String(val);
  }
}
function aggregateLogFields(log) {
  const attributes = {};
  const resources = {};
  for (const key of Object.keys(log)) {
    const val = log[key];
    if (!val || typeof val !== "object" || Array.isArray(val)) continue;
    if (key.startsWith("attributes_") || key === "attributesString" || key === "attributeMap" || key === "attributes") {
      Object.entries(val).forEach(([k, v]) => {
        attributes[k] = formatLabelValue(v);
      });
    } else if (key.startsWith("resources_") || key === "resourcesString" || key === "resourceMap" || key === "resources") {
      Object.entries(val).forEach(([k, v]) => {
        resources[k] = formatLabelValue(v);
      });
    }
  }
  return { attributes, resources };
}
function extractService(labels, extras) {
  if (extras) {
    for (const k of [
      "service.name",
      "service",
      "serviceName",
      "job",
      "app"
    ]) {
      if (extras[k] != null && String(extras[k]).trim())
        return String(extras[k]);
    }
  }
  const blob = String(labels ?? "");
  for (const key of ["service.name", "service", "job", "app"]) {
    const re = new RegExp(
      `(?:^|,)\\s*${key.replace(".", "\\.")}\\s*=\\s*([^,]+)`,
      "i"
    );
    const m = blob.match(re);
    if (m?.[1]) return m[1].trim();
  }
  return "";
}
function extractTraceId(labels, extras) {
  if (extras) {
    for (const k of ["trace_id", "traceId", "traceID", "trace.id"]) {
      if (extras[k] != null && String(extras[k]).trim())
        return String(extras[k]);
    }
  }
  const blob = String(labels ?? "");
  const m = blob.match(
    /(?:^|,)\s*(?:trace_id|traceId|traceID|trace\.id)\s*=\s*([^,]+)/i
  );
  return m?.[1]?.trim() ?? "";
}
function labelsFromField(field, i) {
  if (!field) return "";
  const v = field.values?.[i];
  if (v && typeof v === "object" && !Array.isArray(v)) {
    return Object.entries(v).map(([k, val]) => `${k}=${formatLabelValue(val)}`).join(", ");
  }
  return formatLabelValue(v);
}
function parseLogRowsFromFrame(frame, options = {}) {
  if (!frame?.fields?.length) return [];
  const time = frame.fields.find((f) => f.type === "time");
  const line = frame.fields.find(
    (f) => /line|message|msg|body|Log/i.test(String(f.name || "")) && f.type === "string"
  ) ?? frame.fields.find((f) => f.type === "string");
  if (!line) return [];
  const labelField = frame.fields.find((f) => /label/i.test(String(f.name || ""))) ?? frame.fields.find(
    (f) => f.labels && Object.keys(f.labels).length
  );
  const levelField = frame.fields.find(
    (f) => /level|severity|severity_text/i.test(String(f.name || ""))
  );
  const serviceField = frame.fields.find(
    (f) => /service(\.name)?$|job|app/i.test(String(f.name || ""))
  );
  const traceField = frame.fields.find(
    (f) => /trace[_]?id|trace\.id/i.test(String(f.name || ""))
  );
  const res = String(options.timestampResolution ?? "ms");
  const total = frame.length ?? line.values?.length ?? 0;
  const max = options.maxRows != null && options.maxRows > 0 ? Math.min(total, options.maxRows) : total;
  const dedup = String(options.dedupStrategy ?? "none");
  const ascending = String(options.sortOrder) === "Ascending";
  const fieldList = frame.fields;
  const simpleFastPath = !options.prettifyLogMessage && dedup === "none" && !labelField && fieldList.length <= 4;
  const buildRow = (i) => {
    const raw = String(line?.values?.[i] ?? "");
    let msg = raw;
    if (options.prettifyLogMessage) {
      try {
        msg = JSON.stringify(JSON.parse(raw), null, 2);
      } catch {
      }
    }
    if (simpleFastPath) {
      const levelFromField2 = levelField ? normalizeLevel(String(levelField.values?.[i] ?? "")) : "";
      const level2 = levelFromField2 && levelFromField2 !== "unknown" ? levelFromField2 : detectLevelFromMessage(msg);
      let service2 = serviceField ? String(serviceField.values?.[i] ?? "") : "";
      if (!service2) {
        const m = /\bservice=([^\s]+)/i.exec(msg);
        if (m) service2 = m[1];
      }
      const serviceFromMsg = service2;
      const traceId2 = traceField ? String(traceField.values?.[i] ?? "") : "";
      const ts2 = time ? Number(time.values?.[i]) : i;
      return {
        id: `${ts2}-${i}`,
        index: i,
        timestamp: ts2,
        t: formatLogTimestamp(ts2, res),
        severityText: (level2 || "INFO").toUpperCase(),
        level: level2,
        body: raw,
        msg,
        raw,
        service: serviceFromMsg,
        traceId: traceId2,
        labels: "",
        attributes: {},
        resources: serviceFromMsg ? { "service.name": serviceFromMsg } : {},
        fields: {}
      };
    }
    const labels = labelsFromField(labelField, i) || (line?.labels ? Object.entries(line.labels).map(([k, v]) => `${k}=${formatLabelValue(v)}`).join(", ") : "");
    const levelFromField = levelField ? normalizeLevel(String(levelField.values?.[i] ?? "")) : "";
    const level = levelFromField && levelFromField !== "unknown" ? levelFromField : detectLevelFromMessage(msg);
    const labelObj = labelField?.values?.[i] && typeof labelField.values[i] === "object" && !Array.isArray(labelField.values[i]) ? labelField.values[i] : line?.labels;
    const service = (serviceField ? String(serviceField.values?.[i] ?? "") : "") || extractService(labels, labelObj);
    const traceId = (traceField ? String(traceField.values?.[i] ?? "") : "") || extractTraceId(labels, labelObj);
    const fields = {};
    for (const f of fieldList) {
      const name = String(f.name || "");
      if (!name) continue;
      const v = f.values?.[i];
      if (v != null && typeof v === "object" && !Array.isArray(v)) {
        Object.entries(v).forEach(([k, val]) => {
          fields[k] = formatLabelValue(val);
        });
      } else {
        fields[name] = formatLabelValue(v);
      }
    }
    const bag = {
      ...fields,
      attributes: labelObj && typeof labelObj === "object" ? labelObj : {},
      resources: service ? { "service.name": service } : {},
      body: raw,
      severityText: level,
      traceId
    };
    const { attributes, resources } = aggregateLogFields(bag);
    if (service && !resources["service.name"]) {
      resources["service.name"] = service;
    }
    const ts = time ? Number(time.values?.[i]) : i;
    return {
      id: `${ts}-${i}`,
      index: i,
      timestamp: ts,
      t: formatLogTimestamp(ts, res),
      severityText: (level || "INFO").toUpperCase(),
      level,
      body: raw,
      msg,
      raw,
      service,
      traceId,
      labels,
      attributes,
      resources,
      fields
    };
  };
  let result = new Array(max);
  if (ascending) {
    for (let i = 0; i < max; i++) result[i] = buildRow(i);
  } else {
    for (let out = 0; out < max; out++) {
      result[out] = buildRow(max - 1 - out);
    }
  }
  if (dedup === "exact") {
    const seen = /* @__PURE__ */ new Set();
    result = result.filter((r) => {
      if (seen.has(r.raw)) return false;
      seen.add(r.raw);
      return true;
    });
  } else if (dedup === "numbers") {
    const seen = /* @__PURE__ */ new Set();
    result = result.filter((r) => {
      const k = r.msg.replace(/\d+/g, "#");
      if (seen.has(k)) return false;
      seen.add(k);
      return true;
    });
  } else if (dedup === "signature") {
    const seen = /* @__PURE__ */ new Set();
    result = result.filter((r) => {
      const k = r.msg.replace(/[0-9a-f]{8,}/gi, "#").replace(/\d+/g, "#");
      if (seen.has(k)) return false;
      seen.add(k);
      return true;
    });
  }
  return result;
}
function getRowAttr(row, key) {
  if (row.resources[key]) return row.resources[key];
  if (row.attributes[key]) return row.attributes[key];
  if (row.fields[key]) return row.fields[key];
  if (key === "service.name") return row.service;
  if (key === "traceId" || key === "trace_id") return row.traceId;
  if (key === "body" || key === "Line" || key === "line") return row.body;
  return "";
}
function rowToDetailObject(row) {
  return {
    timestamp: row.timestamp,
    id: row.id,
    traceId: row.traceId,
    severityText: row.severityText,
    body: row.body,
    attributes: row.attributes,
    resources: {
      ...row.resources,
      ...row.service ? { "service.name": row.service } : {}
    },
    fields: row.fields
  };
}
const EMPTY_ATTRS = Object.freeze({});
const EMPTY_FIELDS = Object.freeze({});
function fastLevelFromMessage(msg) {
  const sp = msg.indexOf(" ");
  const head = (sp < 0 ? msg : msg.slice(0, sp)).toLowerCase();
  if (head === "info" || head === "error" || head === "warn" || head === "warning" || head === "debug" || head === "trace" || head === "critical" || head === "fatal") {
    return head === "warn" ? "warning" : head;
  }
  return detectLevelFromMessage(msg);
}
function createLazyLogSource(frames, options = {}) {
  const dedup = String(options.dedupStrategy ?? "none");
  const list = frames ?? [];
  const complexFrame = list.some((frame) => {
    const fields = frame?.fields ?? [];
    if (fields.length > 4) return true;
    return fields.some((f) => /label/i.test(String(f.name || "")));
  });
  const needsEager = options.prettifyLogMessage || dedup !== "none" || options.maxRows != null || complexFrame;
  if (needsEager) {
    const all = parseLogRowsFromFrames(frames, options);
    return {
      length: all.length,
      getRow: (i) => all[i],
      materializeAll: () => all
    };
  }
  const segs = [];
  let offset = 0;
  for (const frame of frames ?? []) {
    if (!frame?.fields?.length) continue;
    const time = frame.fields.find((f) => f.type === "time");
    const line = frame.fields.find(
      (f) => /line|message|msg|body|Log/i.test(String(f.name || "")) && f.type === "string"
    ) ?? frame.fields.find((f) => f.type === "string");
    if (!line) continue;
    const length = frame.length ?? line.values?.length ?? 0;
    if (!length) continue;
    segs.push({
      frame,
      time,
      line,
      levelField: frame.fields.find(
        (f) => /level|severity|severity_text/i.test(String(f.name || ""))
      ),
      serviceField: frame.fields.find(
        (f) => /service(\.name)?$|job|app/i.test(String(f.name || ""))
      ),
      traceField: frame.fields.find(
        (f) => /trace[_]?id|trace\.id/i.test(String(f.name || ""))
      ),
      offset,
      length
    });
    offset += length;
  }
  const total = offset;
  const ascending = String(options.sortOrder) === "Ascending";
  const res = String(options.timestampResolution ?? "ms");
  const cache = /* @__PURE__ */ new Map();
  function sourceIndex(displayIndex) {
    if (displayIndex < 0 || displayIndex >= total) return -1;
    return ascending ? displayIndex : total - 1 - displayIndex;
  }
  function locate(src) {
    for (const seg of segs) {
      if (src >= seg.offset && src < seg.offset + seg.length) {
        return { seg, i: src - seg.offset };
      }
    }
    return null;
  }
  function buildAt(src) {
    const hit = locate(src);
    if (!hit) {
      return {
        id: `missing-${src}`,
        index: src,
        timestamp: src,
        t: "",
        severityText: "INFO",
        level: "unknown",
        body: "",
        msg: "",
        raw: "",
        service: "",
        traceId: "",
        labels: "",
        attributes: EMPTY_ATTRS,
        resources: EMPTY_ATTRS,
        fields: EMPTY_FIELDS
      };
    }
    const { seg, i } = hit;
    const raw = String(seg.line?.values?.[i] ?? "");
    const levelFromField = seg.levelField ? normalizeLevel(String(seg.levelField.values?.[i] ?? "")) : "";
    const level = levelFromField && levelFromField !== "unknown" ? levelFromField : fastLevelFromMessage(raw);
    let service = seg.serviceField ? String(seg.serviceField.values?.[i] ?? "") : "";
    if (!service) {
      const m = /\bservice=([^\s]+)/i.exec(raw);
      if (m) service = m[1];
    }
    const traceId = seg.traceField ? String(seg.traceField.values?.[i] ?? "") : "";
    const ts = seg.time ? Number(seg.time.values?.[i]) : i;
    return {
      id: `${ts}-${src}`,
      index: src,
      timestamp: ts,
      t: formatLogTimestamp(ts, res),
      severityText: (level || "INFO").toUpperCase(),
      level,
      body: raw,
      msg: raw,
      raw,
      service,
      traceId,
      labels: "",
      attributes: EMPTY_ATTRS,
      resources: service ? { "service.name": service } : EMPTY_ATTRS,
      fields: EMPTY_FIELDS
    };
  }
  function getRow(displayIndex) {
    const cached = cache.get(displayIndex);
    if (cached) return cached;
    const src = sourceIndex(displayIndex);
    const row = buildAt(src);
    if (cache.size > 512) {
      const first = cache.keys().next().value;
      if (first != null) cache.delete(first);
    }
    cache.set(displayIndex, row);
    return row;
  }
  function materializeAll() {
    const out = new Array(total);
    for (let i = 0; i < total; i++) out[i] = getRow(i);
    return out;
  }
  return { length: total, getRow, materializeAll };
}
function parseLogRowsFromFrames(frames, options = {}) {
  const list = frames ?? [];
  const out = [];
  let indexBase = 0;
  for (const frame of list) {
    const rows = parseLogRowsFromFrame(frame, {
      ...options,
      // explicit only — never silent cap across frames
      maxRows: options.maxRows
    });
    for (const r of rows) {
      out.push({ ...r, index: indexBase + r.index, id: `${r.id}` });
    }
    indexBase += rows.length;
  }
  return out;
}
const _hoisted_1$1$ = ["data-level", "data-open", "data-testid", "onClick"];
const _hoisted_2$1A = { class: "le-entry" };
const _hoisted_3$1p = { class: "le-entry-head" };
const _hoisted_4$1e = {
  key: 0,
  class: "le-entry-ts timestamp field"
};
const _hoisted_5$14 = ["title"];
const _hoisted_6$X = ["title"];
const _hoisted_7$U = {
  key: 3,
  class: "labels field le-entry-labels",
  "data-testid": "log-attributes"
};
const _hoisted_8$L = { class: "le-entry-actions" };
const _hoisted_9$I = ["onClick"];
const _hoisted_10$C = ["innerHTML"];
const _hoisted_11$w = { class: "le-detail-ts" };
const _hoisted_12$q = { class: "le-detail-body" };
const _hoisted_13$p = { class: "fieldsTable" };
const _hoisted_14$n = { class: "fieldsKey" };
const _hoisted_15$i = { class: "fieldsVal" };
const _hoisted_16$h = {
  key: 0,
  class: "log-detail-sidebar",
  "data-testid": "log-detail",
  "data-details-mode": "sidebar"
};
const _hoisted_17$g = {
  key: 0,
  class: "sidebar-inner"
};
const _hoisted_18$g = { class: "fieldsTable" };
const _hoisted_19$f = { class: "fieldsKey" };
const _hoisted_20$e = { class: "fieldsVal" };
const _sfc_main$2N = /* @__PURE__ */ defineComponent({
  __name: "LogsListRenderer",
  props: {
    rows: {},
    rowCount: {},
    getRow: { type: Function },
    options: {},
    openId: {},
    wrap: { type: Boolean },
    extraColumns: {},
    highlightMsg: { type: Function },
    detailEntries: { type: Function },
    rowHeight: {}
  },
  emits: ["toggle", "copy"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const opts = computed(() => props.options ?? {});
    const viewportEl = ref(null);
    const scrollTop = ref(0);
    const viewportHeight = ref(400);
    const ROW_H2 = computed(() => Math.max(22, Number(props.rowHeight ?? 28)));
    const totalRows = computed(
      () => props.getRow ? Number(props.rowCount ?? 0) : props.rows?.length ?? 0
    );
    const win = computed(
      () => computeVirtualWindow(
        totalRows.value,
        scrollTop.value,
        viewportHeight.value,
        ROW_H2.value,
        12
      )
    );
    const visibleRows = computed(() => {
      if (props.getRow) {
        const out = [];
        for (let i = win.value.start; i < win.value.end; i++) {
          out.push(props.getRow(i));
        }
        return out;
      }
      return sliceVirtualRows(props.rows ?? [], win.value);
    });
    const openRow = computed(() => {
      if (!props.openId) return null;
      if (props.getRow) {
        for (let i = 0; i < totalRows.value; i++) {
          const r = props.getRow(i);
          if (r.id === props.openId) return r;
        }
        return null;
      }
      return props.rows?.find((r) => r.id === props.openId) ?? null;
    });
    function onScroll() {
      const el = viewportEl.value;
      if (!el) return;
      scrollTop.value = el.scrollTop;
      viewportHeight.value = el.clientHeight;
    }
    let ro = null;
    onMounted(() => {
      onScroll();
      if (typeof ResizeObserver !== "undefined" && viewportEl.value) {
        ro = new ResizeObserver(() => onScroll());
        ro.observe(viewportEl.value);
      }
    });
    onBeforeUnmount(() => {
      ro?.disconnect();
    });
    watch(
      () => totalRows.value,
      () => {
        onScroll();
      }
    );
    function scrollToIndex(index2) {
      const el = viewportEl.value;
      if (!el) return;
      const i = Math.max(0, Math.min(totalRows.value - 1, Math.floor(index2)));
      const top = i * ROW_H2.value;
      el.scrollTo({ top });
      scrollTop.value = top;
      viewportHeight.value = el.clientHeight || viewportHeight.value;
    }
    __expose({
      scrollToTop() {
        viewportEl.value?.scrollTo({ top: 0 });
      },
      scrollToBottom() {
        const el = viewportEl.value;
        if (el) el.scrollTo({ top: el.scrollHeight });
      },
      scrollToIndex,
      getViewport() {
        return viewportEl.value;
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          ref_key: "viewportEl",
          ref: viewportEl,
          class: "logs-list-viewport le-list-wrap",
          "data-testid": "logs-list-viewport",
          role: "list",
          onScrollPassive: onScroll
        },
        [
          createElementVNode(
            "div",
            {
              class: "logs-list-spacer",
              style: normalizeStyle({ height: win.value.totalHeight + "px", position: "relative" })
            },
            [
              createElementVNode(
                "div",
                {
                  class: "logs-list-window",
                  style: normalizeStyle({
                    transform: `translateY(${win.value.offsetY}px)`,
                    position: "absolute",
                    left: 0,
                    right: 0,
                    top: 0
                  })
                },
                [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(visibleRows.value, (r) => {
                      return openBlock(), createElementBlock("div", {
                        key: r.id,
                        class: normalizeClass(["logLine le-list-entry", {
                          clickable: opts.value.enableLogDetails !== false,
                          detailsDisplayed: __props.openId === r.id,
                          small: opts.value.fontSize === "small" || opts.value.fontSize === "sm",
                          "is-active": __props.openId === r.id
                        }]),
                        role: "listitem",
                        "data-level": r.level,
                        "data-open": __props.openId === r.id,
                        "data-testid": `log-row-${r.id}`,
                        style: normalizeStyle({ minHeight: ROW_H2.value + "px" }),
                        onClick: ($event) => emit("toggle", r)
                      }, [
                        createElementVNode(
                          "div",
                          {
                            class: "le-sev-bar",
                            style: normalizeStyle({ background: unref(severityColor)(r.level) })
                          },
                          null,
                          4
                          /* STYLE */
                        ),
                        createElementVNode("div", _hoisted_2$1A, [
                          createElementVNode("div", _hoisted_3$1p, [
                            !!opts.value.showTime ? (openBlock(), createElementBlock(
                              "span",
                              _hoisted_4$1e,
                              toDisplayString(r.t),
                              1
                              /* TEXT */
                            )) : createCommentVNode("v-if", true),
                            opts.value.showLevel !== false ? (openBlock(), createElementBlock("span", {
                              key: 1,
                              class: normalizeClass(["le-entry-lvl level field", "level-" + r.level]),
                              style: normalizeStyle(unref(severityBadgeStyle)(r.level)),
                              title: r.level
                            }, toDisplayString(r.severityText || "INFO"), 15, _hoisted_5$14)) : createCommentVNode("v-if", true),
                            r.service ? (openBlock(), createElementBlock("span", {
                              key: 2,
                              class: "le-entry-svc",
                              title: r.service
                            }, toDisplayString(r.service), 9, _hoisted_6$X)) : createCommentVNode("v-if", true),
                            (openBlock(true), createElementBlock(
                              Fragment,
                              null,
                              renderList(__props.extraColumns || [], (col2) => {
                                return openBlock(), createElementBlock(
                                  "span",
                                  {
                                    key: col2,
                                    class: "le-entry-extra"
                                  },
                                  toDisplayString(unref(getRowAttr)(r, col2) || "—"),
                                  1
                                  /* TEXT */
                                );
                              }),
                              128
                              /* KEYED_FRAGMENT */
                            )),
                            (opts.value.showLabels || opts.value.showLogAttributes !== false) && r.labels && !r.service ? (openBlock(), createElementBlock(
                              "span",
                              _hoisted_7$U,
                              toDisplayString(r.labels),
                              1
                              /* TEXT */
                            )) : createCommentVNode("v-if", true),
                            createElementVNode("div", _hoisted_8$L, [
                              opts.value.showCopyLogLink ? (openBlock(), createElementBlock("button", {
                                key: 0,
                                type: "button",
                                class: "le-entry-btn",
                                "data-testid": "logs-copy",
                                title: "复制",
                                onClick: withModifiers(($event) => emit("copy", r), ["stop"])
                              }, " 复制 ", 8, _hoisted_9$I)) : createCommentVNode("v-if", true)
                            ])
                          ]),
                          createElementVNode(
                            "div",
                            {
                              class: normalizeClass(["le-entry-body fieldsWrapper", __props.wrap ? "wrappedLogLine" : "unwrappedLogLine"])
                            },
                            [
                              createElementVNode("span", {
                                class: normalizeClass(["field log-line-body", {
                                  "log-syntax-highlight": opts.value.syntaxHighlighting !== false,
                                  "le-body-clamp": !__props.wrap
                                }]),
                                innerHTML: __props.highlightMsg(r.msg)
                              }, null, 10, _hoisted_10$C)
                            ],
                            2
                            /* CLASS */
                          ),
                          opts.value.enableLogDetails !== false && __props.openId === r.id && (opts.value.detailsMode || "inline") === "inline" ? (openBlock(), createElementBlock("div", {
                            key: 0,
                            class: "logDetails le-detail-inline",
                            "data-testid": "log-detail",
                            onClick: _cache[0] || (_cache[0] = withModifiers(() => {
                            }, ["stop"]))
                          }, [
                            createElementVNode(
                              "div",
                              {
                                class: "le-detail-strip",
                                style: normalizeStyle({ borderLeftColor: unref(severityColor)(r.level) })
                              },
                              [
                                createElementVNode(
                                  "span",
                                  _hoisted_11$w,
                                  toDisplayString(r.t),
                                  1
                                  /* TEXT */
                                ),
                                createElementVNode(
                                  "pre",
                                  _hoisted_12$q,
                                  toDisplayString(r.msg),
                                  1
                                  /* TEXT */
                                )
                              ],
                              4
                              /* STYLE */
                            ),
                            createElementVNode("div", _hoisted_13$p, [
                              (openBlock(true), createElementBlock(
                                Fragment,
                                null,
                                renderList(__props.detailEntries(r), (e, di) => {
                                  return openBlock(), createElementBlock("div", {
                                    key: di,
                                    class: "fieldsRow"
                                  }, [
                                    createElementVNode(
                                      "div",
                                      _hoisted_14$n,
                                      toDisplayString(e.key),
                                      1
                                      /* TEXT */
                                    ),
                                    createElementVNode(
                                      "div",
                                      _hoisted_15$i,
                                      toDisplayString(e.value),
                                      1
                                      /* TEXT */
                                    )
                                  ]);
                                }),
                                128
                                /* KEYED_FRAGMENT */
                              ))
                            ])
                          ])) : createCommentVNode("v-if", true)
                        ])
                      ], 14, _hoisted_1$1$);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ],
                4
                /* STYLE */
              )
            ],
            4
            /* STYLE */
          ),
          createCommentVNode(" sidebar detail portal target "),
          opts.value.enableLogDetails !== false && __props.openId && opts.value.detailsMode === "sidebar" ? (openBlock(), createElementBlock("aside", _hoisted_16$h, [
            openRow.value ? (openBlock(), createElementBlock("div", _hoisted_17$g, [
              createElementVNode("div", _hoisted_18$g, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(__props.detailEntries(openRow.value), (e, di) => {
                    return openBlock(), createElementBlock("div", {
                      key: di,
                      class: "fieldsRow"
                    }, [
                      createElementVNode(
                        "div",
                        _hoisted_19$f,
                        toDisplayString(e.key),
                        1
                        /* TEXT */
                      ),
                      createElementVNode(
                        "div",
                        _hoisted_20$e,
                        toDisplayString(e.value),
                        1
                        /* TEXT */
                      )
                    ]);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])
            ])) : createCommentVNode("v-if", true)
          ])) : createCommentVNode("v-if", true)
        ],
        544
        /* NEED_HYDRATION, NEED_PATCH */
      );
    };
  }
});
const LogsListRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2N, [["__scopeId", "data-v-daa02fc3"]]);
const _hoisted_1$1_ = ["data-testid"];
const _sfc_main$2M = /* @__PURE__ */ defineComponent({
  __name: "LogsRawRenderer",
  props: {
    rows: {},
    rowCount: {},
    getRow: { type: Function },
    options: {},
    rowHeight: {}
  },
  setup(__props) {
    const props = __props;
    const viewportEl = ref(null);
    const scrollTop = ref(0);
    const viewportHeight = ref(400);
    const ROW_H2 = computed(() => Math.max(18, Number(props.rowHeight ?? 20)));
    const totalRows = computed(
      () => props.getRow ? Number(props.rowCount ?? 0) : props.rows?.length ?? 0
    );
    const win = computed(
      () => computeVirtualWindow(
        totalRows.value,
        scrollTop.value,
        viewportHeight.value,
        ROW_H2.value,
        16
      )
    );
    const visibleRows = computed(() => {
      if (props.getRow) {
        const out = [];
        for (let i = win.value.start; i < win.value.end; i++) out.push(props.getRow(i));
        return out;
      }
      return sliceVirtualRows(props.rows ?? [], win.value);
    });
    function onScroll() {
      const el = viewportEl.value;
      if (!el) return;
      scrollTop.value = el.scrollTop;
      viewportHeight.value = el.clientHeight;
    }
    let ro = null;
    onMounted(() => {
      onScroll();
      if (typeof ResizeObserver !== "undefined" && viewportEl.value) {
        ro = new ResizeObserver(() => onScroll());
        ro.observe(viewportEl.value);
      }
    });
    onBeforeUnmount(() => ro?.disconnect());
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          ref_key: "viewportEl",
          ref: viewportEl,
          class: "logs-raw-viewport",
          "data-testid": "logs-raw-viewport",
          "data-log-format": "raw",
          onScrollPassive: onScroll
        },
        [
          createElementVNode(
            "div",
            {
              class: "spacer",
              style: normalizeStyle({ height: win.value.totalHeight + "px" })
            },
            [
              createElementVNode(
                "div",
                {
                  class: "window",
                  style: normalizeStyle({ transform: `translateY(${win.value.offsetY}px)` })
                },
                [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(visibleRows.value, (r) => {
                      return openBlock(), createElementBlock("pre", {
                        key: r.id,
                        class: "raw-line",
                        "data-testid": `log-row-${r.id}`,
                        style: normalizeStyle({ minHeight: ROW_H2.value + "px" })
                      }, toDisplayString(r.raw || r.msg), 13, _hoisted_1$1_);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ],
                4
                /* STYLE */
              )
            ],
            4
            /* STYLE */
          )
        ],
        544
        /* NEED_HYDRATION, NEED_PATCH */
      );
    };
  }
});
const LogsRawRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2M, [["__scopeId", "data-v-c76462c2"]]);
const _hoisted_1$1Z = ["data-frames", "data-log-format", "data-dedup", "data-wrap", "data-sort", "data-show-controls", "data-show-time", "data-show-labels", "data-show-common", "data-prettify", "data-details", "data-details-mode", "data-infinite-scroll", "data-show-level", "data-syntax-highlighting", "data-allow-download", "data-show-field-selector", "data-show-log-attributes", "data-copy-link", "data-font-size", "data-timestamp-resolution", "data-unwrapped-columns"];
const _hoisted_2$1z = { class: "le-actions-bar" };
const _hoisted_3$1o = { class: "le-ab-label" };
const _hoisted_4$1d = {
  key: 0,
  class: "navContainer",
  "data-testid": "logs-controls"
};
const _hoisted_5$13 = { class: "level-wrap" };
const _hoisted_6$W = {
  key: 0,
  class: "level-menu"
};
const _hoisted_7$T = ["onClick"];
const _hoisted_8$K = { class: "meta" };
const _hoisted_9$H = { class: "main" };
const _hoisted_10$B = {
  key: 0,
  class: "commonLabels",
  "data-testid": "logs-common-labels"
};
const _hoisted_11$v = {
  key: 1,
  class: "frameBar"
};
const _hoisted_12$p = ["value"];
const _hoisted_13$o = {
  key: 2,
  class: "searchBar"
};
const _hoisted_14$m = {
  key: 3,
  class: "labelVolume",
  "data-testid": "logs-label-volume"
};
const _hoisted_15$h = ["onClick"];
const _hoisted_16$g = { class: "vol-label" };
const _hoisted_17$f = { class: "vol-count" };
const _hoisted_18$f = {
  key: 7,
  class: "le-footer"
};
const _sfc_main$2L = /* @__PURE__ */ defineComponent({
  __name: "LogsRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    replaceVariables: { type: Function },
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const openId = ref(null);
    const search = ref("");
    const searchVisible = ref(false);
    const levelFilter = ref("all");
    const labelFilter = ref("");
    const frameIndex = ref(0);
    const levelMenuOpen = ref(false);
    const rowsEl = ref(null);
    const wrapLocal = ref(null);
    const extraColumnsLocal = ref(null);
    const opts = computed(() => props.options ?? {});
    const frames = computed(() => props.data?.series ?? []);
    const extraColumns = computed(() => {
      if (extraColumnsLocal.value) return extraColumnsLocal.value;
      const raw = opts.value.extraColumns ?? opts.value.unwrappedColumns;
      if (Array.isArray(raw)) return raw.map(String).filter(Boolean);
      if (typeof raw === "string" && raw.trim()) {
        return raw.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
      }
      return [];
    });
    const parseOpts = computed(() => ({
      timestampResolution: String(opts.value.timestampResolution ?? "ms"),
      prettifyLogMessage: !!opts.value.prettifyLogMessage,
      enableInfiniteScrolling: !!opts.value.enableInfiniteScrolling,
      dedupStrategy: String(opts.value.dedupStrategy ?? "none"),
      sortOrder: String(opts.value.sortOrder ?? "Descending")
    }));
    const hasActiveFilters = computed(
      () => levelFilter.value !== "all" || Boolean(labelFilter.value) || Boolean(search.value.trim())
    );
    const needsFullMaterialize = computed(
      () => hasActiveFilters.value || !!opts.value.showCommonLabels || !!opts.value.showLabels || String(opts.value.dedupStrategy ?? "none") !== "none" || !!opts.value.prettifyLogMessage
    );
    const lazySource = computed(
      () => createLazyLogSource(frames.value, parseOpts.value)
    );
    const allRows = computed(() => {
      const list = frames.value;
      if (!list.length) return [];
      if (!needsFullMaterialize.value) {
        return [];
      }
      return parseLogRowsFromFrames(list, parseOpts.value);
    });
    const rowCount = computed(() => {
      if (!frames.value.length) return 0;
      if (!needsFullMaterialize.value) return lazySource.value.length;
      return allRows.value.length;
    });
    const getLazyRow = (index2) => lazySource.value.getRow(index2);
    const commonLabels = computed(() => {
      if (!opts.value.showCommonLabels) return "";
      const all = needsFullMaterialize.value ? allRows.value : lazySource.value.materializeAll();
      if (!all.length) return "";
      const sets = all.map((r) => {
        const m = /* @__PURE__ */ new Map();
        String(r.labels || "").split(",").map((s) => s.trim()).filter(Boolean).forEach((pair) => {
          const [k, ...rest] = pair.split("=");
          if (k) m.set(k.trim(), rest.join("=").trim());
        });
        return m;
      });
      const first = sets[0];
      const shared2 = [];
      for (const [k, v] of first) {
        if (sets.every((s) => s.get(k) === v)) shared2.push(`${k}=${v}`);
      }
      return shared2.join(", ");
    });
    const labelVolumes = computed(() => {
      if (!opts.value.showLabels) return [];
      const map = /* @__PURE__ */ new Map();
      const all = needsFullMaterialize.value ? allRows.value : lazySource.value.materializeAll();
      for (const r of all) {
        const parts = r.labels ? r.labels.split(/[,;\s]+/).filter(Boolean) : [r.level];
        for (const p of parts) map.set(p, (map.get(p) ?? 0) + 1);
      }
      return [...map.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20).map(([label, count]) => ({ label, count }));
    });
    const rows = computed(() => {
      if (!needsFullMaterialize.value) return [];
      let list = allRows.value;
      if (levelFilter.value !== "all") {
        const lf = levelFilter.value === "warn" ? "warning" : levelFilter.value;
        list = list.filter(
          (r) => r.level === lf || lf === "warning" && r.level === "warn"
        );
      }
      if (labelFilter.value) {
        const lf = labelFilter.value.toLowerCase();
        list = list.filter(
          (r) => r.labels.toLowerCase().includes(lf) || r.level.toLowerCase() === lf || r.msg.toLowerCase().includes(lf)
        );
      }
      const q = search.value.trim().toLowerCase();
      if (q) {
        list = list.filter(
          (r) => r.msg.toLowerCase().includes(q) || r.labels.toLowerCase().includes(q) || r.level.includes(q) || r.service.toLowerCase().includes(q)
        );
      }
      return list;
    });
    const useLazyRows = computed(
      () => !needsFullMaterialize.value && lazySource.value.length > 0
    );
    const showControls = computed(() => opts.value.showControls === true);
    const wrapOn = computed(() => !!opts.value.wrapLogMessage);
    const wrapEffective = computed(
      () => wrapLocal.value === null ? wrapOn.value : wrapLocal.value
    );
    const levels = ["all", "critical", "error", "warning", "info", "debug", "trace"];
    function toggleRow(row) {
      if (opts.value.enableLogDetails === false) return;
      openId.value = openId.value === row.id ? null : row.id;
    }
    function copyLink(r) {
      try {
        void navigator.clipboard?.writeText(`${r.t} ${r.level} ${r.raw}`);
      } catch {
      }
    }
    function download() {
      if (!opts.value.allowDownload) return;
      const list = useLazyRows.value ? lazySource.value.materializeAll() : rows.value;
      const text = list.map((r) => `${r.t}	${r.level}	${r.labels}	${r.raw}`).join("\n");
      const blob = new Blob([text], { type: "text/plain;charset=utf-8" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "logs.txt";
      a.click();
      URL.revokeObjectURL(url);
    }
    function scrollTop() {
      rowsEl.value?.scrollTo({ top: 0 });
    }
    function scrollBottom() {
      const el = rowsEl.value;
      if (el) el.scrollTo({ top: el.scrollHeight });
    }
    function toggleSearch() {
      searchVisible.value = !searchVisible.value;
      if (searchVisible.value) {
        nextTick(() => {
          document.querySelector(
            '[data-testid="logs-search"]'
          )?.focus();
        });
      } else {
        search.value = "";
      }
    }
    function setLevel(lv) {
      levelFilter.value = lv;
      levelMenuOpen.value = false;
    }
    function escapeHtml(s) {
      return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
    }
    function highlightMsg(msg) {
      const q = search.value.trim();
      if (!q || opts.value.syntaxHighlighting === false) return escapeHtml(msg);
      const esc = escapeHtml(msg);
      const re = new RegExp(
        `(${q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
        "gi"
      );
      return esc.replace(re, '<mark class="log-search-match">$1</mark>');
    }
    function detailEntries(r) {
      const entries = [
        { key: "Time", value: r.t || "—" },
        { key: "level", value: r.level }
      ];
      if (r.service) entries.push({ key: "service.name", value: r.service });
      if (r.traceId) entries.push({ key: "traceId", value: r.traceId });
      if (r.labels) {
        for (const part of r.labels.split(",").map((s) => s.trim()).filter(Boolean)) {
          const eq = part.indexOf("=");
          if (eq > 0)
            entries.push({ key: part.slice(0, eq), value: part.slice(eq + 1) });
          else entries.push({ key: "label", value: part });
        }
      }
      for (const col2 of extraColumns.value) {
        const v = getRowAttr(r, col2);
        if (v) entries.push({ key: col2, value: v });
      }
      entries.push({ key: "Line", value: r.msg });
      return entries;
    }
    watch(showControls, (v) => {
      if (v) searchVisible.value = true;
    });
    if (showControls.value) searchVisible.value = true;
    function onKeydownEscape(ev) {
      if (ev.key !== "Escape") return;
      if (openId.value != null) {
        openId.value = null;
        ev.stopPropagation();
      }
    }
    onMounted(() => window.addEventListener("keydown", onKeydownEscape));
    onBeforeUnmount(() => window.removeEventListener("keydown", onKeydownEscape));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "logs",
        "data-testid": "panel-logs",
        "data-frames": String(frames.value.length),
        "data-log-format": String(opts.value.logFormat || "list"),
        "data-dedup": String(opts.value.dedupStrategy ?? "none"),
        "data-wrap": String(!!wrapEffective.value),
        "data-sort": String(opts.value.sortOrder ?? "Descending"),
        "data-show-controls": String(!!showControls.value),
        "data-show-time": String(!!opts.value.showTime),
        "data-show-labels": String(!!opts.value.showLabels),
        "data-show-common": String(!!opts.value.showCommonLabels),
        "data-prettify": String(!!opts.value.prettifyLogMessage),
        "data-details": String(opts.value.enableLogDetails !== false),
        "data-details-mode": String(opts.value.detailsMode ?? "inline"),
        "data-infinite-scroll": String(!!opts.value.enableInfiniteScrolling),
        "data-show-level": String(opts.value.showLevel !== false),
        "data-syntax-highlighting": String(opts.value.syntaxHighlighting !== false),
        "data-allow-download": String(!!opts.value.allowDownload),
        "data-show-field-selector": String(!!opts.value.showFieldSelector),
        "data-show-log-attributes": String(opts.value.showLogAttributes !== false),
        "data-copy-link": String(!!opts.value.showCopyLogLink),
        "data-font-size": String(opts.value.fontSize ?? "default"),
        "data-timestamp-resolution": String(opts.value.timestampResolution ?? "ms"),
        "data-unwrapped-columns": String(opts.value.unwrappedColumns ?? "")
      }, [
        createElementVNode("div", _hoisted_2$1z, [
          createElementVNode(
            "span",
            _hoisted_3$1o,
            toDisplayString(rows.value.length) + " 条日志",
            1
            /* TEXT */
          )
        ]),
        createElementVNode(
          "div",
          {
            class: normalizeClass(["le-shell", { "with-controls": showControls.value }])
          },
          [
            showControls.value ? (openBlock(), createElementBlock("div", _hoisted_4$1d, [
              createElementVNode(
                "button",
                {
                  type: "button",
                  class: normalizeClass(["ctrl", { active: wrapEffective.value }]),
                  title: "换行",
                  onClick: _cache[0] || (_cache[0] = ($event) => wrapLocal.value = !wrapEffective.value)
                },
                " ↵ ",
                2
                /* CLASS */
              ),
              createElementVNode("button", {
                type: "button",
                class: "ctrl",
                title: "搜索",
                onClick: toggleSearch
              }, " ⌕ "),
              createElementVNode("div", _hoisted_5$13, [
                createElementVNode("button", {
                  type: "button",
                  class: "ctrl",
                  title: "级别",
                  "data-testid": "logs-level-filter",
                  onClick: _cache[1] || (_cache[1] = ($event) => levelMenuOpen.value = !levelMenuOpen.value)
                }, " ≡ "),
                levelMenuOpen.value ? (openBlock(), createElementBlock("div", _hoisted_6$W, [
                  (openBlock(), createElementBlock(
                    Fragment,
                    null,
                    renderList(levels, (lv) => {
                      return createElementVNode("button", {
                        key: lv,
                        type: "button",
                        class: normalizeClass({ active: levelFilter.value === lv }),
                        onClick: ($event) => setLevel(lv)
                      }, toDisplayString(lv), 11, _hoisted_7$T);
                    }),
                    64
                    /* STABLE_FRAGMENT */
                  ))
                ])) : createCommentVNode("v-if", true)
              ]),
              opts.value.allowDownload ? (openBlock(), createElementBlock("button", {
                key: 0,
                type: "button",
                class: "ctrl",
                title: "下载",
                "data-testid": "logs-download",
                onClick: download
              }, " ↓ ")) : createCommentVNode("v-if", true),
              createElementVNode("button", {
                type: "button",
                class: "ctrl",
                title: "顶部",
                "data-testid": "scrollToTop",
                onClick: scrollTop
              }, " ↑ "),
              createElementVNode("button", {
                type: "button",
                class: "ctrl",
                title: "底部",
                onClick: scrollBottom
              }, " ↓ "),
              createElementVNode(
                "span",
                _hoisted_8$K,
                toDisplayString(rows.value.length),
                1
                /* TEXT */
              )
            ])) : createCommentVNode("v-if", true),
            createElementVNode("div", _hoisted_9$H, [
              opts.value.showCommonLabels && commonLabels.value ? (openBlock(), createElementBlock(
                "div",
                _hoisted_10$B,
                toDisplayString(commonLabels.value),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true),
              frames.value.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_11$v, [
                withDirectives(createElementVNode(
                  "select",
                  {
                    "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => frameIndex.value = $event),
                    "data-testid": "logs-frame-select"
                  },
                  [
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(frames.value, (_, i) => {
                        return openBlock(), createElementBlock("option", {
                          key: i,
                          value: i
                        }, " 序列 " + toDisplayString(i + 1), 9, _hoisted_12$p);
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ],
                  512
                  /* NEED_PATCH */
                ), [
                  [
                    vModelSelect,
                    frameIndex.value,
                    void 0,
                    { number: true }
                  ]
                ])
              ])) : createCommentVNode("v-if", true),
              showControls.value || searchVisible.value ? (openBlock(), createElementBlock("div", _hoisted_13$o, [
                withDirectives(createElementVNode(
                  "input",
                  {
                    "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => search.value = $event),
                    type: "search",
                    placeholder: "搜索日志…",
                    "data-testid": "logs-search"
                  },
                  null,
                  512
                  /* NEED_PATCH */
                ), [
                  [vModelText, search.value]
                ])
              ])) : createCommentVNode("v-if", true),
              opts.value.showLabels && labelVolumes.value.length ? (openBlock(), createElementBlock("aside", _hoisted_14$m, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(labelVolumes.value, (v) => {
                    return openBlock(), createElementBlock("div", {
                      key: v.label,
                      class: "vol",
                      onClick: ($event) => labelFilter.value = labelFilter.value === v.label ? "" : v.label
                    }, [
                      createElementVNode(
                        "span",
                        _hoisted_16$g,
                        toDisplayString(v.label),
                        1
                        /* TEXT */
                      ),
                      createElementVNode(
                        "span",
                        _hoisted_17$f,
                        toDisplayString(v.count),
                        1
                        /* TEXT */
                      )
                    ], 8, _hoisted_15$h);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])) : createCommentVNode("v-if", true),
              createCommentVNode(" LIST / RAW (virtualized) "),
              rowCount.value && String(opts.value.logFormat || "list") === "raw" ? (openBlock(), createBlock(LogsRawRenderer, {
                key: 4,
                rows: useLazyRows.value ? void 0 : rows.value,
                "row-count": useLazyRows.value ? rowCount.value : void 0,
                "get-row": useLazyRows.value ? getLazyRow : void 0,
                options: opts.value
              }, null, 8, ["rows", "row-count", "get-row", "options"])) : rowCount.value ? (openBlock(), createBlock(LogsListRenderer, {
                key: 5,
                ref: "listRef",
                rows: useLazyRows.value ? void 0 : rows.value,
                "row-count": useLazyRows.value ? rowCount.value : void 0,
                "get-row": useLazyRows.value ? getLazyRow : void 0,
                options: opts.value,
                "open-id": openId.value,
                wrap: wrapEffective.value,
                "extra-columns": extraColumns.value,
                "highlight-msg": highlightMsg,
                "detail-entries": detailEntries,
                onToggle: toggleRow,
                onCopy: copyLink
              }, null, 8, ["rows", "row-count", "get-row", "options", "open-id", "wrap", "extra-columns"])) : (openBlock(), createBlock(PanelDataErrorView, {
                key: 6,
                data: __props.data,
                "needs-string-field": true,
                "needs-time-field": true
              }, null, 8, ["data"])),
              rowCount.value && opts.value.enableInfiniteScrolling ? (openBlock(), createElementBlock(
                "div",
                _hoisted_18$f,
                " 已加载 " + toDisplayString(rowCount.value) + " 条 ",
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true)
            ])
          ],
          2
          /* CLASS */
        )
      ], 8, _hoisted_1$1Z);
    };
  }
});
const LogsRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2L, [["__scopeId", "data-v-05fdf8b1"]]);
const _sfc_main$2K = /* @__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(LogsRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  { id: "logs", name: "日志", state: "stable", skipDataQuery: false },
  _sfc_main$2K
).setPanelOptions((builder) => {
  const cat = ["日志"];
  builder.addBoolean(
    {
      id: "showTime",
      path: "showTime",
      name: "时间",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showLabels",
      path: "showLabels",
      name: "唯一标签",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showCommonLabels",
      path: "showCommonLabels",
      name: "公共标签",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "wrapLogMessage",
      path: "wrapLogMessage",
      name: "自动换行",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "prettifyLogMessage",
      path: "prettifyLogMessage",
      name: "美化 JSON",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "enableLogDetails",
      path: "enableLogDetails",
      name: "启用日志详情",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "enableInfiniteScrolling",
      path: "enableInfiniteScrolling",
      name: "无限滚动",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showControls",
      path: "showControls",
      name: "显示控件",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showLevel",
      path: "showLevel",
      name: "显示日志级别",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "syntaxHighlighting",
      path: "syntaxHighlighting",
      name: "语法高亮",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "enableLogDetails",
      path: "enableLogDetails",
      name: "日志详情",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "allowDownload",
      path: "allowDownload",
      name: "允许下载",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showFieldSelector",
      path: "showFieldSelector",
      name: "显示字段选择器",
      category: cat,
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showLogAttributes",
      path: "showLogAttributes",
      name: "显示日志属性",
      category: cat,
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showCopyLogLink",
      path: "showCopyLogLink",
      name: "显示复制链接",
      category: cat,
      editor: "boolean"
    },
    false
  ).addSelect(
    {
      id: "sortOrder",
      path: "sortOrder",
      name: "顺序",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "最新在前", value: "Descending" },
          { label: "最旧在前", value: "Ascending" }
        ]
      }
    },
    "Descending"
  ).addSelect(
    {
      id: "dedupStrategy",
      path: "dedupStrategy",
      name: "去重",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "精确", value: "exact" },
          { label: "数字", value: "numbers" },
          { label: "签名", value: "signature" }
        ]
      }
    },
    "none"
  ).addRadio(
    {
      id: "detailsMode",
      path: "detailsMode",
      name: "详情模式",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "内联", value: "inline" },
          { label: "侧栏", value: "sidebar" }
        ]
      }
    },
    "inline"
  ).addSelect(
    {
      id: "fontSize",
      path: "fontSize",
      name: "字号",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "默认", value: "default" },
          { label: "小", value: "small" }
        ]
      }
    },
    "default"
  ).addSelect(
    {
      id: "timestampResolution",
      path: "timestampResolution",
      name: "时间戳精度",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "ms", value: "ms" },
          { label: "µs", value: "us" },
          { label: "ns", value: "ns" }
        ]
      }
    },
    "ms"
  ).addBoolean(
    {
      id: "unwrappedColumns",
      path: "unwrappedColumns",
      name: "展开列",
      category: cat,
      editor: "boolean"
    },
    false
  ).addRadio(
    {
      id: "logFormat",
      path: "logFormat",
      name: "日志格式",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "原始", value: "raw" },
          { label: "列表", value: "list" },
          { label: "列", value: "table" }
        ]
      }
    },
    "list"
  ).addNumber(
    {
      id: "rawMaxLines",
      path: "rawMaxLines",
      name: "原始最大行数",
      category: cat,
      editor: "number",
      showIf: (c) => c.logFormat === "raw"
    },
    1
  ).addText(
    {
      id: "extraColumns",
      path: "extraColumns",
      name: "额外列",
      category: cat,
      editor: "text",
      showIf: (c) => c.logFormat !== "raw"
    },
    ""
  );
}).setRuntimeConsumedPaths([
  "showTime",
  "showLabels",
  "showCommonLabels",
  "wrapLogMessage",
  "prettifyLogMessage",
  "enableLogDetails",
  "enableInfiniteScrolling",
  "showControls",
  "showLevel",
  "syntaxHighlighting",
  "allowDownload",
  "showFieldSelector",
  "showLogAttributes",
  "showCopyLogLink",
  "sortOrder",
  "dedupStrategy",
  "detailsMode",
  "fontSize",
  "timestampResolution",
  "unwrappedColumns",
  "extraColumns"
]).register();
const _hoisted_1$1Y = { class: "ld-content" };
const _hoisted_2$1y = { class: "ld-header" };
const _hoisted_3$1n = { class: "ld-header-left" };
const _hoisted_4$1c = { class: "ld-header-actions" };
const _hoisted_5$12 = { class: "ld-body-ts" };
const _hoisted_6$V = ["title"];
const _hoisted_7$S = { class: "ld-tabs" };
const _hoisted_8$J = ["onClick"];
const _hoisted_9$G = { class: "ld-scroll" };
const _hoisted_10$A = {
  key: 0,
  class: "lov-root"
};
const _hoisted_11$u = { class: "lov-key" };
const _hoisted_12$o = { class: "lov-val" };
const _hoisted_13$n = {
  key: 1,
  class: "ljc-root"
};
const _hoisted_14$l = ["innerHTML"];
const _hoisted_15$g = {
  key: 2,
  class: "ld-stub"
};
const _hoisted_16$f = { class: "lov-row" };
const _hoisted_17$e = { class: "lov-val" };
const _hoisted_18$e = { class: "lov-row" };
const _hoisted_19$e = { class: "lov-val" };
const _hoisted_20$d = {
  key: 3,
  class: "ld-stub"
};
const _sfc_main$2J = /* @__PURE__ */ defineComponent({
  __name: "ArgusLogDetail",
  props: {
    open: { type: Boolean },
    row: {},
    initialTab: {}
  },
  emits: ["close"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const activeTab = ref(props.initialTab ?? "overview");
    watch(
      () => props.open,
      (v) => {
        if (v) activeTab.value = props.initialTab ?? "overview";
      }
    );
    watch(
      () => props.initialTab,
      (t2) => {
        if (t2) activeTab.value = t2;
      }
    );
    const tabs = [
      { key: "overview", label: "概览" },
      { key: "json", label: "JSON" },
      { key: "context", label: "上下文" },
      { key: "metrics", label: "指标" }
    ];
    const sev = computed(
      () => props.row ? severityColor(props.row.level) : severityColor("unknown")
    );
    const bodyPreview = computed(() => props.row?.msg || props.row?.body || "");
    const tsText = computed(() => {
      if (!props.row) return "";
      return props.row.t || formatLogTimestamp(props.row.timestamp);
    });
    const overviewFields = computed(() => {
      const row = props.row;
      if (!row) return [];
      const fields = [
        { key: "timestamp", value: tsText.value || "—" },
        { key: "severity", value: row.severityText || row.level },
        { key: "service.name", value: row.service || "—" },
        { key: "traceId", value: row.traceId || "—" },
        { key: "body", value: row.body || "—" }
      ];
      for (const [k, v] of Object.entries(row.resources)) {
        if (!fields.some((f) => f.key === k)) fields.push({ key: k, value: v });
      }
      for (const [k, v] of Object.entries(row.attributes)) {
        if (!fields.some((f) => f.key === k)) fields.push({ key: k, value: v });
      }
      for (const [k, v] of Object.entries(row.fields)) {
        if (/time|line|message|body|level|severity/i.test(k) || fields.some((f) => f.key === k))
          continue;
        fields.push({ key: k, value: v });
      }
      return fields;
    });
    const jsonText = computed(() => {
      if (!props.row) return "";
      try {
        return JSON.stringify(rowToDetailObject(props.row), null, 2);
      } catch {
        return props.row.raw;
      }
    });
    function esc(s) {
      return s.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
    }
    const highlightedJson = computed(
      () => esc(jsonText.value).replaceAll(
        /("(\\u[\dA-Fa-f]{4}|\\[^u]|[^"\\])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[Ee][+-]?\d+)?)/g,
        (m) => {
          if (m.startsWith('"')) {
            if (m.endsWith(":")) return `<span class="t-key">${m}</span>`;
            return `<span class="t-str">${m}</span>`;
          }
          if (/true|false/.test(m)) return `<span class="t-bool">${m}</span>`;
          if (/null/.test(m)) return `<span class="t-null">${m}</span>`;
          return `<span class="t-num">${m}</span>`;
        }
      )
    );
    async function copyContent() {
      try {
        const text = activeTab.value === "json" ? jsonText.value : bodyPreview.value;
        await navigator.clipboard?.writeText(text);
      } catch {
      }
    }
    return (_ctx, _cache) => {
      return openBlock(), createBlock(Transition, { name: "le-panel" }, {
        default: withCtx(() => [
          __props.open && __props.row ? (openBlock(), createElementBlock("aside", {
            key: 0,
            class: "le-detail-panel",
            "data-testid": "log-details",
            onClick: _cache[1] || (_cache[1] = withModifiers(() => {
            }, ["stop"]))
          }, [
            createElementVNode("div", _hoisted_1$1Y, [
              createElementVNode("div", _hoisted_2$1y, [
                createElementVNode("div", _hoisted_3$1n, [
                  createElementVNode(
                    "div",
                    {
                      class: "ld-sev-bar",
                      style: normalizeStyle({ background: sev.value })
                    },
                    null,
                    4
                    /* STYLE */
                  ),
                  _cache[2] || (_cache[2] = createElementVNode(
                    "span",
                    { class: "ld-title" },
                    "日志详情",
                    -1
                    /* CACHED */
                  ))
                ]),
                createElementVNode("div", _hoisted_4$1c, [
                  createElementVNode("button", {
                    type: "button",
                    class: "ld-icon-btn",
                    title: "复制",
                    "data-testid": "logs-copy",
                    onClick: copyContent
                  }, " 复制 "),
                  createElementVNode("button", {
                    type: "button",
                    class: "ld-icon-btn",
                    title: "关闭",
                    onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
                  }, " ✕ ")
                ])
              ]),
              createElementVNode(
                "div",
                {
                  class: "ld-body-strip",
                  style: normalizeStyle({ borderLeftColor: sev.value })
                },
                [
                  createElementVNode(
                    "span",
                    _hoisted_5$12,
                    toDisplayString(tsText.value),
                    1
                    /* TEXT */
                  ),
                  createElementVNode("pre", {
                    class: "ld-body-text",
                    title: bodyPreview.value
                  }, toDisplayString(bodyPreview.value), 9, _hoisted_6$V)
                ],
                4
                /* STYLE */
              ),
              createElementVNode("div", _hoisted_7$S, [
                (openBlock(), createElementBlock(
                  Fragment,
                  null,
                  renderList(tabs, (tab) => {
                    return createElementVNode("button", {
                      key: tab.key,
                      type: "button",
                      class: normalizeClass(["ld-tab", { "ld-tab--active": activeTab.value === tab.key }]),
                      onClick: ($event) => activeTab.value = tab.key
                    }, toDisplayString(tab.label), 11, _hoisted_8$J);
                  }),
                  64
                  /* STABLE_FRAGMENT */
                ))
              ]),
              createElementVNode("div", _hoisted_9$G, [
                activeTab.value === "overview" ? (openBlock(), createElementBlock("div", _hoisted_10$A, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(overviewFields.value, (f) => {
                      return openBlock(), createElementBlock("div", {
                        key: f.key,
                        class: "lov-row"
                      }, [
                        createElementVNode(
                          "div",
                          _hoisted_11$u,
                          toDisplayString(f.key),
                          1
                          /* TEXT */
                        ),
                        createElementVNode(
                          "div",
                          _hoisted_12$o,
                          toDisplayString(f.value),
                          1
                          /* TEXT */
                        )
                      ]);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ])) : activeTab.value === "json" ? (openBlock(), createElementBlock("div", _hoisted_13$n, [
                  createElementVNode("div", { class: "ljc-toolbar" }, [
                    _cache[3] || (_cache[3] = createElementVNode(
                      "span",
                      { class: "ljc-lang" },
                      "JSON",
                      -1
                      /* CACHED */
                    )),
                    createElementVNode("button", {
                      type: "button",
                      class: "ljc-copy-btn",
                      onClick: copyContent
                    }, " 复制 ")
                  ]),
                  createCommentVNode(" eslint-disable-next-line vue/no-v-html "),
                  createElementVNode("pre", {
                    class: "ljc-pre",
                    innerHTML: highlightedJson.value
                  }, null, 8, _hoisted_14$l)
                ])) : activeTab.value === "context" ? (openBlock(), createElementBlock("div", _hoisted_15$g, [
                  _cache[6] || (_cache[6] = createElementVNode(
                    "p",
                    null,
                    "上下文需查询 API，面板内展示当前日志前后字段摘要。",
                    -1
                    /* CACHED */
                  )),
                  createElementVNode("div", _hoisted_16$f, [
                    _cache[4] || (_cache[4] = createElementVNode(
                      "div",
                      { class: "lov-key" },
                      "service",
                      -1
                      /* CACHED */
                    )),
                    createElementVNode(
                      "div",
                      _hoisted_17$e,
                      toDisplayString(__props.row.service || "—"),
                      1
                      /* TEXT */
                    )
                  ]),
                  createElementVNode("div", _hoisted_18$e, [
                    _cache[5] || (_cache[5] = createElementVNode(
                      "div",
                      { class: "lov-key" },
                      "traceId",
                      -1
                      /* CACHED */
                    )),
                    createElementVNode(
                      "div",
                      _hoisted_19$e,
                      toDisplayString(__props.row.traceId || "—"),
                      1
                      /* TEXT */
                    )
                  ])
                ])) : (openBlock(), createElementBlock("div", _hoisted_20$d, [..._cache[7] || (_cache[7] = [
                  createElementVNode(
                    "p",
                    null,
                    "指标视图需要聚合查询；面板模式下暂无关联时序数据。",
                    -1
                    /* CACHED */
                  )
                ])]))
              ])
            ])
          ])) : createCommentVNode("v-if", true)
        ]),
        _: 1
        /* STABLE */
      });
    };
  }
});
const ArgusLogDetail = /* @__PURE__ */ _export_sfc(_sfc_main$2J, [["__scopeId", "data-v-c488dee9"]]);
const _hoisted_1$1X = ["data-show-controls", "data-enable-log-details", "data-allow-download", "data-show-copy", "data-show-copy-log-link", "data-logs-compatible", "data-show-time", "data-wrap", "data-prettify"];
const _hoisted_2$1x = { class: "le-actions-bar" };
const _hoisted_3$1m = { class: "le-actions-left" };
const _hoisted_4$1b = { class: "le-ab-label" };
const _hoisted_5$11 = { class: "le-actions-right" };
const _hoisted_6$U = { class: "le-options-wrap" };
const _hoisted_7$R = ["value"];
const _hoisted_8$I = {
  key: 0,
  class: "le-extra-chips"
};
const _hoisted_9$F = ["onClick"];
const _hoisted_10$z = {
  key: 0,
  class: "navContainer",
  "data-testid": "logstable-controls"
};
const _hoisted_11$t = { class: "meta" };
const _hoisted_12$n = { class: "main" };
const _hoisted_13$m = {
  key: 0,
  class: "time"
};
const _hoisted_14$k = {
  key: 1,
  class: "act"
};
const _hoisted_15$f = ["data-open", "data-level", "onClick"];
const _hoisted_16$e = { class: "sev" };
const _hoisted_17$d = {
  key: 0,
  class: "time"
};
const _hoisted_18$d = { class: "le-ts" };
const _hoisted_19$d = { class: "level" };
const _hoisted_20$c = { class: "service" };
const _hoisted_21$b = { class: "mono" };
const _hoisted_22$9 = { class: "body" };
const _hoisted_23$7 = { class: "mono body-cell" };
const _hoisted_24$7 = { class: "trace" };
const _hoisted_25$7 = { class: "trace-id" };
const _hoisted_26$6 = {
  key: 1,
  class: "act"
};
const _hoisted_27$5 = ["onClick"];
const _hoisted_28$5 = {
  key: 0,
  class: "empty"
};
const ROW_H = 32;
const _sfc_main$2I = /* @__PURE__ */ defineComponent({
  __name: "LogsTableRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    replaceVariables: { type: Function },
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const openId = ref(null);
    const optionsVisible = ref(false);
    const wrapLocal = ref(null);
    const extraColumnsLocal = ref(null);
    const opts = computed(() => props.options ?? {});
    const frames = computed(() => props.data?.series ?? []);
    const showControls = computed(() => opts.value.showControls !== false);
    const enableLogDetails = computed(() => opts.value.enableLogDetails !== false);
    const allowDownload = computed(() => !!opts.value.allowDownload);
    const showCopyLogLink = computed(() => opts.value.showCopyLogLink !== false);
    const showTime = computed(() => opts.value.showTime !== false);
    const prettifyLogMessage = computed(() => !!opts.value.prettifyLogMessage);
    const wrapOn = computed(() => !!opts.value.wrapLogMessage);
    const wrapEffective = computed(
      () => wrapLocal.value === null ? wrapOn.value : wrapLocal.value
    );
    const extraColumns = computed(() => {
      if (extraColumnsLocal.value) return extraColumnsLocal.value;
      const raw = opts.value.extraColumns;
      if (Array.isArray(raw)) return raw.map(String).filter(Boolean);
      if (typeof raw === "string" && raw.trim()) {
        return raw.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
      }
      return [];
    });
    const logsCompatible = computed(() => {
      const frame = frames.value[0];
      if (!frame?.fields?.length) return false;
      const hasTime = frame.fields.some((f) => f.type === "time");
      const hasString = frame.fields.some((f) => f.type === "string");
      return hasTime && hasString;
    });
    const availableColumnNames = computed(() => {
      const frame = frames.value[0];
      if (!frame) return [];
      const names = /* @__PURE__ */ new Set();
      for (const f of frame.fields || []) {
        const n = String(f.name || "");
        if (!n || /time|Time/i.test(n)) continue;
        if (/line|message|msg|body|Log/i.test(n)) continue;
        if (/level|severity/i.test(n)) continue;
        names.add(n);
        const sample = f.values?.[0];
        if (sample && typeof sample === "object" && !Array.isArray(sample)) {
          Object.keys(sample).forEach((k) => names.add(k));
        }
      }
      names.add("service.name");
      names.add("traceId");
      return [...names].sort();
    });
    const rows = computed(() => {
      const list = frames.value;
      if (!list.length) return [];
      return parseLogRowsFromFrames(list, {
        prettifyLogMessage: prettifyLogMessage.value,
        sortOrder: "Descending"
      });
    });
    const tableViewport = ref(null);
    const scrollTop = ref(0);
    const viewportHeight = ref(400);
    const virtualWin = computed(
      () => computeVirtualWindow(rows.value.length, scrollTop.value, viewportHeight.value, ROW_H, 10)
    );
    const visibleRows = computed(() => sliceVirtualRows(rows.value, virtualWin.value));
    function onTableScroll() {
      const el = tableViewport.value;
      if (!el) return;
      scrollTop.value = el.scrollTop;
      viewportHeight.value = el.clientHeight || 400;
    }
    let tableRo = null;
    onMounted(() => {
      onTableScroll();
      if (typeof ResizeObserver !== "undefined" && tableViewport.value) {
        tableRo = new ResizeObserver(() => onTableScroll());
        tableRo.observe(tableViewport.value);
      }
    });
    onBeforeUnmount(() => tableRo?.disconnect());
    const activeRow = computed(
      () => rows.value.find((r) => r.id === openId.value) ?? null
    );
    function toggleRow(row) {
      if (!enableLogDetails.value) return;
      openId.value = openId.value === row.id ? null : row.id;
    }
    function closeDetail() {
      openId.value = null;
    }
    async function copyRow(r) {
      try {
        await navigator.clipboard?.writeText(r.raw);
      } catch {
      }
    }
    function downloadCsv() {
      if (!allowDownload.value) return;
      const cols = [
        ...showTime.value ? ["timestamp"] : [],
        "severity",
        "service",
        ...extraColumns.value,
        "body",
        "traceId"
      ];
      const header = cols.join(",");
      const body = rows.value.map(
        (r) => cols.map((c) => {
          let v = "";
          if (c === "timestamp") v = r.t;
          else if (c === "severity") v = r.severityText;
          else if (c === "service") v = r.service;
          else if (c === "body") v = r.raw;
          else if (c === "traceId") v = r.traceId;
          else v = getRowAttr(r, c);
          return `"${String(v).replace(/"/g, '""')}"`;
        }).join(",")
      ).join("\n");
      const blob = new Blob([header + "\n" + body], {
        type: "text/csv;charset=utf-8"
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "logs-table.csv";
      a.click();
      URL.revokeObjectURL(url);
    }
    function addColumn(name) {
      if (!name || extraColumns.value.includes(name)) return;
      extraColumnsLocal.value = [...extraColumns.value, name];
    }
    function removeColumn(name) {
      extraColumnsLocal.value = extraColumns.value.filter((c) => c !== name);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["logstable", {
          "logstable--wrap": wrapEffective.value,
          "logstable--prettify": prettifyLogMessage.value
        }]),
        "data-testid": "panel-logstable",
        "data-show-controls": String(showControls.value),
        "data-enable-log-details": String(enableLogDetails.value),
        "data-allow-download": String(allowDownload.value),
        "data-show-copy": String(showCopyLogLink.value),
        "data-show-copy-log-link": String(showCopyLogLink.value),
        "data-logs-compatible": String(logsCompatible.value),
        "data-show-time": String(showTime.value),
        "data-wrap": String(wrapEffective.value),
        "data-prettify": String(prettifyLogMessage.value)
      }, [
        !logsCompatible.value ? (openBlock(), createBlock(PanelDataErrorView, {
          key: 0,
          data: __props.data,
          "field-config": __props.fieldConfig,
          "needs-string-field": true,
          "needs-time-field": true
        }, null, 8, ["data", "field-config"])) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" Argus actions bar "),
            createElementVNode("div", _hoisted_2$1x, [
              createElementVNode("div", _hoisted_3$1m, [
                createElementVNode(
                  "span",
                  _hoisted_4$1b,
                  toDisplayString(rows.value.length) + " 条日志",
                  1
                  /* TEXT */
                )
              ]),
              createElementVNode("div", _hoisted_5$11, [
                createElementVNode("div", _hoisted_6$U, [
                  createElementVNode(
                    "button",
                    {
                      type: "button",
                      class: normalizeClass(["le-options-btn", { active: optionsVisible.value }]),
                      "data-testid": "logstable-options",
                      onClick: _cache[0] || (_cache[0] = ($event) => optionsVisible.value = !optionsVisible.value)
                    },
                    " 选项 ",
                    2
                    /* CLASS */
                  ),
                  optionsVisible.value ? (openBlock(), createElementBlock("div", {
                    key: 0,
                    class: "le-opts-popper",
                    onClick: _cache[2] || (_cache[2] = withModifiers(() => {
                    }, ["stop"]))
                  }, [
                    _cache[5] || (_cache[5] = createElementVNode(
                      "div",
                      { class: "le-opts-label" },
                      "添加列",
                      -1
                      /* CACHED */
                    )),
                    createElementVNode(
                      "select",
                      {
                        class: "le-select",
                        "data-testid": "logstable-add-column",
                        onChange: _cache[1] || (_cache[1] = ($event) => {
                          addColumn($event.target.value);
                          $event.target.value = "";
                        })
                      },
                      [
                        _cache[4] || (_cache[4] = createElementVNode(
                          "option",
                          { value: "" },
                          "选择字段…",
                          -1
                          /* CACHED */
                        )),
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(availableColumnNames.value.filter(
                            (c) => !extraColumns.value.includes(c)
                          ), (n) => {
                            return openBlock(), createElementBlock("option", {
                              key: n,
                              value: n
                            }, toDisplayString(n), 9, _hoisted_7$R);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ],
                      32
                      /* NEED_HYDRATION */
                    ),
                    extraColumns.value.length ? (openBlock(), createElementBlock("div", _hoisted_8$I, [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(extraColumns.value, (c) => {
                          return openBlock(), createElementBlock("span", {
                            key: c,
                            class: "chip",
                            onClick: ($event) => removeColumn(c)
                          }, toDisplayString(c) + " ×", 9, _hoisted_9$F);
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])) : createCommentVNode("v-if", true)
                  ])) : createCommentVNode("v-if", true)
                ])
              ])
            ]),
            createElementVNode(
              "div",
              {
                class: normalizeClass(["le-shell", { "with-controls": showControls.value }])
              },
              [
                showControls.value ? (openBlock(), createElementBlock("div", _hoisted_10$z, [
                  createElementVNode(
                    "button",
                    {
                      type: "button",
                      class: normalizeClass(["ctrl", { active: wrapEffective.value }]),
                      title: "换行",
                      onClick: _cache[3] || (_cache[3] = ($event) => wrapLocal.value = !wrapEffective.value)
                    },
                    " ↵ ",
                    2
                    /* CLASS */
                  ),
                  allowDownload.value ? (openBlock(), createElementBlock("button", {
                    key: 0,
                    type: "button",
                    class: "ctrl",
                    title: "下载",
                    "data-testid": "logstable-download",
                    onClick: downloadCsv
                  }, " ↓ ")) : createCommentVNode("v-if", true),
                  createElementVNode(
                    "span",
                    _hoisted_11$t,
                    toDisplayString(rows.value.length),
                    1
                    /* TEXT */
                  )
                ])) : createCommentVNode("v-if", true),
                createElementVNode("div", _hoisted_12$n, [
                  createElementVNode(
                    "div",
                    {
                      ref_key: "tableViewport",
                      ref: tableViewport,
                      class: "tableWrap",
                      "data-testid": "logstable-details",
                      onScrollPassive: onTableScroll
                    },
                    [
                      createElementVNode(
                        "div",
                        {
                          style: normalizeStyle({ height: virtualWin.value.totalHeight + "px", position: "relative" })
                        },
                        [
                          createElementVNode(
                            "table",
                            {
                              class: "table le-col-table",
                              style: normalizeStyle({ transform: "translateY(" + virtualWin.value.offsetY + "px)" })
                            },
                            [
                              createElementVNode("thead", null, [
                                createElementVNode("tr", null, [
                                  _cache[6] || (_cache[6] = createElementVNode(
                                    "th",
                                    {
                                      class: "sev",
                                      "aria-hidden": "true"
                                    },
                                    null,
                                    -1
                                    /* CACHED */
                                  )),
                                  showTime.value ? (openBlock(), createElementBlock("th", _hoisted_13$m, "时间")) : createCommentVNode("v-if", true),
                                  _cache[7] || (_cache[7] = createElementVNode(
                                    "th",
                                    { class: "level" },
                                    "级别",
                                    -1
                                    /* CACHED */
                                  )),
                                  _cache[8] || (_cache[8] = createElementVNode(
                                    "th",
                                    { class: "service" },
                                    "服务",
                                    -1
                                    /* CACHED */
                                  )),
                                  (openBlock(true), createElementBlock(
                                    Fragment,
                                    null,
                                    renderList(extraColumns.value, (col2) => {
                                      return openBlock(), createElementBlock(
                                        "th",
                                        { key: col2 },
                                        toDisplayString(col2),
                                        1
                                        /* TEXT */
                                      );
                                    }),
                                    128
                                    /* KEYED_FRAGMENT */
                                  )),
                                  _cache[9] || (_cache[9] = createElementVNode(
                                    "th",
                                    { class: "body" },
                                    "内容",
                                    -1
                                    /* CACHED */
                                  )),
                                  _cache[10] || (_cache[10] = createElementVNode(
                                    "th",
                                    { class: "trace" },
                                    "Trace ID",
                                    -1
                                    /* CACHED */
                                  )),
                                  showCopyLogLink.value ? (openBlock(), createElementBlock("th", _hoisted_14$k)) : createCommentVNode("v-if", true)
                                ])
                              ]),
                              createElementVNode("tbody", null, [
                                (openBlock(true), createElementBlock(
                                  Fragment,
                                  null,
                                  renderList(visibleRows.value, (r) => {
                                    return openBlock(), createElementBlock("tr", {
                                      key: r.id,
                                      class: normalizeClass(["row", { "is-active": openId.value === r.id }]),
                                      "data-testid": "logstable-row",
                                      "data-open": openId.value === r.id ? "true" : "false",
                                      "data-level": r.level,
                                      onClick: ($event) => toggleRow(r)
                                    }, [
                                      createElementVNode("td", _hoisted_16$e, [
                                        createElementVNode(
                                          "span",
                                          {
                                            class: "le-sev-bar",
                                            style: normalizeStyle({ background: unref(severityColor)(r.level) })
                                          },
                                          null,
                                          4
                                          /* STYLE */
                                        )
                                      ]),
                                      showTime.value ? (openBlock(), createElementBlock("td", _hoisted_17$d, [
                                        createElementVNode(
                                          "span",
                                          _hoisted_18$d,
                                          toDisplayString(r.t),
                                          1
                                          /* TEXT */
                                        )
                                      ])) : createCommentVNode("v-if", true),
                                      createElementVNode("td", _hoisted_19$d, [
                                        createElementVNode(
                                          "span",
                                          {
                                            class: "le-lvl",
                                            style: normalizeStyle(unref(severityBadgeStyle)(r.level))
                                          },
                                          toDisplayString(r.severityText),
                                          5
                                          /* TEXT, STYLE */
                                        )
                                      ]),
                                      createElementVNode(
                                        "td",
                                        _hoisted_20$c,
                                        toDisplayString(r.service || "—"),
                                        1
                                        /* TEXT */
                                      ),
                                      (openBlock(true), createElementBlock(
                                        Fragment,
                                        null,
                                        renderList(extraColumns.value, (col2) => {
                                          return openBlock(), createElementBlock("td", {
                                            key: col2,
                                            class: "extra"
                                          }, [
                                            createElementVNode(
                                              "span",
                                              _hoisted_21$b,
                                              toDisplayString(unref(getRowAttr)(r, col2) || "—"),
                                              1
                                              /* TEXT */
                                            )
                                          ]);
                                        }),
                                        128
                                        /* KEYED_FRAGMENT */
                                      )),
                                      createElementVNode("td", _hoisted_22$9, [
                                        createElementVNode(
                                          "span",
                                          _hoisted_23$7,
                                          toDisplayString(r.msg),
                                          1
                                          /* TEXT */
                                        )
                                      ]),
                                      createElementVNode("td", _hoisted_24$7, [
                                        createElementVNode(
                                          "span",
                                          _hoisted_25$7,
                                          toDisplayString(r.traceId || "—"),
                                          1
                                          /* TEXT */
                                        )
                                      ]),
                                      showCopyLogLink.value ? (openBlock(), createElementBlock("td", _hoisted_26$6, [
                                        createElementVNode("button", {
                                          type: "button",
                                          "data-testid": "logstable-copy",
                                          title: "复制",
                                          onClick: withModifiers(($event) => copyRow(r), ["stop"])
                                        }, " 复制 ", 8, _hoisted_27$5)
                                      ])) : createCommentVNode("v-if", true)
                                    ], 10, _hoisted_15$f);
                                  }),
                                  128
                                  /* KEYED_FRAGMENT */
                                ))
                              ])
                            ],
                            4
                            /* STYLE */
                          )
                        ],
                        4
                        /* STYLE */
                      ),
                      !rows.value.length ? (openBlock(), createElementBlock("div", _hoisted_28$5, "无日志数据")) : createCommentVNode("v-if", true)
                    ],
                    544
                    /* NEED_HYDRATION, NEED_PATCH */
                  )
                ])
              ],
              2
              /* CLASS */
            ),
            enableLogDetails.value ? (openBlock(), createBlock(ArgusLogDetail, {
              key: 0,
              open: !!activeRow.value,
              row: activeRow.value,
              onClose: closeDetail
            }, null, 8, ["open", "row"])) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 10, _hoisted_1$1X);
    };
  }
});
const LogsTableRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2I, [["__scopeId", "data-v-7addc568"]]);
const _sfc_main$2H = /* @__PURE__ */ defineComponent({
  __name: "LogsTableRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    replaceVariables: { type: Function },
    width: {},
    height: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createBlock(LogsTableRenderer, {
        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 _sfc_main$2G = /* @__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(_sfc_main$2H, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "logstable",
    name: "日志表格",
    description: "表格形态日志",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2G
).useFieldConfig().setPanelOptions((builder) => {
  const cat = ["日志表格"];
  builder.addBoolean(
    {
      id: "enableLogDetails",
      path: "enableLogDetails",
      name: "启用日志详情",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showCopyLogLink",
      path: "showCopyLogLink",
      name: "显示复制链接按钮",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showControls",
      path: "showControls",
      name: "显示控件",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "allowDownload",
      path: "allowDownload",
      name: "显示下载控件",
      category: cat,
      showIf: (c) => !!c.showControls
    },
    false
  ).addBoolean(
    {
      id: "showTime",
      path: "showTime",
      name: "显示时间",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "wrapLogMessage",
      path: "wrapLogMessage",
      name: "换行日志",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "prettifyLogMessage",
      path: "prettifyLogMessage",
      name: "美化 JSON 日志",
      category: cat
    },
    false
  ).addText(
    {
      id: "extraColumns",
      path: "extraColumns",
      name: "额外列",
      category: cat
    },
    ""
  );
}).setRuntimeConsumedPaths([
  "allowDownload",
  "enableLogDetails",
  "showControls",
  "showCopyLogLink",
  "showTime",
  "wrapLogMessage",
  "prettifyLogMessage",
  "extraColumns"
]).register();
function uplotSeriesSchemaSig(seriesList) {
  return seriesList.map((s) => {
    const style = [
      s.color ?? "",
      JSON.stringify(s.lineStyle ?? ""),
      s.drawStyle ?? "",
      s.showPoints ?? "",
      s.pointSize ?? "",
      s.lineWidth ?? "",
      s.fillOpacity ?? "",
      s.lineInterpolation ?? "",
      String(s.spanNulls ?? ""),
      String(s.showValues ?? ""),
      s.barAlignment ?? "",
      s.barWidthFactor ?? "",
      s.gradientMode ?? "",
      s.scaleKey ?? "",
      s.constantY != null ? "c" : "p"
    ].join(",");
    return `${s.label ?? ""}:${style}`;
  }).join("|");
}
function uplotSeriesVisibilitySig(seriesList) {
  return seriesList.map((s) => `${s.label ?? ""}:${s.hidden ? 0 : 1}`).join("|");
}
const NO_UPDATE_OPS = {
  rebuild: false,
  setData: false,
  setSize: false,
  setScale: false,
  setSeries: false
};
function planUPlotUpdate(hasChart, prev, next) {
  if (!hasChart || !prev) {
    return {
      rebuild: true,
      setData: false,
      setSize: false,
      setScale: false,
      setSeries: false
    };
  }
  if (next.themeToken !== prev.themeToken || next.schemaSig !== prev.schemaSig || next.styleSig !== prev.styleSig) {
    return {
      rebuild: true,
      setData: false,
      setSize: false,
      setScale: false,
      setSeries: false
    };
  }
  const ops = { ...NO_UPDATE_OPS };
  if (next.visibilitySig !== prev.visibilitySig) {
    ops.setSeries = true;
  }
  if (next.sizeW !== prev.sizeW || next.sizeH !== prev.sizeH) {
    ops.setSize = true;
  }
  if (next.xMin !== prev.xMin || next.xMax !== prev.xMax) {
    ops.setScale = true;
  }
  if (next.dataRevision !== prev.dataRevision) {
    ops.setData = true;
  }
  return ops;
}
function mergeUPlotOps(a, b) {
  if (a.rebuild || b.rebuild) {
    return {
      rebuild: true,
      setData: false,
      setSize: false,
      setScale: false,
      setSeries: false
    };
  }
  return {
    rebuild: false,
    setData: a.setData || b.setData,
    setSize: a.setSize || b.setSize,
    setScale: a.setScale || b.setScale,
    setSeries: a.setSeries || b.setSeries
  };
}
function hasAnyUPlotOps(ops) {
  return ops.rebuild || ops.setData || ops.setSize || ops.setScale || ops.setSeries;
}
function getStackingBands(group) {
  const bands = [];
  const series = group.series ?? [];
  const dir = group.dir ?? 1;
  const lastIdx = series.length - 1;
  const rSeries = series.slice().reverse();
  rSeries.forEach((si, i) => {
    if (i !== lastIdx) {
      const nextIdx = rSeries[i + 1];
      bands.push({
        series: [si, nextIdx],
        // fill direction is inverted from stack direction
        dir: -1 * dir
      });
    }
  });
  return bands;
}
function stackingBandsForSeriesCount(count, dir = 1) {
  if (count < 2) return [];
  const series = Array.from({ length: count }, (_, i) => i + 1);
  return getStackingBands({ series, dir });
}
const UPLOT_AXIS_FONT_SIZE$1 = 12;
let _measureCtx$1 = null;
function measureAxisText$1(text, fontSize = UPLOT_AXIS_FONT_SIZE$1) {
  if (typeof document === "undefined")
    return Math.ceil(String(text).length * fontSize * 0.6);
  if (!_measureCtx$1) {
    _measureCtx$1 = document.createElement("canvas").getContext("2d");
  }
  if (!_measureCtx$1) return Math.ceil(String(text).length * fontSize * 0.6);
  _measureCtx$1.font = `400 ${fontSize}px Inter`;
  return _measureCtx$1.measureText(String(text ?? "")).width;
}
function pad2(n) {
  return n.toString().padStart(2, "0");
}
function formatTime(v, tz, spanMs) {
  const d = new Date(v);
  const utc = String(tz || "").toLowerCase() === "utc";
  const Y = utc ? d.getUTCFullYear() : d.getFullYear();
  const M = utc ? d.getUTCMonth() + 1 : d.getMonth() + 1;
  const D = utc ? d.getUTCDate() : d.getDate();
  const h2 = utc ? d.getUTCHours() : d.getHours();
  const m = utc ? d.getUTCMinutes() : d.getMinutes();
  const s = utc ? d.getUTCSeconds() : d.getSeconds();
  const span = spanMs ?? 0;
  if (span > 0 && span <= 5 * 6e4) {
    return `${pad2(h2)}:${pad2(m)}:${pad2(s)}`;
  }
  if (span > 7 * 24 * 60 * 6e4) {
    return `${Y}-${pad2(M)}-${pad2(D)}`;
  }
  if (span > 24 * 60 * 6e4) {
    return `${pad2(M)}-${pad2(D)} ${pad2(h2)}:${pad2(m)}`;
  }
  return `${pad2(h2)}:${pad2(m)}`;
}
function formatAxisNumber(v) {
  if (!Number.isFinite(v)) return "";
  const abs = Math.abs(v);
  if (abs >= 1e9) return `${Number((v / 1e9).toFixed(abs >= 1e10 ? 0 : 1))}G`;
  if (abs >= 1e6) return `${Number((v / 1e6).toFixed(abs >= 1e7 ? 0 : 1))}M`;
  if (abs >= 1e4) return `${Number((v / 1e3).toFixed(abs >= 1e5 ? 0 : 1))}k`;
  if (Number.isInteger(v) || Math.abs(v - Math.round(v)) < 1e-9)
    return String(Math.round(v));
  if (abs >= 100) return String(Number(v.toFixed(1)));
  if (abs >= 1) return String(Number(v.toFixed(2)));
  if (abs >= 0.01) return String(Number(v.toFixed(3)));
  return String(Number(v.toPrecision(2)));
}
function formatAxisValue(v, opts) {
  if (!Number.isFinite(v)) return "";
  const unit = opts?.unit;
  const decimals = opts?.decimals;
  if (unit && unit !== "none") {
    try {
      const out = getValueFormat(unit)(v, decimals);
      return `${out.text}${out.suffix || ""}`;
    } catch {
    }
  }
  if (decimals != null && Number.isFinite(decimals)) {
    return Number(v).toFixed(Math.max(0, Math.min(10, Math.floor(decimals))));
  }
  return formatAxisNumber(v);
}
function estimateLabelWidth(text, isTime) {
  const len = Math.max(text.length, 5);
  return Math.ceil(len * 7.2 + 10);
}
const Y_TICK_SPACING_PANEL_HEIGHT = 150;
const Y_TICK_SPACING_NORMAL = 30;
const Y_TICK_SPACING_SMALL = 15;
const X_TICK_SPACING_NORMAL = 40;
const X_TICK_VALUE_GAP = 18;
function adaptiveAxisSpace(plotPx, axis, isTime, spanMs = 0) {
  if (axis === "y") {
    return plotPx <= Y_TICK_SPACING_PANEL_HEIGHT ? Y_TICK_SPACING_SMALL : Y_TICK_SPACING_NORMAL;
  }
  let sample = "00:00";
  if (isTime) {
    if (spanMs > 0 && spanMs <= 5 * 6e4) sample = "00:00:00";
    else if (spanMs > 7 * 24 * 60 * 6e4) sample = "2020-01-01";
    else if (spanMs > 24 * 60 * 6e4) sample = "01-01 00:00";
    else sample = "00:00";
  } else {
    sample = "0.000";
  }
  const valueWidth = measureAxisText$1(sample, UPLOT_AXIS_FONT_SIZE$1);
  return Math.max(
    X_TICK_SPACING_NORMAL,
    Math.ceil(valueWidth + X_TICK_VALUE_GAP)
  );
}
function formatSplitsAdaptive(u, splits, scaleKey, format) {
  if (!splits.length) return [];
  const isX = scaleKey === "x";
  const out = splits.map(() => "");
  const up = u;
  const pos = splits.map(
    (v) => isX ? up.valToPos(v, "x") : up.valToPos(v, "y")
  );
  let lastPlaced = -1;
  for (let i = 0; i < splits.length; i++) {
    const label = format(splits[i]);
    if (!label) continue;
    const need = isX ? estimateLabelWidth(label) * 0.92 : 16;
    if (lastPlaced < 0 || Math.abs(pos[i] - pos[lastPlaced]) >= need) {
      out[i] = label;
      lastPlaced = i;
    }
  }
  const last = splits.length - 1;
  if (last > 0 && !out[last]) {
    const label = format(splits[last]);
    let prev = -1;
    for (let i = last - 1; i >= 0; i--) {
      if (out[i]) {
        prev = i;
        break;
      }
    }
    const need = isX ? estimateLabelWidth(label) * 0.7 : 14;
    if (prev < 0 || Math.abs(pos[last] - pos[prev]) >= need) out[last] = label;
  }
  return out;
}
function pickNearestHoverSeries(series, cursorTop) {
  const withVal = series.filter(
    (s) => s.value != null && Number.isFinite(s.value)
  );
  if (!withVal.length) return series.filter((s) => s.value != null).slice(0, 1);
  let best = withVal[0];
  let bestDist = Infinity;
  for (const sp of withVal) {
    const y = sp.yPos;
    if (y == null || !Number.isFinite(y)) continue;
    const d = Math.abs(y - cursorTop);
    if (d < bestDist) {
      bestDist = d;
      best = sp;
    }
  }
  return [
    {
      index: best.index,
      label: best.label,
      value: best.value,
      color: best.color
    }
  ];
}
function isNaNNumber(v) {
  return typeof v === "number" && Number.isNaN(v);
}
function toYCell(v) {
  if (v === void 0) return void 0;
  if (v === null || isNaNNumber(v)) return null;
  if (typeof v === "number" && Number.isFinite(v)) return v;
  return null;
}
function isPreAlignedSeries(series) {
  if (series.length === 0) return false;
  if (series.some((s) => s.constantY != null)) return false;
  const n = series[0].points?.length ?? 0;
  if (n === 0) return false;
  for (let si = 1; si < series.length; si++) {
    if ((series[si].points?.length ?? 0) !== n) return false;
  }
  const base = series[0].points;
  for (let i = 1; i < n; i++) {
    if (base[i].x <= base[i - 1].x) return false;
  }
  for (let si = 1; si < series.length; si++) {
    const pts = series[si].points;
    for (let i = 0; i < n; i++) {
      if (pts[i].x !== base[i].x) return false;
    }
  }
  return true;
}
function toAlignedSeriesData(series) {
  const visible = series.filter((s) => !s.hidden);
  if (!visible.length) return [[0], [0]];
  if (isPreAlignedSeries(visible)) {
    const base = visible[0].points;
    const xs2 = new Array(base.length);
    for (let i = 0; i < base.length; i++) xs2[i] = base[i].x;
    const ys2 = visible.map((s) => {
      const row = new Array(base.length);
      const pts = s.points;
      for (let i = 0; i < base.length; i++) {
        row[i] = toYCell(pts[i].y);
      }
      return row;
    });
    return [xs2, ...ys2];
  }
  const xSet = /* @__PURE__ */ new Set();
  for (const s of visible) {
    if (s.constantY != null) continue;
    for (const p of s.points) {
      if (p.x != null) xSet.add(p.x);
    }
  }
  if (xSet.size === 0) {
    const hasConst = visible.some((s) => s.constantY != null);
    if (hasConst) {
      const xs2 = [0];
      const ys2 = visible.map(
        (s) => s.constantY != null ? [s.constantY] : [null]
      );
      return [xs2, ...ys2];
    }
    return [[0], [0]];
  }
  const xs = Array.from(xSet);
  xs.sort((a, b) => a - b);
  const xIndex = /* @__PURE__ */ new Map();
  for (let i = 0; i < xs.length; i++) xIndex.set(xs[i], i);
  const ys = visible.map((s) => {
    if (s.constantY != null) {
      const row2 = new Array(xs.length);
      const c = s.constantY;
      for (let i = 0; i < xs.length; i++) row2[i] = c;
      return row2;
    }
    const missing = s.spanNulls === true ? void 0 : null;
    const row = new Array(xs.length);
    for (let i = 0; i < xs.length; i++) row[i] = missing;
    for (const p of s.points) {
      if (p.x == null) continue;
      const idx = xIndex.get(p.x);
      if (idx == null) continue;
      row[idx] = toYCell(p.y);
    }
    return row;
  });
  return [xs, ...ys];
}
function getUPlotPalette() {
  return getClassicPalette$1(resolveThemeModeHint());
}
getClassicPalette$1("dark");
const UPLOT_AXIS_FONT_SIZE = 12;
const UPLOT_AXIS_FONT = `${UPLOT_AXIS_FONT_SIZE}px Inter`;
let _measureCtx = null;
function measureAxisText(text, fontSize = UPLOT_AXIS_FONT_SIZE) {
  if (typeof document === "undefined")
    return Math.ceil(String(text).length * fontSize * 0.6);
  if (!_measureCtx) {
    _measureCtx = document.createElement("canvas").getContext("2d");
  }
  if (!_measureCtx) return Math.ceil(String(text).length * fontSize * 0.6);
  _measureCtx.font = `400 ${fontSize}px Inter`;
  return _measureCtx.measureText(String(text ?? "")).width;
}
function calculateAxisSize(self, values, side) {
  const ticksSize = 4;
  const gap = 5;
  const labelGap = 0;
  let axisSize = ticksSize;
  if (side === 2) {
    axisSize += gap + UPLOT_AXIS_FONT_SIZE;
  } else {
    const labels = (values || []).map((v) => v == null ? "" : String(v)).filter((v) => v.length > 0 && v.length < 24);
    let maxTextWidth = 12;
    if (labels.length) {
      maxTextWidth = labels.reduce(
        (acc, value) => Math.max(acc, measureAxisText(value)),
        0
      );
    }
    const textWidthWithLimit = Math.min(
      (self?.width ?? 100) * 0.4,
      maxTextWidth
    );
    axisSize += gap + labelGap + textWidthWithLimit;
  }
  return Math.ceil(axisSize);
}
function isDarkTheme() {
  if (typeof document === "undefined") return true;
  const root = document.documentElement;
  const t2 = root.getAttribute("data-theme") || root.getAttribute("data-grafana-theme") || root.dataset.theme || document.body?.dataset?.theme || "";
  if (String(t2).toLowerCase() === "light") return false;
  if (String(t2).toLowerCase() === "dark") return true;
  try {
    const bg = getComputedStyle(root).getPropertyValue("--grafana-bg") || getComputedStyle(document.body).backgroundColor;
    const m = String(bg).match(/rgba?\((\d+)/);
    if (m && Number(m[1]) > 200) return false;
  } catch {
  }
  return true;
}
function uplotGridColor(dark) {
  return dark ? "rgba(240, 250, 255, 0.09)" : "rgba(0, 10, 23, 0.09)";
}
function uplotAxisStroke(dark) {
  return dark ? "rgb(204, 204, 220)" : "rgb(36, 41, 46)";
}
function grafanaPaddingSide(_u, side, sidesWithAxes) {
  const hasCrossAxis = side % 2 ? sidesWithAxes[0] || sidesWithAxes[2] : sidesWithAxes[1] || sidesWithAxes[3];
  return sidesWithAxes[side] || !hasCrossAxis ? 0 : 8;
}
function readNum(v) {
  if (v == null || v === "") return void 0;
  const n = Number(unref(v));
  return Number.isFinite(n) ? n : void 0;
}
function readStr(v, fallback = "") {
  const x = unref(v);
  return x == null ? fallback : String(x);
}
function dashFor(style) {
  if (!style) return void 0;
  if (typeof style === "object") {
    if (style.dash?.length) return style.dash;
    return dashFor(style.fill);
  }
  if (style === "dash") return [10, 10];
  if (style === "dot" || style === "dots") return [0, 10];
  return void 0;
}
function hexAlpha(color, alpha2) {
  if (typeof color !== "string" || !color)
    return `rgba(115,191,105,${Math.max(0, Math.min(1, alpha2))})`;
  if (color.startsWith("rgba") || color.startsWith("rgb")) return color;
  const a = Math.max(0, Math.min(1, alpha2));
  if (color.startsWith("#") && (color.length === 7 || color.length === 4)) {
    let r, g, b;
    if (color.length === 4) {
      r = parseInt(color[1] + color[1], 16);
      g = parseInt(color[2] + color[2], 16);
      b = parseInt(color[3] + color[3], 16);
    } else {
      r = parseInt(color.slice(1, 3), 16);
      g = parseInt(color.slice(3, 5), 16);
      b = parseInt(color.slice(5, 7), 16);
    }
    return `rgba(${r},${g},${b},${a})`;
  }
  return color;
}
function squarePointPaths(u, seriesIdx, idx0, idx1, filtIdxs) {
  const s = u.series[seriesIdx];
  const size = s.points?.size ?? 6;
  const half = size / 2;
  const xdata = u.data[0];
  const ydata = u.data[seriesIdx];
  const ctx = u.ctx;
  const allow = filtIdxs ? new Set(filtIdxs) : null;
  ctx.save();
  ctx.fillStyle = String(s.points?.fill ?? s.stroke ?? (isDarkTheme() ? "rgb(204, 204, 220)" : "rgb(17, 18, 23)"));
  ctx.strokeStyle = String(s.points?.stroke ?? s.stroke ?? (isDarkTheme() ? "rgb(204, 204, 220)" : "rgb(17, 18, 23)"));
  ctx.lineWidth = Number(s.points?.width ?? 1);
  for (let i = idx0; i <= idx1; i++) {
    if (allow && !allow.has(i)) continue;
    const y = ydata[i];
    if (y == null || !Number.isFinite(y)) continue;
    const x = u.valToPos(xdata[i], "x", true);
    const yy = u.valToPos(y, s.scale, true);
    ctx.fillRect(x - half, yy - half, size, size);
    if (ctx.lineWidth > 0) ctx.strokeRect(x - half, yy - half, size, size);
  }
  ctx.restore();
  return {
    stroke: null,
    fill: null,
    clip: null,
    band: null,
    gaps: null,
    flags: 0
  };
}
function pathsFor(interp, mode2, barWidthFactor, barBucketSize, barAlignment) {
  const paths = uPlot.paths;
  if (mode2 === "bars") {
    if (barBucketSize != null && Number.isFinite(barBucketSize) && barBucketSize > 0) {
      const bs = barBucketSize;
      return paths.bars?.({
        align: 1,
        disp: {
          x0: {
            unit: 1,
            values: (u) => u.data[0]
          },
          size: {
            unit: 1,
            values: () => [bs]
          }
        }
      });
    }
    const size = Math.max(0.05, Math.min(1, barWidthFactor));
    const opts = { size: [size, 1e6] };
    if (barAlignment != null && Number.isFinite(barAlignment)) {
      opts.align = barAlignment;
    } else if (size >= 0.99) {
      opts.align = 1;
    }
    return paths.bars?.(opts);
  }
  if (mode2 === "points") return void 0;
  if (interp === "smooth") return paths.spline?.();
  if (interp === "stepBefore") return paths.stepped?.({ align: -1 });
  if (interp === "stepAfter") return paths.stepped?.({ align: 1 });
  return void 0;
}
function createThresholdsDrawHook(thresholds, thresholdsMode, percent) {
  if (!thresholds.length || !thresholdsMode || thresholdsMode === "off")
    return null;
  const wantLine = thresholdsMode === "line" || thresholdsMode === "dashed" || thresholdsMode === "line+area" || thresholdsMode === "dashed+area";
  const wantArea = thresholdsMode === "area" || thresholdsMode === "line+area" || thresholdsMode === "dashed+area";
  const dashed = thresholdsMode === "dashed" || thresholdsMode === "dashed+area";
  return (u) => {
    const ctx = u.ctx;
    const { left, top, width: w, height: h2 } = u.bbox;
    const yMin = u.scales.y.min ?? 0;
    const yMax = u.scales.y.max ?? 1;
    const sorted = [...thresholds].filter((th) => Number.isFinite(th.value)).map(
      (th) => percent ? { ...th, value: yMin + (yMax - yMin) * Number(th.value) / 100 } : th
    ).sort((a, b) => a.value - b.value);
    if (!sorted.length) return;
    ctx.save();
    if (wantArea) {
      for (let i = 0; i < sorted.length; i++) {
        const th = sorted[i];
        const yTop = i + 1 < sorted.length ? u.valToPos(sorted[i + 1].value, "y", true) : top;
        const yBot = u.valToPos(th.value, "y", true);
        const y0 = Math.min(yTop, yBot);
        const y1 = Math.max(yTop, yBot);
        if (y1 < top || y0 > top + h2) continue;
        const color = th.color || classicOrange();
        ctx.fillStyle = hexAlpha(color, 0.12);
        const cy0 = Math.max(y0, top);
        const cy1 = Math.min(y1, top + h2);
        if (cy1 > cy0) ctx.fillRect(left, cy0, w, cy1 - cy0);
      }
    }
    if (wantLine) {
      for (const th of sorted) {
        const y = u.valToPos(th.value, "y", true);
        if (y < top || y > top + h2) continue;
        ctx.strokeStyle = th.color || classicOrange();
        ctx.lineWidth = 1.5;
        ctx.globalAlpha = 0.85;
        ctx.setLineDash(dashed ? [6, 4] : []);
        ctx.beginPath();
        ctx.moveTo(left, y);
        ctx.lineTo(left + w, y);
        ctx.stroke();
        ctx.setLineDash([]);
        ctx.globalAlpha = 1;
        if (th.label) {
          ctx.fillStyle = th.color || classicOrange();
          ctx.font = "10px sans-serif";
          ctx.fillText(th.label, left + 4, y - 3);
        }
      }
    }
    ctx.restore();
  };
}
function resolvePointsShow(drawStyle, showPoints) {
  if (drawStyle === "points") return true;
  if (showPoints === "always") return true;
  if (showPoints === "never" || drawStyle === "bars") return false;
  return void 0;
}
function resolvePointSize(pointSize, lineWidth) {
  if (!pointSize || pointSize < lineWidth) return void 0;
  return pointSize;
}
function buildPointOptionOverrides(options) {
  const result = {};
  if (options.show !== void 0) result.show = options.show;
  if (options.size !== void 0) result.size = options.size;
  if (options.space !== void 0) result.space = options.space;
  if (options.paths !== void 0) result.paths = options.paths;
  return result;
}
function getPointValueLabelPosition(x, y, pointSize, pixelRatio = 1, value = 0) {
  const isNegative = value < 0;
  const radiusPad = Math.max(pointSize / 2 + 4, 5);
  const offset = isNegative ? radiusPad + 2 : -radiusPad;
  return {
    x,
    y: y + offset * pixelRatio,
    textAlign: "center",
    textBaseline: isNegative ? "top" : "bottom"
  };
}
function shouldShowSeriesValues(drawStyle, pointsVisible, plotWidth, pointCount) {
  if (pointsVisible) return true;
  return drawStyle === "bars" && pointCount > 0 && plotWidth / pointCount >= 30;
}
function toRgbCss(color) {
  if (!color) return "rgb(115,191,105)";
  if (color.startsWith("rgb")) return color;
  if (color.startsWith("#")) {
    const c = color.length === 4 ? `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` : color.slice(0, 7);
    const r = parseInt(c.slice(1, 3), 16);
    const g = parseInt(c.slice(3, 5), 16);
    const b = parseInt(c.slice(5, 7), 16);
    return `rgb(${r},${g},${b})`;
  }
  return color;
}
function huePair(color, opacity, dark) {
  const base = toRgbCss(color);
  const top = lighten(base, 0.12);
  const bot = darken(base, dark ? 0.18 : 0.08);
  return [alpha$1(top, opacity), alpha$1(bot, opacity)];
}
function getOpacityGradientFill(color, opacityPercent) {
  const opacity = Math.max(0, Math.min(1, opacityPercent / 100));
  return (plot) => {
    const ctx = plot.ctx;
    const g = ctx.createLinearGradient(
      0,
      plot.bbox.top,
      0,
      plot.bbox.top + plot.bbox.height
    );
    g.addColorStop(0, hexAlpha(color, opacity));
    g.addColorStop(1, hexAlpha(color, 0));
    return g;
  };
}
function getHueGradientFill(color, opacityPercent, darkTheme) {
  const opacity = Math.max(0, Math.min(1, opacityPercent / 100));
  return (plot) => {
    const stroke = plot.series[plot.series.length - 1]?._stroke || color;
    const [c0, c1] = huePair(String(stroke || color), opacity, darkTheme);
    const ctx = plot.ctx;
    const g = ctx.createLinearGradient(
      0,
      plot.bbox.top,
      0,
      plot.bbox.top + plot.bbox.height
    );
    g.addColorStop(0, c0);
    g.addColorStop(1, c1);
    return g;
  };
}
function getSchemeGradientFill(color, opacityPercent, thresholds, scaleKey = "y") {
  const steps = thresholds?.steps?.filter(
    (s) => s && Number.isFinite(Number(s.value)) && Number(s.value) !== -Infinity
  );
  if (!steps?.length) {
    return getOpacityGradientFill(color, opacityPercent);
  }
  const opacity = Math.max(0, Math.min(1, opacityPercent / 100));
  return (plot) => {
    const scale = plot.scales[scaleKey];
    const min = scale?.min ?? 0;
    const max = scale?.max ?? 1;
    const range = max - min || 1;
    const ctx = plot.ctx;
    const g = ctx.createLinearGradient(
      0,
      plot.bbox.top + plot.bbox.height,
      0,
      plot.bbox.top
    );
    const sorted = [...steps].sort((a, b) => Number(a.value) - Number(b.value));
    for (const step of sorted) {
      const t2 = Math.max(0, Math.min(1, (Number(step.value) - min) / range));
      g.addColorStop(t2, hexAlpha(step.color || color, opacity || 1));
    }
    return g;
  };
}
function resolveSeriesFill(opts) {
  const { color, fillOpacity, gradientMode, darkTheme, thresholds, scaleKey } = opts;
  if (!(fillOpacity > 0) && gradientMode === "none") return void 0;
  const mode2 = gradientMode || "none";
  if (mode2 === "opacity") return getOpacityGradientFill(color, fillOpacity);
  if (mode2 === "hue") return getHueGradientFill(color, fillOpacity || 100, darkTheme);
  if (mode2 === "scheme") {
    return getSchemeGradientFill(color, fillOpacity || 100, thresholds, scaleKey);
  }
  if (fillOpacity > 0) return hexAlpha(color, fillOpacity / 100);
  return void 0;
}
function nullToUndefThreshold(refValues, fieldValues2, maxThreshold) {
  if (!(maxThreshold > 0) || !fieldValues2.length) return fieldValues2.slice();
  const out = fieldValues2.slice();
  let prevRef;
  let nullIdx;
  for (let i = 0; i < out.length; i++) {
    const fieldVal = out[i];
    const isMissing = fieldVal == null || typeof fieldVal === "number" && !Number.isFinite(fieldVal);
    if (isMissing) {
      if (nullIdx == null && prevRef != null) {
        nullIdx = i;
      }
    } else {
      if (nullIdx != null && prevRef != null) {
        if (refValues[i] - prevRef < maxThreshold) {
          while (nullIdx < i) {
            out[nullIdx++] = void 0;
          }
        }
        nullIdx = void 0;
      }
      prevRef = refValues[i];
    }
  }
  return out;
}
function applySpanNullsThreshold(points, maxThreshold) {
  if (!points.length || !(maxThreshold > 0)) return points;
  const refValues = points.map((p) => p.x);
  const fieldValues2 = points.map((p) => p.y);
  const next = nullToUndefThreshold(refValues, fieldValues2, maxThreshold);
  return points.map((p, i) => ({ x: p.x, y: next[i] }));
}
function applyInsertNulls(points, insertNulls, mode2 = "threshold") {
  if (!insertNulls || points.length < 2) return points;
  const xs = points.map((p) => p.x);
  const steps = [];
  for (let i = 1; i < xs.length; i++) steps.push(xs[i] - xs[i - 1]);
  const sorted = steps.slice().sort((a, b) => a - b);
  const median = sorted[Math.floor(sorted.length / 2)] || 1;
  const threshold = typeof insertNulls === "number" && Number.isFinite(insertNulls) ? insertNulls : median * 2.5;
  if (!(threshold > 0)) return points;
  const insertX = (prev, next) => {
    if (mode2 === "midpoint") return [(prev + next) / 2];
    if (mode2 === "plusone") return [prev + 1];
    const xsIns = [];
    let x = prev + threshold;
    let guard = 0;
    while (x < next && guard++ < 1e4) {
      xsIns.push(x);
      x += threshold;
    }
    return xsIns;
  };
  const out = [];
  for (let i = 0; i < points.length; i++) {
    out.push(points[i]);
    if (i < points.length - 1) {
      const prev = points[i].x;
      const next = points[i + 1].x;
      const gap = next - prev;
      if (gap > threshold) {
        for (const x of insertX(prev, next)) {
          out.push({ x, y: null });
        }
      }
    }
  }
  return out;
}
function resolveSpanGaps(spanNulls) {
  if (typeof spanNulls === "number") return false;
  return Boolean(spanNulls);
}
function numRef(v, fallback = 0) {
  const n = Number(unref(v));
  return Number.isFinite(n) ? n : fallback;
}
function boolRef(v, fallback = false) {
  if (v == null) return fallback;
  return Boolean(unref(v));
}
function unrefAny(v) {
  return unref(v);
}
function useUPlot(el, seriesList, opts) {
  let chart = null;
  const hover = ref(null);
  function mode2() {
    const m = opts.mode;
    if (!m) return "line";
    return typeof m === "string" ? m : m.value;
  }
  function build2() {
    if (!el.value) return;
    chart?.destroy();
    chart = null;
    const series = seriesList.value.filter((s) => !s.hidden);
    const hasPoints = series.some(
      (s) => s.points?.some((p) => p.y != null && Number.isFinite(p.y))
    );
    if (!series.length || !hasPoints) {
      return;
    }
    const data = toAlignedSeriesData(seriesList.value);
    const width2 = Math.max(
      numRef(opts.width) || el.value.clientWidth || 100,
      40
    );
    const height2 = Math.max(
      numRef(opts.height) || el.value.clientHeight || 80,
      40
    );
    const xs = data[0] ?? [];
    const dataSpanMs = unrefAny(opts.timeX) !== false && xs.length >= 2 ? Math.abs(Number(xs[xs.length - 1]) - Number(xs[0])) : 0;
    const plotWGuess = Math.max(width2 - 64, 40);
    const plotHGuess = Math.max(height2 - 40, 32);
    const m = mode2();
    const barWidthFactor = readNum(opts.barWidthFactor) ?? 0.6;
    const barBucketSize = readNum(opts.barBucketSize);
    const softMin = readNum(opts.softMin);
    const softMax = readNum(opts.softMax);
    const globalSpan = boolRef(opts.spanNulls);
    const globalLW = readNum(opts.lineWidth) ?? 1;
    const globalFill = readNum(opts.fillOpacity) ?? (m === "area" ? 20 : 0);
    void (opts.showLegend == null ? series.length > 1 : boolRef(opts.showLegend, true));
    const gradientMode = readStr(opts.gradientMode, "none");
    const globalInterp = readStr(opts.lineInterpolation, "linear");
    const axis = unrefAny(
      opts.axis
    ) ?? {};
    const thresholds = unrefAny(
      opts.thresholds
    ) ?? [];
    const globalShowValues = boolRef(opts.showValues);
    const showValues = globalShowValues || series.some((item) => item.showValues === true);
    const yScale = { auto: true };
    const scaleDist = normalizeScaleDistribution(unrefAny(opts.scaleDistribution));
    if (scaleDist.type === "log") {
      yScale.distr = 3;
      yScale.log = scaleDist.log ?? 10;
    } else if (scaleDist.type === "symlog") {
      yScale.distr = 4;
      yScale.log = scaleDist.log ?? 10;
      yScale.asinh = scaleDist.linearThreshold ?? 1;
    }
    if (axis.centeredZero || softMin != null || softMax != null) {
      if (axis.centeredZero) {
        yScale.range = (_u, dataMin, dataMax) => {
          const abs = Math.max(
            Math.abs(dataMin ?? 0),
            Math.abs(dataMax ?? 0),
            1
          );
          let min = -abs;
          let max = abs;
          if (softMin != null) min = Math.min(min, softMin);
          if (softMax != null) max = Math.max(max, softMax);
          return [min, max];
        };
      } else {
        yScale.range = (_u, dataMin, dataMax) => {
          if (dataMin == null && dataMax == null) return [null, null];
          const softMinMode = softMin == null ? 3 : 1;
          const softMaxMode = softMax == null ? 3 : 1;
          const rangeConfig = {
            min: {
              pad: 0.1,
              hard: -Infinity,
              soft: softMin ?? 0,
              mode: softMinMode
            },
            max: {
              pad: 0.1,
              hard: Infinity,
              soft: softMax ?? 0,
              mode: softMaxMode
            }
          };
          return uPlot.rangeNum(
            dataMin,
            dataMax,
            rangeConfig
          );
        };
      }
    }
    if (axis.softMin != null && softMin == null) yScale.min = axis.softMin;
    if (axis.softMax != null && softMax == null) yScale.max = axis.softMax;
    if (scaleDist.type === "log" && !yScale.range) {
      yScale.range = (_u, dataMin, dataMax) => {
        let min = dataMin ?? 1;
        let max = dataMax ?? 10;
        if (!(min > 0) || !Number.isFinite(min)) min = 1;
        if (!(max > 0) || !Number.isFinite(max)) max = min * 10;
        if (max <= min) max = min * 10;
        if (softMin != null && softMin > 0) min = Math.min(min, softMin);
        if (softMax != null && softMax > 0) max = Math.max(max, softMax);
        return [min, max];
      };
    }
    const gridShow = axis.gridShow !== false;
    const xGridShow = axis.xGridShow != null ? !!axis.xGridShow : gridShow;
    const yGridShow = axis.yGridShow != null ? !!axis.yGridShow : gridShow;
    const axisHidden = axis.placement === "hidden";
    const axisSide = axis.placement === "right" ? 1 : 3;
    const hooks = {};
    const thresholdsMode = readStr(opts.thresholdsMode, "line");
    const thresholdDraw = createThresholdsDrawHook(
      thresholds,
      thresholdsMode,
      boolRef(opts.thresholdsPercent)
    );
    if (thresholdDraw) {
      hooks.draw = [thresholdDraw];
    }
    const drawHook = unrefAny(opts.drawHook);
    if (typeof drawHook === "function") {
      hooks.draw = [...hooks.draw || [], drawHook];
    }
    if (showValues) {
      hooks.drawSeries = [
        (u, si) => {
          if (si === 0) return;
          if (!(series[si - 1]?.showValues ?? globalShowValues)) return;
          const ctx = u.ctx;
          const s = u.series[si];
          if (!s.show) return;
          const pointsVisible = typeof s.points?.show === "function" ? s.points.show(u, si) : Boolean(s.points?.show);
          if (!shouldShowSeriesValues(
            series[si - 1]?.drawStyle,
            pointsVisible,
            u.bbox.width / uPlot.pxRatio,
            u.data[0]?.length ?? 0
          )) {
            return;
          }
          ctx.save();
          ctx.fillStyle = getComputedStyle(el.value).getPropertyValue("--grafana-text").trim() || s.stroke;
          const fs = readNum(opts.showValueFontSize) ?? 10;
          ctx.font = `${fs * uPlot.pxRatio}px sans-serif`;
          const xs2 = u.data[0];
          const ys = u.data[si];
          const pointSize = Number(s.points?.size || 5);
          const seriesUnit = series[si - 1]?.unit;
          for (let i = 0; i < xs2.length; i++) {
            const yv = ys[i];
            if (yv == null || !Number.isFinite(yv)) continue;
            const x = u.valToPos(xs2[i], "x", true);
            const y = u.valToPos(yv, s.scale || "y", true);
            const label = getPointValueLabelPosition(
              x,
              y,
              pointSize,
              uPlot.pxRatio,
              yv
            );
            ctx.textAlign = label.textAlign;
            ctx.textBaseline = label.textBaseline;
            ctx.fillText(
              formatAxisValue(yv, {
                unit: seriesUnit || axis.unit,
                decimals: axis.decimals
              }),
              label.x,
              label.y
            );
          }
          ctx.restore();
        }
      ];
    }
    if (boolRef(opts.fullHighlight)) {
      hooks.draw = [
        ...hooks.draw || [],
        (u) => {
          const idx = u.cursor?.idx;
          if (idx == null || idx < 0) return;
          const xs2 = u.data[0];
          if (!xs2 || idx >= xs2.length) return;
          const ctx = u.ctx;
          const { top, width: plotW, height: plotH } = u.bbox;
          const xC = u.valToPos(xs2[idx], "x", true);
          const n = xs2.length;
          const slot = plotW / Math.max(n, 1);
          const w = Math.max(1, slot * 0.97);
          ctx.save();
          ctx.fillStyle = isDarkTheme() ? "rgba(204, 204, 220, 0.08)" : "rgba(36, 41, 46, 0.08)";
          ctx.fillRect(xC - w / 2, top, w, plotH);
          ctx.restore();
        }
      ];
    }
    hooks.setCursor = [
      ...hooks.setCursor || [],
      (u) => {
        pendingHoverU = u;
        if (hoverRaf != null) return;
        hoverRaf = typeof requestAnimationFrame === "function" ? requestAnimationFrame(() => {
          hoverRaf = null;
          const cu = pendingHoverU;
          pendingHoverU = null;
          if (!cu) return;
          applyHoverFromCursor(cu);
        }) : null;
        if (hoverRaf == null) {
          const cu = pendingHoverU;
          pendingHoverU = null;
          if (cu) applyHoverFromCursor(cu);
        }
      }
    ];
    const bandList = unrefAny(opts.bands) ?? [];
    const uBands = bandList.filter((b) => Array.isArray(b?.series) && b.series.length === 2).map((b) => {
      const band = { series: [b.series[0], b.series[1]] };
      if (b.dir === 1 || b.dir === -1) band.dir = b.dir;
      if (b.fill !== void 0) band.fill = b.fill;
      return band;
    });
    const dark = isDarkTheme();
    const gridColor = uplotGridColor(dark);
    const axisStrokeBase = uplotAxisStroke(dark);
    const axisColorMode = String(axis.colorMode || "text");
    const axisStroke = axisColorMode === "series" && axis.seriesColor ? String(axis.seriesColor) : axisStrokeBase;
    const axisFont = axis.font || UPLOT_AXIS_FONT;
    const hair = 1 / (typeof devicePixelRatio === "number" && devicePixelRatio > 0 ? devicePixelRatio : 1);
    const xMin = readNum(opts.xMin);
    const xMax = readNum(opts.xMax);
    const xScale = { time: unrefAny(opts.timeX) !== false };
    if (xMin != null && xMax != null && xMax > xMin) {
      xScale.range = () => [xMin, xMax];
      xScale.min = xMin;
      xScale.max = xMax;
      xScale.auto = false;
    } else {
      if (xMin != null) xScale.min = xMin;
      if (xMax != null) xScale.max = xMax;
    }
    const scaleOrientation = String(
      unrefAny(opts.scaleOrientation) ?? "vertical"
    );
    const isHorizontalScale = scaleOrientation === "horizontal";
    if (isHorizontalScale) {
      xScale.ori = 1;
      xScale.dir = -1;
      yScale.ori = 0;
      yScale.dir = 1;
    }
    chart = new uPlot(
      {
        width: width2,
        height: height2,
        // Grafana DEFAULT_PLOT_CONFIG: timestamps are milliseconds
        ms: 1,
        // Grafana DEFAULT_PLOT_CONFIG paddingSide: 0 on sides with axes.
        // Explicit function guards against uPlot sidesWithAxes false-negatives on left y.
        padding: [
          (_u, side, sidesWithAxes) => grafanaPaddingSide(_u, side, sidesWithAxes),
          (_u, side, sidesWithAxes) => grafanaPaddingSide(_u, side, sidesWithAxes),
          (_u, side, sidesWithAxes) => grafanaPaddingSide(_u, side, sidesWithAxes),
          // left: always 0 when y-axis is shown (default timeseries)
          (_u, side, sidesWithAxes) => {
            if (!axisHidden) return 0;
            return grafanaPaddingSide(_u, side, sidesWithAxes);
          }
        ],
        cursor: (() => {
          const proxRaw = readNum(opts.hoverProximity);
          const DEFAULT_FOCUS = 30;
          const DEFAULT_NULL = 15;
          const focusProx = proxRaw != null ? proxRaw : DEFAULT_FOCUS;
          const dragOpt = unrefAny(opts.cursorDrag);
          return {
            show: true,
            drag: {
              x: dragOpt?.x !== false,
              y: dragOpt?.y === true
            },
            // Grafana TimeSeries utils: focus.prox + hover.prox
            focus: { prox: focusProx },
            hover: {
              prox: (_self, _seriesIdx, _hoveredIdx) => {
                if (proxRaw != null) return proxRaw;
                return DEFAULT_NULL;
              },
              skip: [null]
            }
          };
        })(),
        legend: { show: false, live: false },
        // custom legend rendered by PanelHost/PanelChrome
        ...uBands.length ? { bands: uBands } : {},
        scales: {
          x: xScale,
          y: yScale,
          ...unrefAny(opts.extraScales) ?? {}
        },
        axes: [
          {
            // horizontal bars: category axis on left; vertical: bottom
            side: isHorizontalScale ? 3 : 2,
            stroke: axisStroke,
            font: axisFont,
            grid: { show: xGridShow, stroke: gridColor, width: hair },
            ticks: { show: true, stroke: gridColor, width: hair, size: 4 },
            border: {
              show: axis.borderShow === true,
              stroke: axisStroke,
              width: hair
            },
            space: (self, _axisIdx, _scaleMin, _scaleMax, plotDim) => {
              const span = unrefAny(opts.timeX) !== false ? Math.abs(
                Number(self.scales.x.max ?? 0) - Number(self.scales.x.min ?? 0)
              ) : Math.abs(
                Number(self.scales.x.max ?? 0) - Number(self.scales.x.min ?? 0)
              ) || dataSpanMs;
              return adaptiveAxisSpace(
                plotDim || plotWGuess,
                "x",
                unrefAny(opts.timeX) !== false,
                span
              );
            },
            // Grafana Histogram.tsx xSplits — bucket-aligned ticks
            ...(() => {
              const xSplitsFn = unrefAny(opts.xSplits);
              return typeof xSplitsFn === "function" ? { splits: xSplitsFn } : {};
            })(),
            gap: readNum(opts.xAxisGap) ?? 5,
            rotate: (() => {
              const r = readNum(opts.xTickLabelRotation);
              return r != null && r !== 0 ? r : void 0;
            })(),
            // Grafana: ticks + gap + fontSize ≈ 21; barchart dual-run needs ~35
            size: (_u, values) => {
              const forced = readNum(opts.xAxisSize);
              if (forced != null && forced > 0) return forced;
              return calculateAxisSize(_u, values || [], 2);
            },
            values: (u, splits) => {
              const span = splits.length >= 2 ? Math.abs(splits[splits.length - 1] - splits[0]) : dataSpanMs;
              const labels = unrefAny(opts.xValueLabels);
              const isTime = unrefAny(opts.timeX) !== false;
              const format = (v) => {
                if (labels && labels.length) {
                  const idx = Math.round(v);
                  if (idx >= 0 && idx < labels.length) return labels[idx] ?? "";
                  return "";
                }
                return isTime ? formatTime(v, axis.timezone, span) : formatAxisNumber(v);
              };
              if (typeof unrefAny(opts.xSplits) === "function") {
                return splits.map((v) => format(v));
              }
              if (labels && labels.length) {
                return splits.map((v) => format(v));
              }
              return formatSplitsAdaptive(u, splits, "x", format);
            }
          },
          {
            show: !axisHidden,
            side: isHorizontalScale ? 2 : axisSide,
            label: axis.label || void 0,
            stroke: axisStroke,
            font: axisFont,
            grid: { show: yGridShow, stroke: gridColor, width: hair },
            ticks: { show: true, stroke: gridColor, width: hair, size: 4 },
            border: {
              show: axis.borderShow === true,
              stroke: axisStroke,
              width: hair
            },
            space: (_self, _axisIdx, _scaleMin, _scaleMax, plotDim) => adaptiveAxisSpace(plotDim || plotHGuess, "y", false),
            // Empirical dual-run: Grafana label right-edge sits ~4px closer to plot than uPlot default gap paint
            gap: axis.gap != null ? Number(axis.gap) : 1,
            size: axis.width != null ? Math.max(Number(axis.width), 1) : axis.sizeAuto || axis.label || unrefAny(opts.yValueLabels) ? (u, values) => calculateAxisSize(u, values || [], axisSide) : 27,
            ...typeof opts.ySplits === "function" ? {
              splits: (u) => {
                const custom = opts.ySplits(u);
                return custom?.length ? custom : [0.5];
              }
            } : unrefAny(opts.yValueLabels) ? {
              splits: (_u) => {
                const labels = unrefAny(opts.yValueLabels) ?? [];
                const n = Math.max(labels.length, 1);
                return Array.from(
                  { length: n },
                  (_, i) => 1 - (i + 0.5) / n
                );
              }
            } : {},
            values: (u, splits) => {
              const labels = unrefAny(opts.yValueLabels);
              if (labels && labels.length) {
                const n = labels.length;
                return splits.map((v) => {
                  let best = 0;
                  let bestD = Infinity;
                  for (let i = 0; i < n; i++) {
                    const mid = 1 - (i + 0.5) / n;
                    const d = Math.abs(v - mid);
                    if (d < bestD) {
                      bestD = d;
                      best = i;
                    }
                  }
                  return labels[best] ?? "";
                });
              }
              return formatSplitsAdaptive(u, splits, "y", (v) => {
                const seriesUnit = series.find(
                  (s) => s && s.unit && String(s.unit).length
                );
                return formatAxisValue(v, {
                  unit: axis.unit || seriesUnit?.unit,
                  decimals: axis.decimals != null && Number.isFinite(Number(axis.decimals)) ? Number(axis.decimals) : void 0
                });
              });
            }
          },
          ...unrefAny(opts.extraAxes) ?? []
        ],
        series: [
          {},
          ...series.map((s, i) => {
            const color = s.color || getUPlotPalette()[i % getUPlotPalette().length];
            const lw = s.lineWidth ?? globalLW;
            const fillOp = s.fillOpacity ?? globalFill;
            const spanRaw = s.spanNulls ?? globalSpan;
            const span = resolveSpanGaps(spanRaw);
            const showPts = s.showPoints ?? "auto";
            const seriesMode = s.drawStyle ?? m;
            const seriesGradientMode = s.gradientMode ?? gradientMode;
            const pointsShow = resolvePointsShow(seriesMode, showPts);
            const suppressPaths = boolRef(opts.suppressSeriesPaths, false);
            const effectivePointsShow = s.skipLine || suppressPaths ? false : pointsShow;
            const interp = s.lineInterpolation ?? globalInterp;
            const path = pathsFor(
              interp,
              seriesMode,
              s.barWidthFactor ?? barWidthFactor,
              barBucketSize,
              s.barAlignment
            );
            const scaleKey = s.scale || "y";
            const lineFill = typeof s.lineStyle === "object" ? String(s.lineStyle?.fill ?? "") : String(s.lineStyle ?? "");
            const base = {
              label: s.label,
              stroke: s.skipLine || suppressPaths ? "rgba(0,0,0,0)" : color,
              width: s.skipLine || suppressPaths || seriesMode === "points" ? 0 : Math.max(lw, 0),
              scale: scaleKey,
              points: {
                ...buildPointOptionOverrides({
                  show: effectivePointsShow,
                  size: resolvePointSize(s.pointSize, Math.max(lw, 0)),
                  space: showPts === "always" || seriesMode === "points" ? 0.01 : void 0,
                  paths: s.pointShape === "square" ? squarePointPaths : void 0
                }),
                fill: color,
                // hollow/ring markers read better on filled area (Grafana timeseries)
                stroke: color,
                width: s.pointStrokeWidth ?? 1
                // showPoints=always must not density-filter markers (uPlot default space=_ptDia*2).
                // Use a tiny positive space — 0 can break uPlot's maxPts math in some builds.
              },
              spanGaps: span,
              dash: dashFor(s.lineStyle),
              ...lineFill === "dot" || lineFill === "dots" ? { cap: "round" } : {}
            };
            if (s.skipLine || suppressPaths) {
              base.paths = () => ({
                stroke: null,
                fill: null,
                clip: null,
                band: null,
                gaps: null,
                flags: 0
              });
            } else if (path) {
              base.paths = path;
            }
            if (!suppressPaths && (seriesMode === "area" || fillOp > 0 || seriesGradientMode === "hue" || seriesGradientMode === "scheme")) {
              const fill = resolveSeriesFill({
                color,
                fillOpacity: fillOp,
                gradientMode: seriesGradientMode,
                darkTheme: isDarkTheme(),
                thresholds: unrefAny(opts.thresholdsConfig),
                scaleKey
              });
              if (fill != null) base.fill = fill;
            }
            return base;
          })
        ],
        hooks
      },
      data,
      el.value
    );
    rememberSnapshotAfterBuild();
  }
  let lastSnap = null;
  let dataRevision = 0;
  let themeToken = isDarkTheme() ? "dark" : "light";
  let pendingOps = { ...NO_UPDATE_OPS };
  let flushRaf = null;
  let flushScheduled = false;
  let hoverRaf = null;
  let pendingHoverU = null;
  let themeRebuildPending = false;
  let io = null;
  let isElementVisible = true;
  let disposed = false;
  function currentSize() {
    const w = Math.max(
      numRef(opts.width) || el.value?.clientWidth || 100,
      40
    );
    const h2 = Math.max(
      numRef(opts.height) || el.value?.clientHeight || 80,
      40
    );
    return { w, h: h2 };
  }
  function styleSig() {
    return [
      mode2(),
      String(unrefAny(opts.timeX) !== false),
      String(readNum(opts.softMin) ?? ""),
      String(readNum(opts.softMax) ?? ""),
      String(boolRef(opts.spanNulls)),
      String(readNum(opts.lineWidth) ?? ""),
      String(readNum(opts.fillOpacity) ?? ""),
      String(boolRef(opts.showLegend, true)),
      String(readNum(opts.barWidthFactor) ?? ""),
      String(readNum(opts.barBucketSize) ?? ""),
      String(readNum(opts.xTickLabelRotation) ?? ""),
      String(boolRef(opts.fullHighlight)),
      String(readNum(opts.xAxisSize) ?? ""),
      String(readNum(opts.xAxisGap) ?? ""),
      readStr(opts.gradientMode, "none"),
      readStr(opts.lineInterpolation, "linear"),
      readStr(opts.thresholdsMode, "line"),
      String(boolRef(opts.thresholdsPercent)),
      String(boolRef(opts.showValues)),
      readStr(opts.tooltipMode, "single"),
      JSON.stringify(unrefAny(opts.axis) ?? null),
      JSON.stringify(unrefAny(opts.thresholds) ?? null),
      JSON.stringify(unrefAny(opts.bands) ?? null),
      JSON.stringify(unrefAny(opts.xValueLabels) ?? null),
      JSON.stringify(unrefAny(opts.yValueLabels) ?? null),
      JSON.stringify(unrefAny(opts.extraScales) ?? null),
      JSON.stringify(unrefAny(opts.extraAxes) ?? null),
      JSON.stringify(unrefAny(opts.thresholdsConfig) ?? null),
      // drawHook identity
      String(typeof unrefAny(opts.drawHook))
    ].join("~");
  }
  function takeSnapshot() {
    const size = currentSize();
    return {
      schemaSig: uplotSeriesSchemaSig(seriesList.value),
      styleSig: styleSig(),
      visibilitySig: uplotSeriesVisibilitySig(seriesList.value),
      sizeW: size.w,
      sizeH: size.h,
      xMin: readNum(opts.xMin),
      xMax: readNum(opts.xMax),
      themeToken,
      dataRevision
    };
  }
  function rememberSnapshotAfterBuild() {
    lastSnap = takeSnapshot();
  }
  function applyHoverFromCursor(u) {
    const tipMode = () => readStr(opts.tooltipMode, "single");
    const mode22 = tipMode();
    if (mode22 === "none" || mode22 === "hidden") {
      hover.value = null;
      opts.onHover?.(null);
      return;
    }
    const idx = u.cursor.idx;
    const left = u.cursor.left;
    const top = u.cursor.top;
    if (idx == null || left == null || top == null || left < 0 || top < 0) {
      hover.value = null;
      opts.onHover?.(null);
      return;
    }
    const xs = u.data[0];
    const x = xs[idx];
    if (x == null || !Number.isFinite(x)) {
      hover.value = null;
      opts.onHover?.(null);
      return;
    }
    const visible = seriesList.value.filter((s) => !s.hidden);
    const seriesPts = [];
    for (let si = 1; si < u.series.length; si++) {
      const sMeta = visible[si - 1];
      const ys = u.data[si];
      const yv = ys?.[idx];
      const val = yv == null || !Number.isFinite(Number(yv)) ? null : Number(yv);
      if (mode22 === "single" || mode22 === "multi" || mode22 === "all") {
        if ((mode22 === "multi" || mode22 === "all") && val == null) continue;
        seriesPts.push({
          index: si,
          label: sMeta?.label || String(u.series[si].label || `Series ${si}`),
          value: val,
          color: sMeta?.color || u.series[si].stroke || void 0,
          yPos: val != null ? u.valToPos(val, "y") : void 0
        });
      }
    }
    let outSeries = seriesPts;
    if (mode22 === "single" && seriesPts.length) {
      const withY = seriesPts.map((sp) => ({
        ...sp,
        yPos: sp.value != null && Number.isFinite(sp.value) ? u.valToPos(sp.value, "y") : void 0
      }));
      outSeries = pickNearestHoverSeries(withY, top);
    }
    if ((mode22 === "multi" || mode22 === "all") && outSeries.length > 1) {
      const sort = readStr(opts.tooltipSort, "none");
      if (sort === "desc" || sort === "asc") {
        outSeries = [...outSeries].sort((a, b) => {
          const av = a.value;
          const bv = b.value;
          if (av == null && bv == null) return 0;
          if (av == null) return 1;
          if (bv == null) return -1;
          return sort === "desc" ? bv - av : av - bv;
        });
      }
    }
    const xPos = u.valToPos(x, "x");
    const yCursorVal = (() => {
      try {
        return u.posToVal(top, "y");
      } catch {
        return void 0;
      }
    })();
    const pt = {
      left,
      top,
      x,
      idx,
      series: outSeries,
      xPos,
      yCursorVal: yCursorVal != null && Number.isFinite(yCursorVal) ? yCursorVal : void 0
    };
    hover.value = pt;
    opts.onHover?.(pt);
  }
  function applySetSeriesVisibility() {
    if (!chart) return false;
    const visible = seriesList.value.filter((s) => !s.hidden);
    const chartSeries = chart.series;
    if (chartSeries.length - 1 !== visible.length) {
      return false;
    }
    for (let i = 0; i < visible.length; i++) {
      const label = visible[i]?.label ?? "";
      const cs = chartSeries[i + 1];
      if (String(cs?.label ?? "") !== label) return false;
      try {
        chart.setSeries(i + 1, { show: true }, false);
      } catch {
        return false;
      }
    }
    return true;
  }
  function applyOps(ops) {
    if (disposed) return;
    if (ops.rebuild) {
      build2();
      return;
    }
    if (!chart) {
      build2();
      return;
    }
    if (ops.setSeries) {
      if (!applySetSeriesVisibility()) {
        build2();
        return;
      }
    }
    if (ops.setSize) {
      const size = currentSize();
      chart.setSize({ width: size.w, height: size.h });
    }
    if (ops.setScale) {
      const xMin = readNum(opts.xMin);
      const xMax = readNum(opts.xMax);
      if (xMin != null && xMax != null && xMax > xMin) {
        chart.setScale("x", { min: xMin, max: xMax });
      }
    }
    if (ops.setData) {
      const data = toAlignedSeriesData(seriesList.value);
      chart.setData(data);
    }
    lastSnap = takeSnapshot();
  }
  function flushPending() {
    flushRaf = null;
    flushScheduled = false;
    if (disposed) return;
    const ops = pendingOps;
    pendingOps = { ...NO_UPDATE_OPS };
    if (!hasAnyUPlotOps(ops)) return;
    if (ops.rebuild && themeRebuildPending && !isElementVisible) {
      pendingOps = mergeUPlotOps(pendingOps, ops);
      scheduleIdleThemeRebuild();
      return;
    }
    if (ops.rebuild) themeRebuildPending = false;
    applyOps(ops);
  }
  function scheduleFlush() {
    if (disposed) return;
    if (flushScheduled) return;
    flushScheduled = true;
    if (typeof requestAnimationFrame === "function") {
      flushRaf = requestAnimationFrame(() => flushPending());
    } else {
      flushPending();
    }
  }
  function enqueueFromSnapshot() {
    const next = takeSnapshot();
    const ops = planUPlotUpdate(!!chart, lastSnap, next);
    if (!hasAnyUPlotOps(ops)) return;
    pendingOps = mergeUPlotOps(pendingOps, ops);
    scheduleFlush();
  }
  function updateData() {
    dataRevision += 1;
    enqueueFromSnapshot();
  }
  let idleHandle = null;
  function scheduleIdleThemeRebuild() {
    if (idleHandle != null) return;
    const ric = globalThis.requestIdleCallback;
    if (typeof ric === "function") {
      idleHandle = ric(
        () => {
          idleHandle = null;
          if (disposed) return;
          if (!isElementVisible && themeRebuildPending) return;
          scheduleFlush();
        },
        { timeout: 1e3 }
      );
    } else if (typeof requestAnimationFrame === "function") {
      idleHandle = requestAnimationFrame(() => {
        idleHandle = null;
        scheduleFlush();
      });
    } else {
      scheduleFlush();
    }
  }
  function observeVisibility() {
    if (typeof IntersectionObserver === "undefined" || !el.value) {
      isElementVisible = true;
      return;
    }
    io = new IntersectionObserver(
      (entries) => {
        const entry = entries[0];
        const vis = !!entry?.isIntersecting;
        const was = isElementVisible;
        isElementVisible = vis;
        if (vis && !was && themeRebuildPending) {
          scheduleFlush();
        }
      },
      { threshold: 0 }
    );
    io.observe(el.value);
  }
  onMounted(() => {
    observeVisibility();
    build2();
  });
  watch(el, (node, prev) => {
    if (!node || disposed) return;
    if (node !== prev) {
      observeVisibility();
      if (!chart) build2();
    }
  });
  watch(seriesList, updateData);
  watch(
    [
      () => unrefAny(opts.width),
      () => unrefAny(opts.height),
      () => unrefAny(opts.mode),
      () => unrefAny(opts.xMin),
      () => unrefAny(opts.xMax),
      () => unrefAny(opts.timeX),
      () => unrefAny(opts.softMin),
      () => unrefAny(opts.softMax),
      () => unrefAny(opts.spanNulls),
      () => unrefAny(opts.lineWidth),
      () => unrefAny(opts.fillOpacity),
      () => unrefAny(opts.showLegend),
      () => unrefAny(opts.barWidthFactor),
      () => unrefAny(opts.barBucketSize),
      () => unrefAny(opts.xValueLabels),
      () => unrefAny(opts.xTickLabelRotation),
      () => unrefAny(opts.fullHighlight),
      () => unrefAny(opts.xAxisSize),
      () => unrefAny(opts.xAxisGap),
      () => unrefAny(opts.yValueLabels),
      () => unrefAny(opts.gradientMode),
      () => unrefAny(opts.lineInterpolation),
      () => unrefAny(opts.axis),
      () => unrefAny(opts.thresholds),
      () => unrefAny(opts.thresholdsMode),
      () => unrefAny(opts.thresholdsPercent),
      () => unrefAny(opts.showValues),
      () => unrefAny(opts.bands),
      () => unrefAny(opts.tooltipMode),
      () => unrefAny(opts.drawHook),
      () => unrefAny(opts.extraScales),
      () => unrefAny(opts.extraAxes),
      () => unrefAny(opts.thresholdsConfig)
    ],
    () => enqueueFromSnapshot(),
    { deep: true }
  );
  const themeOff = onThemeChange(() => {
    themeToken = isDarkTheme() ? "dark" : "light";
    themeRebuildPending = true;
    pendingOps = mergeUPlotOps(pendingOps, {
      rebuild: true,
      setData: false,
      setSize: false,
      setScale: false,
      setSeries: false
    });
    if (isElementVisible) {
      scheduleFlush();
    } else {
      scheduleIdleThemeRebuild();
    }
  });
  onBeforeUnmount(() => {
    disposed = true;
    themeOff?.();
    io?.disconnect();
    io = null;
    if (flushRaf != null && typeof cancelAnimationFrame === "function") {
      cancelAnimationFrame(flushRaf);
      flushRaf = null;
    }
    if (hoverRaf != null && typeof cancelAnimationFrame === "function") {
      cancelAnimationFrame(hoverRaf);
      hoverRaf = null;
    }
    if (idleHandle != null) {
      const cic = globalThis.cancelIdleCallback;
      if (typeof cic === "function") cic(idleHandle);
      else if (typeof cancelAnimationFrame === "function") {
        cancelAnimationFrame(idleHandle);
      }
      idleHandle = null;
    }
    chart?.destroy();
    chart = null;
  });
  return {
    rebuild: build2,
    getChart: () => chart,
    hover
  };
}
const _hoisted_1$1W = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "histogram"
};
const _hoisted_2$1w = { class: "chart-wrap" };
const _hoisted_3$1l = ["data-empty", "data-bucket-count", "data-bucket-size", "data-bucket-offset", "data-fill-opacity", "data-line-width", "data-gradient", "data-stacking", "data-combine", "data-calc", "data-calc-option", "data-series-count", "data-band-count", "data-legend-show", "data-tooltip-mode"];
const _hoisted_4$1a = {
  key: 0,
  class: "panel-empty",
  "data-testid": "histogram-empty"
};
const _hoisted_5$10 = {
  key: 0,
  class: "legend",
  "data-testid": "histogram-legend",
  "data-placement": "bottom"
};
const _hoisted_6$T = { class: "name" };
const _sfc_main$2F = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    useCssVars((_ctx) => ({
      "a6136edc": chartHeight.value
    }));
    const props = __props;
    const el = ref(null);
    const opts = computed(() => props.options ?? {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    function collectFieldSeries() {
      const rows = [];
      for (const frame of props.data?.series ?? []) {
        for (const f of frame.fields.filter((x) => x.type === "number")) {
          const values = [];
          for (const v of f.values) {
            const n = Number(v);
            if (Number.isFinite(n)) values.push(n);
          }
          if (!values.length) continue;
          const label = getFieldDisplayName(f, frame, props.data?.series);
          const color = getFieldColor(values[values.length - 1] ?? 0, {
            ...props.fieldConfig?.defaults ?? {},
            ...f.config ?? {}
          }) || void 0;
          rows.push({ label, values, color });
        }
      }
      return rows;
    }
    const HISTOGRAM_BUCKET_SIZES = [
      1e-9,
      2e-9,
      25e-10,
      4e-9,
      5e-9,
      1e-8,
      2e-8,
      25e-9,
      4e-8,
      5e-8,
      1e-7,
      2e-7,
      25e-8,
      4e-7,
      5e-7,
      1e-6,
      2e-6,
      25e-7,
      4e-6,
      5e-6,
      1e-5,
      2e-5,
      25e-6,
      4e-5,
      5e-5,
      1e-4,
      2e-4,
      25e-5,
      4e-4,
      5e-4,
      1e-3,
      2e-3,
      25e-4,
      4e-3,
      5e-3,
      0.01,
      0.02,
      0.025,
      0.04,
      0.05,
      0.1,
      0.2,
      0.25,
      0.4,
      0.5,
      1,
      2,
      4,
      5,
      10,
      20,
      25,
      40,
      50,
      100,
      200,
      250,
      400,
      500,
      1e3,
      2e3,
      2500,
      4e3,
      5e3,
      1e4,
      2e4,
      25e3,
      4e4,
      5e4,
      1e5,
      2e5,
      25e4,
      4e5,
      5e5,
      1e6
    ];
    function pickBucketSize(allValues, bucketCount, explicit) {
      if (explicit && explicit > 0) return explicit;
      const sorted = [...allValues].filter((n) => Number.isFinite(n)).sort((a, b) => a - b);
      if (!sorted.length) return 1;
      let smallestDelta = Infinity;
      if (sorted.length === 1) {
        smallestDelta = 1;
      } else {
        for (let i = 1; i < sorted.length; i++) {
          const delta = sorted[i] - sorted[i - 1];
          if (delta !== 0) smallestDelta = Math.min(smallestDelta, delta);
        }
      }
      if (!Number.isFinite(smallestDelta)) smallestDelta = 1;
      const min = sorted[0];
      const max = sorted[sorted.length - 1];
      const range = max - min;
      const targetSize = range / Math.max(bucketCount, 1);
      for (const size of HISTOGRAM_BUCKET_SIZES) {
        if (targetSize < size && size >= smallestDelta) return size;
      }
      return Math.max(smallestDelta, targetSize || 1);
    }
    function isBucketFieldName(name, kind2) {
      const n = String(name);
      if (kind2 === "min") return n === "xMin" || n === "BucketMin";
      return n === "xMax" || n === "BucketMax";
    }
    function originalDataHasHistogram(frames) {
      if (!frames || frames.length !== 1) return false;
      const frame = frames[0];
      const fields = frame?.fields ?? [];
      if (fields.length < 3) return false;
      if (!isBucketFieldName(fields[0]?.name, "min") || !isBucketFieldName(fields[1]?.name, "max")) {
        return false;
      }
      return fields.every((f) => f.type === "number");
    }
    function seriesFromPreBucketedHistogram(frame) {
      const fields = frame.fields ?? [];
      const xMin = fields[0];
      const out = [];
      for (let fi = 2; fi < fields.length; fi++) {
        const f = fields[fi];
        const points = [];
        const n = Math.min(xMin.values.length, f.values.length);
        for (let i = 0; i < n; i++) {
          const x = Number(xMin.values[i]);
          const y = Number(f.values[i]);
          if (Number.isFinite(x) && Number.isFinite(y)) points.push({ x, y });
        }
        if (!points.length) continue;
        const label = getFieldDisplayName(f, frame, [frame]);
        const color = getFieldColor(points[points.length - 1]?.y ?? 0, {
          ...props.fieldConfig?.defaults ?? {},
          ...f.config ?? {}
        }) || void 0;
        out.push({
          label,
          values: points.map((p) => p.y),
          color,
          points
        });
      }
      return out;
    }
    const preBucketed = computed(() => {
      const has = originalDataHasHistogram(props.data?.series);
      const calc = opts.value.__calc__;
      if (calc === false || calc === "false" || calc === "client") return false;
      if (calc === true || calc === "true" || calc === "query") return has;
      return has;
    });
    function bucketizeValues(values, size, offset) {
      const counts = /* @__PURE__ */ new Map();
      for (const n of values) {
        if (!Number.isFinite(n)) continue;
        const bucket = Math.floor((n - offset) / size) * size + offset;
        const key = Math.round(bucket * 1e9) / 1e9;
        counts.set(key, (counts.get(key) ?? 0) + 1);
      }
      return [...counts.entries()].sort((a, b) => a[0] - b[0]).map(([x, y]) => ({ x, y }));
    }
    const series = computed(() => {
      const bucketCount = Math.max(1, Number(opts.value.bucketCount ?? 30));
      const fillOpacity0 = Number(
        opts.value.fillOpacity ?? custom.value.fillOpacity ?? 80
      );
      const lineWidth0 = Number(opts.value.lineWidth ?? custom.value.lineWidth ?? 1);
      if (preBucketed.value) {
        const frame = props.data?.series?.[0];
        const pre = seriesFromPreBucketedHistogram(frame);
        return pre.map((g) => ({
          label: g.label,
          color: g.color || void 0,
          points: g.points ?? [],
          fillOpacity: fillOpacity0,
          lineWidth: lineWidth0
        }));
      }
      const fieldSeries = collectFieldSeries();
      if (!fieldSeries.length) return [];
      const combine = opts.value.combine === true;
      const stackingMode = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? custom.value.stacking?.mode ?? custom.value.stacking ?? "none"
      );
      const fillOpacity = Number(
        opts.value.fillOpacity ?? custom.value.fillOpacity ?? 80
      );
      const lineWidth = Number(opts.value.lineWidth ?? custom.value.lineWidth ?? 1);
      const allNums = fieldSeries.flatMap((s) => s.values);
      const offset = Number(opts.value.bucketOffset ?? 0);
      const size = pickBucketSize(
        allNums,
        bucketCount,
        Number(opts.value.bucketSize) || void 0
      );
      const groups = combine ? [{ label: "count", values: allNums, color: fieldSeries[0]?.color }] : fieldSeries;
      let out = groups.map((g) => {
        const points = bucketizeValues(g.values, size, offset);
        return {
          label: g.label,
          color: g.color || void 0,
          points,
          fillOpacity,
          lineWidth
        };
      });
      if ((stackingMode === "normal" || stackingMode === "percent") && out.length > 1) {
        const xs = /* @__PURE__ */ new Map();
        const totals = /* @__PURE__ */ new Map();
        if (stackingMode === "percent") {
          for (const s of out) {
            for (const p of s.points) {
              if (p.y == null || !Number.isFinite(p.y)) continue;
              totals.set(p.x, (totals.get(p.x) ?? 0) + Math.abs(p.y));
            }
          }
        }
        out = out.map((s) => {
          if ((s.fillOpacity ?? 0) <= 0) s.fillOpacity = 35;
          s.points = s.points.map((p) => {
            if (p.y == null || !Number.isFinite(p.y)) return p;
            let y = p.y;
            if (stackingMode === "percent") {
              const t2 = totals.get(p.x) || 1;
              y = y / t2 * 100;
            }
            const base = xs.get(p.x) ?? 0;
            const stacked = base + y;
            xs.set(p.x, stacked);
            return { x: p.x, y: stacked };
          });
          return s;
        });
      }
      return out;
    });
    const plotBands = computed(() => {
      const stackingMode = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? custom.value.stacking?.mode ?? custom.value.stacking ?? "none"
      );
      if ((stackingMode === "normal" || stackingMode === "percent") && series.value.length > 1) {
        return stackingBandsForSeriesCount(series.value.length, 1);
      }
      return [];
    });
    const width2 = computed(() => props.width || 400);
    const showLegend = computed(() => opts.value.legend?.showLegend !== false);
    const legendReserve = computed(() => showLegend.value ? 32 : 0);
    const height2 = computed(
      () => Math.max((props.height || 200) - legendReserve.value, 40)
    );
    const chartHeight = computed(() => `${height2.value}px`);
    const legendItems = computed(
      () => series.value.map((s) => ({
        label: s.label || "value",
        color: s.color || classicGreen()
      }))
    );
    const barWidthFactor = computed(() => 1);
    const histScale = computed(() => {
      const bucketCount = Math.max(1, Number(opts.value.bucketCount ?? 30));
      Number(opts.value.bucketOffset ?? 0);
      const fieldSeries = collectFieldSeries();
      const allNums = fieldSeries.flatMap((s) => s.values);
      const size = pickBucketSize(
        allNums,
        bucketCount,
        Number(opts.value.bucketSize) || void 0
      );
      const xs = series.value.flatMap((s) => s.points.map((p) => Number(p.x))).filter((n) => Number.isFinite(n));
      if (!xs.length || !Number.isFinite(size) || size <= 0) {
        return {
          bucketSize: size || 1,
          xMin: void 0,
          xMax: void 0
        };
      }
      const minX = Math.min(...xs);
      const maxX = Math.max(...xs);
      return { bucketSize: size, xMin: minX, xMax: maxX + size };
    });
    const softMax = computed(() => {
      const stackingMode = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? custom.value.stacking?.mode ?? custom.value.stacking ?? "none"
      );
      return stackingMode === "percent" ? 100 : void 0;
    });
    const softMin = computed(() => 0);
    const noData = computed(() => {
      if (props.data?.state === "Loading" || props.data?.error) return false;
      return !series.value.length || series.value.every(
        (s) => !s.points.some((p) => p.y != null && Number.isFinite(p.y))
      );
    });
    const seriesCount = computed(() => series.value.length);
    function histogramXSplits(u, _axisIdx, _scaleMin, _scaleMax, _foundIncr, _foundSpace) {
      const bucketSize = histScale.value.bucketSize;
      if (!bucketSize || bucketSize <= 0) return [];
      const dataX = u.data?.[0] || [];
      if (!dataX.length) return [];
      const xScaleMin = histScale.value.xMin ?? dataX[0];
      const xScaleMax = histScale.value.xMax ?? dataX[dataX.length - 1] + bucketSize;
      const firstSplit = Math.floor(xScaleMin / bucketSize) * bucketSize;
      const lastSplit = Math.ceil(xScaleMax / bucketSize) * bucketSize;
      const minSpace = u.axes?.[_axisIdx]?._space ?? 40;
      const bucketWidth = Math.abs(
        u.valToPos(dataX[0] + bucketSize, "x") - u.valToPos(dataX[0], "x")
      );
      const skip = Math.max(1, Math.ceil(minSpace / Math.max(bucketWidth, 1)));
      const splits = [];
      for (let i = 0, s = firstSplit; s <= lastSplit + bucketSize * 1e-9; i++, s += bucketSize) {
        if (i % skip === 0) splits.push(Number(s.toPrecision(12)));
      }
      return splits;
    }
    useUPlot(el, series, {
      width: width2,
      height: height2,
      mode: "bars",
      timeX: false,
      showLegend: false,
      barWidthFactor,
      barBucketSize: computed(() => histScale.value.bucketSize),
      xMin: computed(() => histScale.value.xMin),
      xMax: computed(() => histScale.value.xMax),
      xSplits: histogramXSplits,
      softMin,
      softMax,
      bands: plotBands,
      // Dual-run: +1px axis size shifts left grid 36→37; gap 4 pulls y labels left to match Grafana
      axis: { width: 28, gap: 5 },
      gradientMode: computed(
        () => String(opts.value.gradientMode ?? custom.value.gradientMode ?? "none")
      )
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1W, [
        createElementVNode(
          "div",
          {
            class: normalizeClass(["hist", { "legend-bottom": showLegend.value }])
          },
          [
            createElementVNode("div", _hoisted_2$1w, [
              createElementVNode("div", {
                ref_key: "el",
                ref: el,
                class: "chart",
                "data-testid": "histogram-panel",
                "data-empty": String(noData.value),
                "data-bucket-count": String(opts.value.bucketCount ?? 30),
                "data-bucket-size": String(opts.value.bucketSize ?? ""),
                "data-bucket-offset": String(opts.value.bucketOffset ?? 0),
                "data-fill-opacity": String(opts.value.fillOpacity ?? custom.value.fillOpacity ?? 80),
                "data-line-width": String(opts.value.lineWidth ?? custom.value.lineWidth ?? 1),
                "data-gradient": String(opts.value.gradientMode ?? custom.value.gradientMode ?? "none"),
                "data-stacking": String(
                  opts.value.stacking?.mode ?? opts.value.stacking ?? custom.value.stacking?.mode ?? custom.value.stacking ?? "none"
                ),
                "data-combine": String(!!opts.value.combine),
                "data-calc": preBucketed.value ? "query" : "client",
                "data-calc-option": String(opts.value.__calc__ ?? ""),
                "data-series-count": String(seriesCount.value),
                "data-band-count": String(plotBands.value.length),
                "data-legend-show": String(showLegend.value),
                "data-tooltip-mode": String(opts.value.tooltip?.mode ?? "single")
              }, null, 8, _hoisted_3$1l),
              noData.value ? (openBlock(), createElementBlock("div", _hoisted_4$1a, [..._cache[0] || (_cache[0] = [
                createElementVNode(
                  "p",
                  { class: "panel-empty__msg" },
                  "回复中未找到直方图",
                  -1
                  /* CACHED */
                )
              ])])) : createCommentVNode("v-if", true)
            ]),
            showLegend.value && !noData.value ? (openBlock(), createElementBlock("ul", _hoisted_5$10, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(legendItems.value, (s, i) => {
                  return openBlock(), createElementBlock("li", {
                    key: i,
                    "data-testid": "histogram-legend-item"
                  }, [
                    createElementVNode(
                      "i",
                      {
                        class: "legend-swatch",
                        style: normalizeStyle({ background: s.color })
                      },
                      null,
                      4
                      /* STYLE */
                    ),
                    createElementVNode(
                      "span",
                      _hoisted_6$T,
                      toDisplayString(s.label),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])) : createCommentVNode("v-if", true)
          ],
          2
          /* CLASS */
        )
      ]);
    };
  }
});
const Panel$h = /* @__PURE__ */ _export_sfc(_sfc_main$2F, [["__scopeId", "data-v-6eb6d08f"]]);
new VuePanelPlugin(
  {
    id: "histogram",
    name: "直方图",
    description: "数值分布直方图",
    state: "stable",
    skipDataQuery: false
  },
  Panel$h
).useFieldConfig({
  useCustomConfig: (builder) => {
    const cat = ["直方图"];
    builder.addRadio(
      {
        id: "custom.stacking",
        path: "custom.stacking",
        name: "堆叠",
        category: cat,
        settings: {
          options: [
            { label: "关闭", value: "none" },
            { label: "普通", value: "normal" },
            { label: "百分比", value: "percent" }
          ]
        }
      },
      "none"
    ).addSlider(
      {
        id: "custom.lineWidth",
        path: "custom.lineWidth",
        name: "线宽",
        category: cat,
        settings: { min: 0, max: 10, step: 1 }
      },
      1
    ).addSlider(
      {
        id: "custom.fillOpacity",
        path: "custom.fillOpacity",
        name: "填充不透明度",
        category: cat,
        settings: { min: 0, max: 100, step: 1 }
      },
      80
    ).addRadio(
      {
        id: "custom.gradientMode",
        path: "custom.gradientMode",
        name: "渐变模式",
        category: cat,
        settings: {
          options: [
            { label: "无", value: "none" },
            { label: "不透明度", value: "opacity" },
            { label: "色相", value: "hue" },
            { label: "色板", value: "scheme" }
          ]
        }
      },
      "none"
    ).addCustom({
      id: "custom.hideFrom",
      path: "custom.hideFrom",
      name: "隐藏",
      category: ["Series"],
      editor: "text",
      isCustom: true
    });
  }
}).setPanelOptions((builder) => {
  const cat = ["直方图"];
  builder.addText(
    {
      id: "__calc__",
      path: "__calc__",
      name: "数值",
      description: "查询已返回直方图频率时显示",
      category: cat
    },
    void 0
  ).addNumber(
    {
      id: "bucketCount",
      path: "bucketCount",
      name: "分桶数",
      description: "自动分桶时的目标桶数量",
      category: cat,
      settings: { min: 0, placeholder: "默认: 30" }
    },
    30
  ).addNumber(
    {
      id: "bucketSize",
      path: "bucketSize",
      name: "桶大小",
      description: "固定桶宽；留空则自动",
      category: cat,
      settings: { min: 0, placeholder: "自动" }
    },
    void 0
  ).addNumber(
    {
      id: "bucketOffset",
      path: "bucketOffset",
      name: "桶偏移",
      category: cat,
      settings: { min: 0, placeholder: "默认: 0" }
    },
    0
  ).addBoolean(
    {
      id: "combine",
      path: "combine",
      name: "合并序列",
      description: "将所有序列合并为一个直方图",
      category: cat
    },
    false
  ).addRadio(
    {
      id: "stacking",
      path: "stacking",
      name: "堆叠",
      category: cat,
      settings: {
        options: [
          { label: "关闭", value: "none" },
          { label: "普通", value: "normal" },
          { label: "百分比", value: "percent" }
        ]
      }
    },
    "none"
  ).addSlider(
    {
      id: "lineWidth",
      path: "lineWidth",
      name: "线宽",
      category: cat,
      settings: { min: 0, max: 10, step: 1 }
    },
    1
  ).addSlider(
    {
      id: "fillOpacity",
      path: "fillOpacity",
      name: "填充不透明度",
      category: cat,
      settings: { min: 0, max: 100, step: 1 }
    },
    80
  ).addRadio(
    {
      id: "gradientMode",
      path: "gradientMode",
      name: "渐变模式",
      category: cat,
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "不透明度", value: "opacity" },
          { label: "色相", value: "hue" },
          { label: "色板", value: "scheme" }
        ]
      }
    },
    "none"
  );
  addTooltipOptions(builder);
  addLegendOptions(builder, true, true);
}).setRuntimeConsumedPaths([
  "__calc__",
  "bucketCount",
  "bucketSize",
  "bucketOffset",
  "combine",
  "stacking",
  "lineWidth",
  "fillOpacity",
  "gradientMode",
  "legend.showLegend",
  "tooltip.mode",
  "custom.lineWidth",
  "custom.fillOpacity",
  "custom.gradientMode",
  "custom.stacking"
]).register();
function clusterAnnotations(rawIn, opts = {}) {
  const clustering = opts.clustering !== false && opts.clustering !== 0;
  const multiLane = !!opts.multiLane;
  const raw = rawIn.map((a, i) => ({
    ...a,
    time: Number(a.time),
    timeEnd: a.timeEnd != null ? Number(a.timeEnd) : void 0,
    title: a.title ?? a.text ?? "annotation",
    color: a.color || classicYellow(),
    index: a.index ?? i
  })).filter((a) => Number.isFinite(a.time));
  if (!clustering || raw.length <= 1) {
    return raw.map((a, i) => ({
      ...a,
      lane: multiLane ? i % 3 : 0,
      count: 1,
      items: [a]
    }));
  }
  const sorted = [...raw].sort((a, b) => a.time - b.time);
  const times = sorted.map((a) => a.time);
  const span = times.length ? Math.max(...times) - Math.min(...times) : 0;
  const thr = Math.max(span * 0.01, 6e4);
  const groups = [];
  for (const a of sorted) {
    const g = groups[groups.length - 1];
    if (g && Math.abs(a.time - g[0].time) <= thr) g.push(a);
    else groups.push([a]);
  }
  return groups.map((g, gi) => {
    const head = g[0];
    return {
      ...head,
      title: g.length > 1 ? `${g.length} 条注解` : head.title,
      text: g.length > 1 ? g.map((x) => x.title).join(", ") : head.text,
      count: g.length,
      items: g,
      lane: multiLane ? gi % 3 : 0
    };
  });
}
function clampTooltipPosition(opts) {
  const tw = Math.max(40, opts.tooltipWidth ?? 160);
  const th = Math.max(24, opts.tooltipHeight ?? 64);
  const ox = opts.offsetX;
  const oy = opts.offsetY;
  const cw = Math.max(1, opts.containerWidth);
  const ch = Math.max(1, opts.containerHeight);
  let left = opts.cursorLeft + ox;
  let top = opts.cursorTop + oy;
  if (left + tw > cw) {
    left = opts.cursorLeft - tw - Math.abs(ox) / 2;
  }
  if (top + th > ch) {
    top = opts.cursorTop - th - 4;
  }
  left = Math.max(0, Math.min(left, Math.max(0, cw - tw)));
  top = Math.max(0, Math.min(top, Math.max(0, ch - th)));
  return { left, top };
}
function hasNegSample$1(data, samples = 100) {
  const len = data.length;
  if (len === 0) return false;
  let firstIdx = 0;
  let lastIdx = len - 1;
  while (firstIdx <= lastIdx && data[firstIdx] == null) firstIdx++;
  while (lastIdx >= firstIdx && data[lastIdx] == null) lastIdx--;
  if (lastIdx < firstIdx) return false;
  let negCount = 0;
  let posCount = 0;
  const stride = Math.max(1, Math.floor((lastIdx - firstIdx + 1) / samples));
  for (let i = firstIdx; i <= lastIdx; i += stride) {
    const v = data[i];
    if (v != null && typeof v === "number") {
      if (v < 0 || Object.is(v, -0)) negCount++;
      else if (v > 0) posCount++;
    }
  }
  return negCount > posCount;
}
function getStackDirection(transform, values) {
  const hasNeg = hasNegSample$1(values ?? []);
  const t2 = String(transform || "");
  const isNegY = t2 === "negative-Y" || t2 === "negativeY" || t2 === "NegativeY";
  if (isNegY) return hasNeg ? 1 : -1;
  return hasNeg ? -1 : 1;
}
function buildScaleKey(f) {
  return [f.unit ?? "", f.softMin ?? "", f.softMax ?? ""].join("|");
}
function getStackingGroups(fields) {
  const groups = /* @__PURE__ */ new Map();
  for (const f of fields) {
    if (f.hideFromViz) continue;
    const mode2 = String(f.stackingMode ?? "none");
    if (!mode2 || mode2 === "none" || mode2 === "off") continue;
    const dir = getStackDirection(f.transform, f.values);
    const groupName = f.stackingGroup ?? "A";
    const drawStyle = f.drawStyle ?? "line";
    const drawStyle2 = f.drawStyle2 ?? null;
    const stackKey = `${dir}|${mode2}|${groupName}|${buildScaleKey(f)}|${drawStyle}|${drawStyle2}`;
    let group = groups.get(stackKey);
    if (!group) {
      group = { series: [], dir };
      groups.set(stackKey, group);
    }
    group.series.push(f.index);
  }
  return [...groups.values()];
}
function toUPlotSeriesIndices(group) {
  return group.series.map((i) => i + 1);
}
function hasNegSample(data, samples = 100) {
  const len = data.length;
  if (len === 0) return false;
  let firstIdx = 0;
  let lastIdx = len - 1;
  while (firstIdx <= lastIdx && data[firstIdx] == null) firstIdx++;
  while (lastIdx >= firstIdx && data[lastIdx] == null) lastIdx--;
  if (lastIdx < firstIdx) return false;
  let negCount = 0;
  let posCount = 0;
  const stride = Math.max(1, Math.floor((lastIdx - firstIdx + 1) / samples));
  for (let i = firstIdx; i <= lastIdx; i += stride) {
    const v = data[i];
    if (v != null && typeof v === "number") {
      if (v < 0 || Object.is(v, -0)) negCount++;
      else if (v > 0) posCount++;
    }
  }
  return negCount > posCount;
}
function getStackDirectionFromValues(transform, data) {
  const hasNeg = hasNegSample(data);
  const t2 = String(transform || "");
  const isNegY = t2 === "negative-Y" || t2 === "negativeY" || t2 === "NegativeY";
  if (isNegY) {
    return hasNeg ? 1 : -1;
  }
  return hasNeg ? -1 : 1;
}
function buildScaleKeyFromField(field) {
  const cfg = field.config ?? {};
  const custom = cfg.custom ?? {};
  const unit = cfg.unit ?? "short";
  const min = cfg.min ?? "na";
  const max = cfg.max ?? "na";
  const softMin = custom.axisSoftMin ?? "na";
  const softMax = custom.axisSoftMax ?? "na";
  const placement = custom.axisPlacement ?? "auto";
  const dist = custom.scaleDistribution?.type ? custom.scaleDistribution.type === "log" ? `log${custom.scaleDistribution.log ?? ""}` : custom.scaleDistribution.type : "linear";
  const label = custom.axisLabel ? custom.axisLabel : "na";
  return `${unit}/${min}-${max}/${softMin}-${softMax}/${placement}/${dist}/${label}/${field.type}`;
}
function getStackingGroupsFromFrame(frame) {
  const groups = /* @__PURE__ */ new Map();
  frame.fields.forEach((field, i) => {
    if (i === 0) return;
    const custom = field.config?.custom;
    if (custom == null) return;
    if (custom.hideFrom?.viz) return;
    const stacking = custom.stacking;
    if (stacking == null) return;
    const stackingMode = String(stacking.mode ?? "none");
    if (!stackingMode || stackingMode === "none" || stackingMode === "None")
      return;
    const transform = custom.transform;
    const stackDir = getStackDirectionFromValues(
      transform,
      field.values
    );
    const stackingGroup = stacking.group ?? "A";
    const drawStyle = custom.drawStyle ?? "line";
    const drawStyle2 = drawStyle === "bars" ? custom.barAlignment ?? null : drawStyle === "line" ? custom.lineInterpolation ?? null : null;
    const stackKey = `${stackDir}|${stackingMode}|${stackingGroup}|${buildScaleKeyFromField(field)}|${drawStyle}|${drawStyle2}`;
    let group = groups.get(stackKey);
    if (!group) {
      group = { series: [], dir: stackDir };
      groups.set(stackKey, group);
    }
    group.series.push(i);
  });
  return [...groups.values()];
}
function preparePlotData2(frame, stackingGroups, onStackMeta) {
  if (!stackingGroups.length) {
    let needsWork = false;
    for (let fi = 1; fi < frame.fields.length; fi++) {
      const custom = frame.fields[fi]?.config?.custom;
      if (!custom) continue;
      const transform = String(custom.transform ?? "");
      if (transform === "constant" || transform === "Constant" || transform === "negative-Y" || transform === "negativeY" || transform === "NegativeY") {
        needsWork = true;
        break;
      }
    }
    if (!needsWork) {
      const out = frame.fields.map((f) => f.values);
      return out;
    }
  }
  const data = Array(frame.fields.length);
  const stacksQty = stackingGroups.length;
  const dataLen = frame.length ?? frame.fields[0]?.values?.length ?? 0;
  const zeroArr = stacksQty > 0 ? Array(dataLen).fill(0) : [];
  const falseArr = stacksQty > 0 ? Array(dataLen).fill(false) : [];
  const accums = Array.from(
    { length: stacksQty },
    () => zeroArr.slice()
  );
  const anyValsAtX = Array.from(
    { length: stacksQty },
    () => falseArr.slice()
  );
  stackingGroups.forEach((group, groupIdx) => {
    const groupValsAtX = anyValsAtX[groupIdx];
    group.series.forEach((seriesIdx) => {
      const field = frame.fields[seriesIdx];
      if (field?.config?.custom?.hideFrom?.viz) return;
      const vals = field.values;
      for (let i = 0; i < dataLen; i++) {
        if (vals[i] != null) groupValsAtX[i] = true;
      }
    });
  });
  frame.fields.forEach((field, fi) => {
    let vals = field.values.slice();
    if (fi === 0) {
      data[fi] = vals;
      return;
    }
    const custom = field.config?.custom;
    if (!custom || custom.hideFrom?.viz) {
      data[fi] = vals;
      return;
    }
    const transform = String(custom.transform ?? "");
    if (transform === "constant" || transform === "Constant") {
      const firstValIdx = vals.findIndex((v) => v != null);
      const firstVal = vals[firstValIdx];
      vals = Array(vals.length).fill(void 0);
      if (firstValIdx >= 0) vals[firstValIdx] = firstVal;
    } else if (transform === "negative-Y" || transform === "negativeY" || transform === "NegativeY") {
      vals = vals.slice();
      for (let i = 0; i < vals.length; i++) {
        if (vals[i] != null) vals[i] = Number(vals[i]) * -1;
      }
    }
    const stackingMode = custom.stacking?.mode;
    if (!stackingMode || stackingMode === "none" || stackingMode === "None") {
      data[fi] = vals;
    } else {
      const stackIdx = stackingGroups.findIndex(
        (group) => group.series.indexOf(fi) > -1
      );
      const accum = accums[stackIdx];
      const groupValsAtX = anyValsAtX[stackIdx];
      const stacked = data[fi] = Array(dataLen);
      for (let i = 0; i < dataLen; i++) {
        const v = vals[i];
        if (v != null) {
          stacked[i] = accum[i] += Number(v);
        } else {
          stacked[i] = groupValsAtX[i] ? accum[i] : v;
        }
      }
    }
  });
  frame.fields.forEach((field, fi) => {
    if (fi === 0 || field.config?.custom?.hideFrom?.viz) return;
    const stackingMode = field.config?.custom?.stacking?.mode;
    if (stackingMode === "percent" || stackingMode === "Percent") {
      const stackIdx = stackingGroups.findIndex(
        (group2) => group2.series.indexOf(fi) > -1
      );
      if (stackIdx < 0) return;
      const accum = accums[stackIdx];
      const group = stackingGroups[stackIdx];
      const stacked = data[fi];
      for (let i = 0; i < dataLen; i++) {
        const v = stacked[i];
        if (v != null) {
          stacked[i] = accum[i] === 0 ? 0 : group.dir * (Number(v) / accum[i]);
        }
      }
    }
  });
  return data;
}
const _hoisted_1$1V = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "timeseries"
};
const _hoisted_2$1v = ["data-tooltip-mode", "data-tooltip-sort", "data-draw-style", "data-line-interp", "data-gradient", "data-axis-placement", "data-show-values", "data-thresholds-mode", "data-hover-proximity", "data-tooltip-max-width", "data-tooltip-max-height", "data-axis-color-mode", "data-axis-width", "data-bar-alignment", "data-fill-below-to", "data-line-style", "data-insert-nulls", "data-legend-limit", "data-legend-overflow", "data-legend-width", "data-legend-show", "data-legend-display-mode", "data-legend-placement", "data-legend-faceted", "data-tooltip-hide-zeros", "data-anno-clustering", "data-anno-multi-lane"];
const _hoisted_3$1k = { class: "chart-wrap" };
const _hoisted_4$19 = ["data-mode", "data-tt-left", "data-tt-top"];
const _hoisted_5$$ = {
  key: 0,
  class: "tt-mirror",
  "data-testid": "uplot-tooltip-y-axis",
  "aria-hidden": "true"
};
const _hoisted_6$S = ["data-series-index", "data-color"];
const _hoisted_7$Q = {
  class: "tt-mirror",
  "data-testid": "uplot-tooltip-time",
  "aria-hidden": "true"
};
const _hoisted_8$H = {
  key: 1,
  class: "anno-layer",
  "data-testid": "timeseries-annotations"
};
const _hoisted_9$E = ["title", "data-anno-index", "data-count", "data-lane", "onMouseenter", "onFocus"];
const _hoisted_10$y = {
  key: 0,
  class: "anno-tip",
  "data-testid": "anno-tooltip"
};
const _hoisted_11$s = { key: 0 };
const _hoisted_12$m = { class: "ts-val" };
const _hoisted_13$l = ["data-faceted-keys"];
const _hoisted_14$j = ["data-facet-key"];
const _hoisted_15$e = { class: "faceted-key" };
const _hoisted_16$d = ["data-facet-value"];
const _hoisted_17$c = ["checked", "onChange"];
const _hoisted_18$c = ["data-placement", "data-mode", "data-scroll-x", "data-scroll-y", "data-calcs", "data-item-count"];
const _hoisted_19$c = ["data-series", "data-index", "onClick"];
const _hoisted_20$b = {
  class: "name",
  "data-testid": "legend-name"
};
const _hoisted_21$a = {
  key: 0,
  class: "stats",
  "data-testid": "legend-stats"
};
const _sfc_main$2E = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  emits: ["inspect", "fullscreen", "edit", "view", "duplicate", "remove", "share", "explore", "copy", "toggleLegend", "help", "copyStyles", "pasteStyles", "timeSettings", "libraryPanel", "unlinkLibrary", "alertRule"],
  setup(__props, { emit: __emit }) {
    useCssVars((_ctx) => ({
      "v2af07064": chartHeightCss.value,
      "v4431d96a": legendMaxHeightCss.value,
      "v88a9c4ca": legendWidthPx.value
    }));
    function arrMin(a) {
      let m = Infinity;
      for (let i = 0; i < a.length; i++) {
        const v = a[i];
        if (v != null && v < m) m = v;
      }
      return m;
    }
    function arrMax(a) {
      let m = -Infinity;
      for (let i = 0; i < a.length; i++) {
        const v = a[i];
        if (v != null && v > m) m = v;
      }
      return m;
    }
    const props = __props;
    const chartEl = ref(null);
    const hoverAnno = ref(
      null
    );
    const hiddenSeries = ref(/* @__PURE__ */ new Set());
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    const panelOpts = computed(() => props.options ?? {});
    const showAnnotations = computed(
      () => panelOpts.value?.annotations?.show !== false
    );
    function fieldCustom(field) {
      return { ...custom.value, ...field.config?.custom ?? {} };
    }
    function seriesColorForField(field, cfg, seriesIndex) {
      const mode2 = cfg?.color?.mode ?? field.config?.color?.mode;
      if (mode2 === "fixed" && (cfg?.color?.fixedColor || field.config?.color?.fixedColor)) {
        return getFieldColor(0, cfg) || getFieldSeriesColor(String(field.name || "series"), seriesIndex, cfg);
      }
      if (!mode2 || mode2 === "palette-classic" || mode2 === "palette-classic-by-name") {
        return getFieldSeriesColor(String(field.name || "series"), seriesIndex, {
          ...cfg,
          color: { mode: "palette-classic" }
        });
      }
      const last = Number(
        field.values?.[field.values?.length - 1] ?? 0
      );
      return getFieldColor(last, cfg) || getFieldSeriesColor(String(field.name || "series"), seriesIndex, cfg);
    }
    const annotations = computed(() => {
      if (!showAnnotations.value) return [];
      const list = (props.data?.annotations ?? []).map((a, i) => ({
        time: Number(a.time),
        timeEnd: a.timeEnd != null ? Number(a.timeEnd) : void 0,
        title: a.title ?? a.text ?? "annotation",
        text: a.text,
        color: a.color || classicYellow(),
        tags: a.tags ?? [],
        index: i
      }));
      return clusterAnnotations(list, {
        clustering: panelOpts.value?.annotations?.clustering,
        multiLane: !!panelOpts.value?.annotations?.multiLane
      });
    });
    const chartMode = computed(() => {
      const style = String(custom.value.drawStyle ?? "line");
      if (style === "bars") return "bars";
      if (style === "points") return "points";
      if (Number(custom.value.fillOpacity ?? 0) > 0) return "area";
      return "line";
    });
    const series = computed(() => {
      const out = [];
      const stackingMode = normalizeStacking(custom.value.stacking).mode;
      const fillBelowTo = custom.value.fillBelowTo ? String(custom.value.fillBelowTo) : "";
      for (let _frameIdx = 0; _frameIdx < (props.data?.series ?? []).length; _frameIdx++) {
        const frame = (props.data?.series ?? [])[_frameIdx];
        const time = frame.fields.find((f) => f.type === "time");
        if (!time) continue;
        for (const field of frame.fields.filter((f) => f.type === "number")) {
          const fc = fieldCustom(field);
          const hideFrom = normalizeHideFrom(fc.hideFrom);
          if (hideFrom.viz === true) continue;
          const cfg = { ...props.fieldConfig?.defaults ?? {}, ...field.config };
          const label = getFieldDisplayName(field, frame, props.data?.series);
          let points = time.values.map((t2, i) => {
            const raw = field.values[i];
            const y = raw == null || typeof raw === "number" && !Number.isFinite(raw) || Number.isNaN(Number(raw)) ? null : Number(raw);
            return { x: Number(t2), y };
          });
          const transform = String(fc.transform ?? "");
          let constantY;
          if (transform === "negative-Y" || transform === "negativeY") {
            points = points.map((p) => ({
              ...p,
              y: p.y == null || Number.isNaN(p.y) ? p.y : -p.y
            }));
          } else if (transform === "constant") {
            const first = points.find(
              (p) => p.y != null && Number.isFinite(p.y)
            );
            if (first) constantY = first.y;
          }
          const insertNullsVal = fc.insertNulls ?? custom.value.insertNulls;
          if (insertNullsVal) {
            points = applyInsertNulls(
              points.filter((p) => p.y != null),
              insertNullsVal
            );
          }
          const spanNullsVal = fc.spanNulls ?? custom.value.spanNulls;
          if (typeof spanNullsVal === "number" && spanNullsVal > 0) {
            points = applySpanNullsThreshold(points, spanNullsVal);
          }
          const fieldFillBelow = String(fc.fillBelowTo ?? fillBelowTo ?? "");
          let fillOpacity = Number(fc.fillOpacity ?? custom.value.fillOpacity ?? 0);
          if (fieldFillBelow && fillOpacity <= 0) {
            fillOpacity = 35;
          }
          out.push({
            label,
            labels: { ...field.labels ?? {} },
            frameName: String(frame.name ?? frame.refId ?? ""),
            color: seriesColorForField(field, cfg, out.length),
            points,
            lineWidth: Number(fc.lineWidth ?? custom.value.lineWidth ?? 1),
            fillOpacity,
            spanNulls: fc.spanNulls ?? custom.value.spanNulls,
            showPoints: String(
              fc.showPoints ?? custom.value.showPoints ?? "auto"
            ),
            pointSize: Number(fc.pointSize ?? custom.value.pointSize ?? 5),
            showValues: Boolean(fc.showValues ?? custom.value.showValues),
            lineStyle: fc.lineStyle ?? custom.value.lineStyle ?? "solid",
            lineInterpolation: String(
              fc.lineInterpolation ?? custom.value.lineInterpolation ?? "linear"
            ),
            hidden: hiddenSeries.value.has(label),
            hideLegend: hideFrom.legend === true,
            hideTooltip: hideFrom.tooltip === true,
            constantY,
            // used by plotBands (1-based uPlot series index pairing)
            fillBelowTo: fieldFillBelow || void 0,
            fieldName: field.name,
            displayNameFromDS: field.config?.displayNameFromDS,
            _frameIdx,
            stackingMode: normalizeStacking(fc.stacking ?? stackingMode).mode,
            stackingGroup: String(
              fc.stacking?.group ?? custom.value.stacking?.group ?? "A"
            ),
            transform: String(fc.transform ?? ""),
            unit: String(cfg.unit ?? ""),
            drawStyle: String(
              fc.drawStyle ?? custom.value.drawStyle ?? "line"
            ),
            barAlignment: Number(
              fc.barAlignment ?? custom.value.barAlignment ?? 0
            ),
            barWidthFactor: Number(
              fc.barWidthFactor ?? custom.value.barWidthFactor ?? 0.6
            ),
            gradientMode: String(
              fc.gradientMode ?? custom.value.gradientMode ?? "none"
            ),
            scale: (() => {
              const fakeField = {
                name: field.name,
                type: field.type,
                config: {
                  unit: cfg.unit,
                  min: cfg.min,
                  max: cfg.max,
                  custom: {
                    ...custom.value,
                    ...fc
                  }
                }
              };
              const key = buildScaleKeyFromField(fakeField);
              const placement = String(
                fc.axisPlacement ?? custom.value.axisPlacement ?? "auto"
              );
              if (placement === "auto" || placement === "left" || placement === "hidden") {
                const defKey = buildScaleKeyFromField({
                  type: "number",
                  config: {
                    unit: props.fieldConfig?.defaults?.unit,
                    custom: { ...custom.value, axisPlacement: "auto" }
                  }
                });
                if (key === defKey || placement === "hidden") return "y";
              }
              return key;
            })(),
            axisPlacement: String(
              fc.axisPlacement ?? custom.value.axisPlacement ?? "auto"
            ),
            axisLabel: String(fc.axisLabel ?? custom.value.axisLabel ?? ""),
            drawStyle2: String(fc.drawStyle ?? custom.value.drawStyle ?? "line") === "bars" ? fc.barAlignment ?? custom.value.barAlignment ?? 0 : String(
              fc.lineInterpolation ?? custom.value.lineInterpolation ?? "linear"
            )
          });
        }
      }
      if (stackingMode === "normal" || stackingMode === "percent") {
        const seriesMeta = out;
        const byFrame = /* @__PURE__ */ new Map();
        seriesMeta.forEach((s, _i) => {
          const fi = s._frameIdx;
          if (fi == null) return;
          if (!byFrame.has(fi)) byFrame.set(fi, []);
          byFrame.get(fi).push(s);
        });
        let usedPrepare = false;
        if (byFrame.size > 0) {
          for (const [, members] of byFrame) {
            if (members.length < 2) continue;
            const xs = /* @__PURE__ */ new Set();
            for (const s of members) for (const p of s.points) xs.add(p.x);
            const xArr = [...xs].sort((a, b) => a - b);
            const fields = [{ name: "time", type: "time", values: xArr }];
            for (const s of members) {
              const yByX = new Map(s.points.map((p) => [p.x, p.y]));
              fields.push({
                name: s.fieldName || s._fieldName || s.label,
                type: "number",
                values: xArr.map((x) => {
                  const y = yByX.get(x);
                  return y == null || !Number.isFinite(y) ? null : y;
                }),
                config: {
                  unit: s.unit,
                  custom: {
                    stacking: {
                      mode: s.stackingMode || stackingMode,
                      group: s.stackingGroup || "A"
                    },
                    transform: s.transform,
                    drawStyle: s.drawStyle,
                    hideFrom: s.hidden ? { viz: true } : void 0
                  }
                }
              });
            }
            const df = createDataFrame({ fields });
            const groups = getStackingGroupsFromFrame(df);
            const aligned = preparePlotData2(
              df,
              groups.length ? groups : getStackingGroupsFromFrame(df)
            );
            members.forEach((s, mi) => {
              const stacked = aligned[mi + 1] || [];
              if ((s.fillOpacity ?? 0) <= 0) s.fillOpacity = 35;
              const isPct = stackingMode === "percent";
              s.points = xArr.map((x, i) => {
                let y = stacked[i];
                if (y == null || !Number.isFinite(Number(y))) return { x, y: null };
                if (isPct) y = Number(y) * 100;
                return { x, y: Number(y) };
              });
            });
            usedPrepare = true;
          }
        }
        if (!usedPrepare) {
          const groups = getStackingGroups(
            seriesMeta.map((s, index2) => ({
              index: index2,
              stackingMode: s.stackingMode ?? stackingMode,
              stackingGroup: s.stackingGroup ?? "A",
              transform: s.transform,
              unit: s.unit,
              drawStyle: s.drawStyle,
              drawStyle2: s.drawStyle2,
              hideFromViz: !!s.hidden,
              values: s.points.map((p) => p.y == null ? null : Number(p.y))
            }))
          );
          const effective = groups.length > 0 ? groups : out.length > 1 ? [{ series: out.map((_, i) => i), dir: 1 }] : [];
          for (const g of effective) {
            const members = g.series.map((i) => seriesMeta[i]).filter(Boolean);
            const totals = /* @__PURE__ */ new Map();
            if (stackingMode === "percent") {
              for (const s of members) {
                for (const p of s.points) {
                  if (p.y == null || !Number.isFinite(p.y)) continue;
                  totals.set(p.x, (totals.get(p.x) ?? 0) + Math.abs(p.y));
                }
              }
            }
            const xs = /* @__PURE__ */ new Map();
            for (const s of members) {
              if ((s.fillOpacity ?? 0) <= 0) s.fillOpacity = 35;
              s.points = s.points.map((p) => {
                if (p.y == null || !Number.isFinite(p.y)) return p;
                let y = p.y;
                if (stackingMode === "percent") {
                  const tot = totals.get(p.x) || 1;
                  y = y / tot * 100;
                }
                const signed = g.dir === -1 ? -Math.abs(y) : y;
                const base = xs.get(p.x) ?? 0;
                const stacked = base + signed;
                xs.set(p.x, stacked);
                return { x: p.x, y: stacked };
              });
            }
          }
        }
      }
      return out;
    });
    const legendItems = computed(() => {
      const calcs = panelOpts.value?.legend?.calcs ?? [];
      const limit = Number(panelOpts.value?.legend?.limit ?? 0);
      let list = series.value.filter((s) => !s.hideLegend);
      if (Number.isFinite(limit) && limit > 0) list = list.slice(0, limit);
      return list.map((s) => {
        const vals = s.points.map((p) => p.y).filter((y) => y != null && Number.isFinite(y));
        const stats = [];
        const fmt = (n) => Math.abs(n) >= 1e3 || Math.abs(n) < 0.01 ? n.toPrecision(4) : n.toFixed(2);
        if ((calcs.includes("min") || calcs.includes("minNotNull")) && vals.length)
          stats.push(`min ${fmt(arrMin(vals))}`);
        if ((calcs.includes("max") || calcs.includes("maxNotNull")) && vals.length)
          stats.push(`max ${fmt(arrMax(vals))}`);
        if ((calcs.includes("mean") || calcs.includes("avg")) && vals.length) {
          stats.push(`mean ${fmt(vals.reduce((a, b) => a + b, 0) / vals.length)}`);
        }
        if ((calcs.includes("last") || calcs.includes("lastNotNull")) && vals.length)
          stats.push(`last ${fmt(vals[vals.length - 1])}`);
        if ((calcs.includes("first") || calcs.includes("firstNotNull")) && vals.length)
          stats.push(`first ${fmt(vals[0])}`);
        if (calcs.includes("sum") && vals.length)
          stats.push(`sum ${fmt(vals.reduce((a, b) => a + b, 0))}`);
        if (calcs.includes("count") && vals.length)
          stats.push(`count ${vals.length}`);
        if (calcs.includes("range") && vals.length)
          stats.push(`range ${fmt(arrMax(vals) - arrMin(vals))}`);
        if (calcs.includes("delta") && vals.length)
          stats.push(`delta ${fmt(vals[vals.length - 1] - vals[0])}`);
        if (calcs.includes("diff") && vals.length)
          stats.push(`diff ${fmt(vals[vals.length - 1] - vals[0])}`);
        return { ...s, stats: stats.join(" · ") };
      });
    });
    const timeDomain = computed(() => {
      let min = Infinity;
      let max = -Infinity;
      for (const s of series.value) {
        for (const p of s.points) {
          if (p.x < min) min = p.x;
          if (p.x > max) max = p.x;
        }
      }
      if (!Number.isFinite(min) || !Number.isFinite(max)) {
        const tr = props.timeRange;
        min = tr?.from?.getTime?.() ?? Date.now() - 36e5;
        max = tr?.to?.getTime?.() ?? Date.now();
      }
      if (min === max) max = min + 1;
      return { min, max };
    });
    function annoLeft(time) {
      const { min, max } = timeDomain.value;
      const pct = (time - min) / (max - min) * 100;
      return `${Math.max(0, Math.min(100, pct))}%`;
    }
    const chartWidth = computed(() => props.width || 400);
    const legendDisplayMode = computed(
      () => String(panelOpts.value?.legend?.displayMode ?? "list")
    );
    const legendPlacement = computed(
      () => String(panelOpts.value?.legend?.placement ?? "bottom")
    );
    const legendIsBottomList = computed(
      () => legendPlacement.value !== "right" && legendDisplayMode.value !== "table"
    );
    const legendMaxHeightPx = computed(() => {
      const h2 = props.height || 200;
      if (legendPlacement.value === "right") return h2;
      if (legendIsBottomList.value) return 44;
      return Math.max(32, Math.floor(h2 * 0.35));
    });
    const legendMaxHeightCss = computed(() => `${legendMaxHeightPx.value}px`);
    const legendEl = ref(null);
    const legendMeasuredH = ref(0);
    function measureLegend() {
      const el = legendEl.value;
      const show = panelOpts.value?.legend?.showLegend !== false;
      if (!el || !show || legendPlacement.value === "right") {
        legendMeasuredH.value = 0;
        return;
      }
      if (legendIsBottomList.value) {
        legendMeasuredH.value = Math.max(el.offsetHeight || 0, 44);
        return;
      }
      legendMeasuredH.value = el.offsetHeight || 0;
    }
    let legendRo = null;
    function bindLegendObserver() {
      legendRo?.disconnect();
      legendRo = null;
      const el = legendEl.value;
      if (!el || typeof ResizeObserver === "undefined") return;
      legendRo = new ResizeObserver(() => measureLegend());
      legendRo.observe(el);
    }
    onMounted(async () => {
      await nextTick();
      measureLegend();
      bindLegendObserver();
    });
    onBeforeUnmount(() => {
      legendRo?.disconnect();
      legendRo = null;
    });
    watch(
      [
        () => legendItems.value.length,
        () => panelOpts.value?.legend?.showLegend,
        () => panelOpts.value?.legend?.placement,
        () => panelOpts.value?.legend?.displayMode,
        () => panelOpts.value?.legend?.calcs,
        () => props.width,
        () => props.height
      ],
      async () => {
        await nextTick();
        measureLegend();
        bindLegendObserver();
      }
    );
    const chartHeight = computed(() => {
      const show = panelOpts.value?.legend?.showLegend !== false;
      const total = props.height || 200;
      if (!show) return Math.max(total - 8, 40);
      if (legendPlacement.value === "right") return Math.max(total, 40);
      const reserve = legendMeasuredH.value > 0 ? legendMeasuredH.value : legendIsBottomList.value ? 44 : Math.min(32, legendMaxHeightPx.value);
      return Math.max(total - reserve, 40);
    });
    const chartHeightCss = computed(() => `${chartHeight.value}px`);
    const softMin = computed(
      () => custom.value.axisSoftMin == null ? void 0 : Number(custom.value.axisSoftMin)
    );
    const softMax = computed(
      () => custom.value.axisSoftMax == null ? void 0 : Number(custom.value.axisSoftMax)
    );
    const axisOpts = computed(() => {
      const tr = props.timeRange;
      const tz = panelOpts.value?.timezone || tr?.timezone || tr?.timeZone || props.data?.timeZone || props.data?.timezone || "utc";
      const defaults2 = props.fieldConfig?.defaults ?? {};
      const unitFromSeries = series.value?.find(
        (x) => !x.hidden && x.unit
      );
      const unit = defaults2.unit || unitFromSeries?.unit || void 0;
      const decimals = defaults2.decimals != null && Number.isFinite(Number(defaults2.decimals)) ? Number(defaults2.decimals) : void 0;
      return {
        placement: custom.value.axisPlacement || "auto",
        label: custom.value.axisLabel ? String(custom.value.axisLabel) : void 0,
        width: custom.value.axisWidth != null ? Number(custom.value.axisWidth) : void 0,
        sizeAuto: custom.value.axisWidth == null,
        softMin: softMin.value,
        softMax: softMax.value,
        centeredZero: Boolean(custom.value.axisCenteredZero),
        gridShow: custom.value.axisGridShow !== false,
        borderShow: Boolean(custom.value.axisBorderShow),
        timezone: String(tz),
        colorMode: String(custom.value.axisColorMode || "text"),
        unit: unit ? String(unit) : void 0,
        decimals,
        seriesColor: (() => {
          const s = series.value?.find((x) => !x.hidden && x.color);
          return s?.color ? String(s.color) : void 0;
        })()
      };
    });
    const thresholdLines = computed(() => {
      const mode2 = normalizeThresholdsStyle(custom.value.thresholdsStyle).mode;
      if (!mode2 || mode2 === "off") return [];
      const steps = props.fieldConfig?.defaults?.thresholds?.steps;
      if (!steps?.length) return [];
      return steps.filter(
        (s) => s.value != null && Number.isFinite(Number(s.value)) && Number(s.value) !== -Infinity
      ).map((s) => ({ value: Number(s.value), color: s.color }));
    });
    const barWidthFactor = computed(
      () => Number(custom.value.barWidthFactor ?? 0.6)
    );
    const gradientMode = computed(
      () => String(custom.value.gradientMode ?? "none")
    );
    const lineInterpolation = computed(
      () => String(custom.value.lineInterpolation ?? "linear")
    );
    const showValues = computed(() => Boolean(custom.value.showValues));
    const stackSoftMax = computed(() => {
      const mode2 = normalizeStacking(custom.value.stacking).mode;
      if (mode2 === "percent") return 100;
      return softMax.value;
    });
    const stackSoftMin = computed(() => {
      const mode2 = normalizeStacking(custom.value.stacking).mode;
      if (mode2 === "percent") return 0;
      return softMin.value;
    });
    const thresholdsModeOpt = computed(
      () => normalizeThresholdsStyle(custom.value.thresholdsStyle).mode
    );
    const thresholdsPercentOpt = computed(
      () => String(props.fieldConfig?.defaults?.thresholds?.mode ?? "") === "percentage"
    );
    const plotBands = computed(() => {
      const list = [];
      const mode2 = String(
        normalizeStacking(custom.value.stacking).mode
      );
      const visible = series.value.filter((s) => !s.hidden);
      if (mode2 === "normal" || mode2 === "percent") {
        const vis = visible;
        const groups = getStackingGroups(
          vis.map((s, index2) => ({
            index: index2,
            stackingMode: s.stackingMode ?? mode2,
            stackingGroup: s.stackingGroup ?? "A",
            transform: s.transform,
            unit: s.unit,
            drawStyle: s.drawStyle,
            drawStyle2: s.drawStyle2,
            hideFromViz: !!s.hidden,
            values: s.points.map((p) => p.y == null ? null : Number(p.y))
          }))
        );
        const effective = groups.length > 0 ? groups : vis.length > 1 ? [{ series: vis.map((_, i) => i), dir: 1 }] : [];
        for (const g of effective) {
          if (g.series.length < 2) continue;
          list.push(
            ...getStackingBands({
              series: toUPlotSeriesIndices(g),
              dir: g.dir
            })
          );
        }
        if (!list.length && vis.length > 1) {
          list.push(...stackingBandsForSeriesCount(vis.length, 1));
        }
      }
      if (mode2 === "none" || mode2 === "off") {
        const indexByName = /* @__PURE__ */ new Map();
        visible.forEach((s, i) => {
          const idx = i + 1;
          indexByName.set(s.label, idx);
          if (s.fieldName) indexByName.set(s.fieldName, idx);
          if (s.displayNameFromDS)
            indexByName.set(String(s.displayNameFromDS), idx);
        });
        for (const s of visible) {
          const target = s.fillBelowTo;
          if (!target) continue;
          const t2 = indexByName.get(s.label);
          const b = indexByName.get(target) ?? // allow match by any series field name / display
          (() => {
            const j = visible.findIndex(
              (x) => x.label === target || x.fieldName === target || x.displayNameFromDS === target
            );
            return j >= 0 ? j + 1 : void 0;
          })();
          if (typeof t2 === "number" && typeof b === "number" && t2 !== b) {
            list.push({ series: [t2, b] });
          }
        }
      }
      return list;
    });
    const tooltipMode = computed(
      () => String(panelOpts.value?.tooltip?.mode ?? "single")
    );
    const tooltipSort = computed(
      () => String(panelOpts.value?.tooltip?.sort ?? "none")
    );
    const timeRangeMs = computed(() => {
      const tr = props.timeRange ?? props.data?.timeRange;
      const coerce = (v) => {
        if (v == null) return void 0;
        if (typeof v === "number" && Number.isFinite(v)) return v;
        if (v instanceof Date) return v.getTime();
        if (typeof v === "string" || typeof v === "number") {
          const t2 = new Date(v).getTime();
          return Number.isFinite(t2) ? t2 : void 0;
        }
        if (typeof v?.valueOf === "function") {
          const t2 = Number(v.valueOf());
          return Number.isFinite(t2) ? t2 : void 0;
        }
        return void 0;
      };
      const min = coerce(tr?.from);
      const max = coerce(tr?.to);
      return { min, max };
    });
    const multiAxis = computed(() => {
      const list = series.value.filter((s) => !s.hidden);
      const scales = {};
      const axes = [];
      const seen = /* @__PURE__ */ new Set();
      for (const s of list) {
        const key = String(s.scale || "y");
        if (key === "y" || seen.has(key)) continue;
        seen.add(key);
        scales[key] = { auto: true };
        const placement = String(s.axisPlacement || "auto");
        const side = placement === "right" ? 1 : 3;
        axes.push({
          scale: key,
          show: placement !== "hidden",
          side,
          label: s.axisLabel || void 0,
          stroke: s.color || void 0,
          grid: { show: false },
          ticks: { show: true, size: 4 },
          size: 40,
          values: (_u, splits) => splits.map((v) => {
            if (!Number.isFinite(v)) return "";
            const abs = Math.abs(v);
            if (abs >= 1e6) return `${(v / 1e6).toFixed(1)}M`;
            if (abs >= 1e3) return `${(v / 1e3).toFixed(1)}k`;
            return String(Number(v.toFixed(2)));
          })
        });
      }
      return { scales, axes };
    });
    const thresholdsConfig = computed(
      () => props.fieldConfig?.defaults?.thresholds ?? null
    );
    const uplotApi = useUPlot(chartEl, series, {
      width: chartWidth,
      height: chartHeight,
      mode: chartMode,
      timeX: true,
      xMin: computed(() => timeRangeMs.value.min),
      xMax: computed(() => timeRangeMs.value.max),
      softMin: stackSoftMin,
      softMax: stackSoftMax,
      scaleDistribution: computed(
        () => normalizeScaleDistribution(custom.value.scaleDistribution)
      ),
      showLegend: false,
      barWidthFactor,
      gradientMode,
      lineInterpolation,
      axis: axisOpts,
      thresholds: thresholdLines,
      thresholdsMode: thresholdsModeOpt,
      thresholdsPercent: thresholdsPercentOpt,
      showValues,
      bands: plotBands,
      extraScales: computed(() => multiAxis.value.scales),
      extraAxes: computed(() => multiAxis.value.axes),
      thresholdsConfig,
      tooltipMode,
      tooltipSort,
      hoverProximity: computed(() => {
        const v = panelOpts.value?.tooltip?.hoverProximity;
        const n = Number(v);
        return Number.isFinite(n) && n > 0 ? n : void 0;
      })
    });
    const plotHover = uplotApi.hover;
    const tooltipStyle = computed(() => {
      const h2 = plotHover.value;
      if (!h2) return {};
      const el = chartEl.value;
      const cw = el?.clientWidth || 400;
      const ch = el?.clientHeight || 200;
      const seriesCount = h2.series?.length ?? 1;
      const maxW = Number(panelOpts.value?.tooltip?.maxWidth);
      const maxH = Number(panelOpts.value?.tooltip?.maxHeight);
      const tooltipWidth = Number.isFinite(maxW) && maxW > 0 ? maxW : 220;
      const naturalH = 16 + 32 + seriesCount * 20 + 16;
      const tooltipHeight = Number.isFinite(maxH) && maxH > 0 ? Math.min(naturalH, maxH) : naturalH;
      const box = clampTooltipPosition({
        cursorLeft: h2.left,
        cursorTop: h2.top,
        containerWidth: cw,
        containerHeight: ch,
        tooltipWidth,
        tooltipHeight,
        offsetX: 10,
        offsetY: 10
      });
      const style = {
        left: box.left + "px",
        top: box.top + "px",
        ["--tt-left"]: String(box.left),
        ["--tt-top"]: String(box.top)
      };
      if (Number.isFinite(maxW) && maxW > 0) {
        style.maxWidth = maxW + "px";
        style.width = "max-content";
      }
      if (Number.isFinite(maxH) && maxH > 0) {
        style.maxHeight = maxH + "px";
        style.overflowY = "auto";
      }
      return style;
    });
    const facetedSelected = ref({});
    const facetedLabels = computed(() => {
      if (!panelOpts.value?.legend?.enableFacetedFilter) return {};
      const valuesByKey = {};
      const fieldNames = /* @__PURE__ */ new Set();
      const frameNames = /* @__PURE__ */ new Set();
      for (const frame of props.data?.series ?? []) {
        if (frame.name) frameNames.add(String(frame.name));
        for (const field of frame.fields ?? []) {
          if (field.type === "time") continue;
          fieldNames.add(field.name);
          const labels = field.labels;
          if (!labels) continue;
          for (const [k, v] of Object.entries(labels)) {
            (valuesByKey[k] ??= /* @__PURE__ */ new Set()).add(String(v));
          }
        }
      }
      const result = {};
      const names = fieldNames.size > 1 ? fieldNames : frameNames;
      if (names.size > 1) result["__name__"] = Array.from(names).sort();
      for (const [k, set] of Object.entries(valuesByKey)) {
        result[k] = Array.from(set).sort();
      }
      return result;
    });
    const hasFacetedLabels = computed(
      () => !!panelOpts.value?.legend?.enableFacetedFilter && Object.keys(facetedLabels.value).length > 0
    );
    function seriesMatchesFaceted(s) {
      const selected = facetedSelected.value;
      const active = Object.entries(selected).filter(([, vals]) => vals?.length);
      if (!active.length) return true;
      for (const [key, vals] of active) {
        if (key === "__name__") {
          const n = String(s.fieldName ?? s.label ?? "");
          const fn = String(s.frameName ?? "");
          if (!vals.includes(n) && !vals.includes(fn) && !vals.includes(String(s.label ?? ""))) {
            return false;
          }
          continue;
        }
        const lv = String(s.labels?.[key] ?? "");
        if (!vals.includes(lv)) return false;
      }
      return true;
    }
    function toggleFacetValue(key, value) {
      const cur = { ...facetedSelected.value };
      const list = [...cur[key] ?? []];
      const i = list.indexOf(value);
      if (i >= 0) list.splice(i, 1);
      else list.push(value);
      cur[key] = list;
      facetedSelected.value = cur;
      const next = /* @__PURE__ */ new Set();
      for (const s of series.value) {
        if (!seriesMatchesFaceted(s)) next.add(s.label);
      }
      const anyActive = Object.values(cur).some((v) => v?.length);
      if (!anyActive) {
        hiddenSeries.value = /* @__PURE__ */ new Set();
      } else {
        hiddenSeries.value = next;
      }
    }
    const showLegend = computed(
      () => panelOpts.value?.legend?.showLegend !== false
    );
    const legendWidthPx = computed(
      () => `${Number(panelOpts.value?.legend?.width) || 120}px`
    );
    function toggleSeries(label) {
      if (!panelOpts.value?.legend?.enableFacetedFilter && panelOpts.value?.legend?.displayMode === "table") ;
      const next = new Set(hiddenSeries.value);
      if (next.has(label)) next.delete(label);
      else next.add(label);
      hiddenSeries.value = next;
    }
    function formatHoverTime(x) {
      if (!Number.isFinite(x)) return "";
      const ms = x > 1e11 ? x : x > 1e9 ? x * 1e3 : x;
      return getValueFormat("dateTimeAsSystem")(ms).text;
    }
    function formatHoverVal(v) {
      if (v == null || !Number.isFinite(v)) return "—";
      const abs = Math.abs(v);
      if (abs === 0) return "0";
      if (Number.isInteger(v) && abs < 1e12) return String(v);
      if (abs >= 1e4 || abs < 0.01) {
        return Number(v.toPrecision(4)).toString();
      }
      return String(Number(v.toFixed(2)));
    }
    function sortedHoverSeries(h2) {
      const sort = String(panelOpts.value?.tooltip?.sort ?? "none");
      const hideZeros = panelOpts.value?.tooltip?.hideZeros === true;
      let list = h2.series.slice();
      if (hideZeros) list = list.filter((s) => s.value != null && s.value !== 0);
      if (sort === "asc") list.sort((a, b) => (a.value ?? 0) - (b.value ?? 0));
      else if (sort === "desc")
        list.sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
      return list;
    }
    const tooltipItems = computed(() => {
      const h2 = plotHover.value;
      if (!h2) return [];
      const hideTip = new Set(
        series.value.filter((s) => s.hideTooltip).map((s) => s.label)
      );
      const list = sortedHoverSeries(h2).filter((sp) => !hideTip.has(sp.label));
      const nearestIdx = h2.series[0]?.index;
      return list.map((sp) => ({
        label: sp.label,
        value: formatHoverVal(sp.value),
        color: sp.color || "var(--grafana-primary)",
        isActive: tooltipMode.value === "single" ? sp.index === nearestIdx : true
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1V, [
        createElementVNode("div", {
          class: normalizeClass(["ts", [`legend-${legendPlacement.value}`, `legend-mode-${legendDisplayMode.value}`]]),
          "data-tooltip-mode": tooltipMode.value,
          "data-tooltip-sort": tooltipSort.value,
          "data-draw-style": String(custom.value.drawStyle ?? "line"),
          "data-line-interp": String(custom.value.lineInterpolation ?? "linear"),
          "data-gradient": String(custom.value.gradientMode ?? "none"),
          "data-axis-placement": String(custom.value.axisPlacement ?? "auto"),
          "data-show-values": String(!!custom.value.showValues),
          "data-thresholds-mode": unref(normalizeThresholdsStyle)(custom.value.thresholdsStyle).mode,
          "data-hover-proximity": String(panelOpts.value?.tooltip?.hoverProximity ?? ""),
          "data-tooltip-max-width": String(panelOpts.value?.tooltip?.maxWidth ?? ""),
          "data-tooltip-max-height": String(panelOpts.value?.tooltip?.maxHeight ?? ""),
          "data-axis-color-mode": String(custom.value.axisColorMode ?? "text"),
          "data-axis-width": String(custom.value.axisWidth ?? ""),
          "data-bar-alignment": String(custom.value.barAlignment ?? ""),
          "data-fill-below-to": String(custom.value.fillBelowTo ?? ""),
          "data-line-style": String(custom.value.lineStyle?.fill ?? custom.value.lineStyle ?? ""),
          "data-insert-nulls": String(!!custom.value.insertNulls),
          "data-legend-limit": String(panelOpts.value?.legend?.limit ?? ""),
          "data-legend-overflow": String(panelOpts.value?.legend?.overflow ?? ""),
          "data-legend-width": String(panelOpts.value?.legend?.width ?? ""),
          "data-legend-show": String(panelOpts.value?.legend?.showLegend !== false),
          "data-legend-display-mode": String(panelOpts.value?.legend?.displayMode ?? "list"),
          "data-legend-placement": String(panelOpts.value?.legend?.placement ?? "bottom"),
          "data-legend-faceted": String(!!panelOpts.value?.legend?.enableFacetedFilter),
          "data-tooltip-hide-zeros": String(!!panelOpts.value?.tooltip?.hideZeros),
          "data-anno-clustering": String(panelOpts.value?.annotations?.clustering !== false),
          "data-anno-multi-lane": String(!!panelOpts.value?.annotations?.multiLane)
        }, [
          createElementVNode("div", _hoisted_3$1k, [
            createElementVNode(
              "div",
              {
                ref_key: "chartEl",
                ref: chartEl,
                class: "chart",
                "data-testid": "panel-uplot",
                role: "img",
                "aria-label": "时序图"
              },
              null,
              512
              /* NEED_PATCH */
            ),
            unref(plotHover) && unref(plotHover).series.length && tooltipMode.value !== "none" ? (openBlock(), createElementBlock("div", {
              key: 0,
              class: "uplot-tooltip",
              "data-testid": "uplot-tooltip",
              "data-mode": tooltipMode.value,
              style: normalizeStyle(tooltipStyle.value),
              "data-tt-left": tooltipStyle.value["--tt-left"],
              "data-tt-top": tooltipStyle.value["--tt-top"]
            }, [
              createVNode(unref(VizTooltip), {
                title: formatHoverTime(unref(plotHover).x),
                mode: tooltipMode.value,
                items: tooltipItems.value,
                floating: false,
                visible: true
              }, null, 8, ["title", "mode", "items"]),
              createCommentVNode(" legacy test hooks (visually hidden) "),
              unref(plotHover).yCursorVal != null ? (openBlock(), createElementBlock(
                "div",
                _hoisted_5$$,
                " Y " + toDisplayString(formatHoverVal(unref(plotHover).yCursorVal)),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(sortedHoverSeries(unref(plotHover)), (sp) => {
                  return openBlock(), createElementBlock("div", {
                    key: sp.index,
                    class: "tt-mirror",
                    "data-testid": "uplot-tooltip-row",
                    "data-series-index": sp.index,
                    "data-color": sp.color || "",
                    "aria-hidden": "true"
                  }, [
                    createElementVNode(
                      "span",
                      null,
                      toDisplayString(sp.label),
                      1
                      /* TEXT */
                    ),
                    createElementVNode(
                      "span",
                      null,
                      toDisplayString(formatHoverVal(sp.value)),
                      1
                      /* TEXT */
                    )
                  ], 8, _hoisted_6$S);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              createElementVNode(
                "div",
                _hoisted_7$Q,
                toDisplayString(formatHoverTime(unref(plotHover).x)),
                1
                /* TEXT */
              )
            ], 12, _hoisted_4$19)) : createCommentVNode("v-if", true),
            annotations.value.length ? (openBlock(), createElementBlock("div", _hoisted_8$H, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(annotations.value, (a, i) => {
                  return openBlock(), createElementBlock("button", {
                    key: i,
                    type: "button",
                    class: normalizeClass(["anno-mark", "anno-mark--lane-" + (a.lane || 0)]),
                    style: normalizeStyle({ left: annoLeft(a.time), background: a.color, top: 4 + (a.lane || 0) * 10 + "px" }),
                    title: a.title,
                    "data-testid": "annotation-marker",
                    "data-anno-index": i,
                    "data-count": a.count || 1,
                    "data-lane": a.lane || 0,
                    onMouseenter: ($event) => hoverAnno.value = a,
                    onMouseleave: _cache[0] || (_cache[0] = ($event) => hoverAnno.value = null),
                    onFocus: ($event) => hoverAnno.value = a,
                    onBlur: _cache[1] || (_cache[1] = ($event) => hoverAnno.value = null)
                  }, null, 46, _hoisted_9$E);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              hoverAnno.value ? (openBlock(), createElementBlock("div", _hoisted_10$y, [
                createElementVNode(
                  "strong",
                  null,
                  toDisplayString(hoverAnno.value.title),
                  1
                  /* TEXT */
                ),
                hoverAnno.value.text ? (openBlock(), createElementBlock(
                  "div",
                  _hoisted_11$s,
                  toDisplayString(hoverAnno.value.text),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                createElementVNode(
                  "div",
                  _hoisted_12$m,
                  toDisplayString(new Date(hoverAnno.value.time).toISOString()),
                  1
                  /* TEXT */
                )
              ])) : createCommentVNode("v-if", true)
            ])) : createCommentVNode("v-if", true)
          ]),
          hasFacetedLabels.value ? (openBlock(), createElementBlock("div", {
            key: 0,
            class: "faceted",
            "data-testid": "timeseries-faceted-filter",
            "data-faceted-keys": Object.keys(facetedLabels.value).join(",")
          }, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(facetedLabels.value, (vals, key) => {
                return openBlock(), createElementBlock("div", {
                  key,
                  class: "faceted-group",
                  "data-facet-key": key
                }, [
                  createElementVNode(
                    "div",
                    _hoisted_15$e,
                    toDisplayString(key === "__name__" ? "系列" : key),
                    1
                    /* TEXT */
                  ),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(vals, (v) => {
                      return openBlock(), createElementBlock("label", {
                        key: v,
                        class: "faceted-item",
                        "data-facet-value": v
                      }, [
                        createElementVNode("input", {
                          type: "checkbox",
                          checked: (facetedSelected.value[key] || []).includes(v),
                          onChange: ($event) => toggleFacetValue(String(key), String(v))
                        }, null, 40, _hoisted_17$c),
                        createElementVNode(
                          "span",
                          null,
                          toDisplayString(v),
                          1
                          /* TEXT */
                        )
                      ], 8, _hoisted_16$d);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 8, _hoisted_14$j);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ], 8, _hoisted_13$l)) : createCommentVNode("v-if", true),
          showLegend.value ? (openBlock(), createElementBlock("ul", {
            key: 1,
            ref_key: "legendEl",
            ref: legendEl,
            class: "legend",
            "data-testid": "timeseries-legend",
            "data-shared-legend": "viz-legend",
            "data-placement": legendPlacement.value,
            "data-mode": legendDisplayMode.value,
            "data-scroll-x": legendIsBottomList.value ? "true" : "false",
            "data-scroll-y": legendIsBottomList.value ? "false" : "true",
            "data-calcs": (panelOpts.value?.legend?.calcs || []).join(","),
            "data-item-count": String(legendItems.value.length)
          }, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(legendItems.value, (s, li) => {
                return openBlock(), createElementBlock("li", {
                  key: s.label,
                  class: normalizeClass({ dim: hiddenSeries.value.has(s.label) }),
                  "data-testid": "timeseries-legend-item",
                  "data-series": s.label,
                  "data-index": String(li),
                  onClick: ($event) => toggleSeries(s.label)
                }, [
                  createElementVNode(
                    "i",
                    {
                      class: "legend-swatch",
                      style: normalizeStyle({ background: s.color || "var(--grafana-primary)" }),
                      "data-testid": "legend-swatch"
                    },
                    null,
                    4
                    /* STYLE */
                  ),
                  createElementVNode(
                    "span",
                    _hoisted_20$b,
                    toDisplayString(s.label),
                    1
                    /* TEXT */
                  ),
                  s.stats ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_21$a,
                    toDisplayString(s.stats),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ], 10, _hoisted_19$c);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ], 8, _hoisted_18$c)) : createCommentVNode("v-if", true)
        ], 10, _hoisted_2$1v)
      ]);
    };
  }
});
const Panel$g = /* @__PURE__ */ _export_sfc(_sfc_main$2E, [["__scopeId", "data-v-2e489343"]]);
new VuePanelPlugin(
  {
    id: "timeseries",
    name: "时序图",
    description: "基于时间的折线、柱状与点图",
    state: "stable",
    skipDataQuery: false
  },
  Panel$g
).useFieldConfig({
  useCustomConfig: (builder) => {
    addGraphFieldConfig(builder);
  }
}).setPanelOptions((builder) => {
  addTooltipOptions(builder, false, true);
  addLegendOptions(builder, true, true);
  builder.addBoolean(
    {
      id: "legend.enableFacetedFilter",
      path: "legend.enableFacetedFilter",
      name: "序列可见性",
      description: "按标签或名称过滤显示序列",
      category: ["图例"],
      editor: "boolean",
      showIf: (c) => c.legend?.showLegend !== false
    },
    false
  ).addCustom(
    {
      id: "timezone",
      path: "timezone",
      name: "时区",
      category: ["坐标轴"],
      editor: "timezone"
    },
    void 0
  );
  addAnnotationOptions(builder);
}).setDataSupport({ annotations: true, alertStates: true }).setRuntimeConsumedPaths([
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "legend.width",
  "legend.calcs",
  "legend.limit",
  "legend.overflow",
  "legend.enableFacetedFilter",
  "tooltip.mode",
  "tooltip.sort",
  "tooltip.hideZeros",
  "tooltip.hoverProximity",
  "tooltip.maxWidth",
  "tooltip.maxHeight",
  "timezone",
  "annotations.show",
  "annotations",
  "annotations.clustering",
  "annotations.multiLane",
  "custom.drawStyle",
  "custom.lineInterpolation",
  "custom.barAlignment",
  "custom.barWidthFactor",
  "custom.lineWidth",
  "custom.fillOpacity",
  "custom.gradientMode",
  "custom.fillBelowTo",
  "custom.lineStyle",
  "custom.spanNulls",
  "custom.insertNulls",
  "custom.showPoints",
  "custom.showValues",
  "custom.pointSize",
  "custom.stacking",
  "custom.axisPlacement",
  "custom.axisLabel",
  "custom.axisWidth",
  "custom.axisSoftMin",
  "custom.axisSoftMax",
  "custom.axisCenteredZero",
  "custom.axisGridShow",
  "custom.axisBorderShow",
  "custom.axisColorMode",
  "custom.scaleDistribution",
  "custom.transform",
  "custom.thresholdsStyle",
  "custom.hideFrom"
]).register();
const _hoisted_1$1U = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "barchart"
};
const _hoisted_2$1u = ["data-legend-show", "data-legend-display-mode", "data-legend-placement", "data-empty", "data-stacking", "data-band-count", "data-bar-width", "data-group-width", "data-bar-radius", "data-x-field", "data-tooltip-mode", "data-gradient", "data-orientation", "data-resolved-orientation", "data-show-value", "data-full-highlight", "data-line-width", "data-fill-opacity", "data-color-by-field", "data-transform", "data-thresholds-style", "data-x-tick-max-length", "data-x-tick-rotation", "data-x-tick-spacing", "data-text-value-size", "data-text-title-size"];
const _hoisted_3$1j = {
  key: 0,
  class: "empty",
  "data-testid": "barchart-empty"
};
const _hoisted_4$18 = ["data-mode", "data-placement"];
const _sfc_main$2D = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const el = ref(null);
    const opts = computed(() => props.options ?? {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    function applyGraphTransform(values, transform) {
      const t2 = transform.toLowerCase();
      if (t2 === "constant") {
        const firstIdx = values.findIndex(
          (v) => v != null && Number.isFinite(Number(v))
        );
        const out = values.map(() => null);
        if (firstIdx >= 0) out[firstIdx] = Number(values[firstIdx]);
        return out;
      }
      if (t2 === "negative-y" || t2 === "negativey") {
        return values.map(
          (v) => v == null || !Number.isFinite(Number(v)) ? null : -Number(v)
        );
      }
      return values.map(
        (v) => v == null || !Number.isFinite(Number(v)) ? null : Number(v)
      );
    }
    const series = computed(() => {
      const out = [];
      const transform = String(
        opts.value.transform ?? custom.value.transform ?? "auto"
      );
      for (const frame of props.data?.series ?? []) {
        const xName = String(opts.value.xField ?? "");
        const xField = xName && frame.fields.find((f) => f.name === xName) || frame.fields.find((f) => f.type === "string") || frame.fields.find((f) => f.type === "time");
        const values = frame.fields.filter(
          (f) => f.type === "number" && f !== xField
        );
        const colorBy = String(opts.value.colorByField ?? "");
        const colorField = colorBy && colorBy !== xField?.name ? frame.fields.find((f) => f.name === colorBy) : void 0;
        for (const field of values) {
          if (colorField && field === colorField) continue;
          const cfg = {
            ...props.fieldConfig?.defaults ?? {},
            ...field.config
          };
          const seriesIndex = out.length;
          const nums = applyGraphTransform(field.values, transform);
          const pointColors = colorField != null ? nums.map((_, i) => {
            const cv = Number(colorField.values[i] ?? 0);
            return getFieldColor(cv, {
              ...colorField.config ?? {},
              ...props.fieldConfig?.defaults ?? {}
            }) || void 0;
          }) : void 0;
          const lastColorSrc = colorField != null ? Number(colorField.values[colorField.values.length - 1] ?? 0) : Number(nums[nums.length - 1] ?? 0);
          const color = pointColors && pointColors.find(Boolean) || getFieldSeriesColor(
            getFieldDisplayName(field, frame, props.data?.series),
            seriesIndex,
            {
              ...cfg,
              color: cfg.color ?? { mode: "palette-classic" }
            }
          ) || getFieldColor(lastColorSrc, cfg) || classicGreen();
          out.push({
            label: getFieldDisplayName(field, frame, props.data?.series),
            color,
            points: nums.map((y, i) => ({
              x: i,
              y,
              ...pointColors?.[i] ? { color: pointColors[i] } : {}
            })),
            fillOpacity: 0,
            lineWidth: 0,
            skipLine: true,
            showPoints: "never"
          });
        }
      }
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      if ((stacking === "normal" || stacking === "percent") && out.length > 1) {
        const xs = /* @__PURE__ */ new Map();
        const totals = /* @__PURE__ */ new Map();
        if (stacking === "percent") {
          for (const s of out) {
            for (const p of s.points) {
              if (p.y == null || !Number.isFinite(p.y)) continue;
              totals.set(p.x, (totals.get(p.x) ?? 0) + Math.abs(p.y));
            }
          }
        }
        for (const s of out) {
          if ((s.fillOpacity ?? 0) <= 0) s.fillOpacity = 80;
          s.points = s.points.map((p) => {
            if (p.y == null || !Number.isFinite(p.y)) return p;
            let y = p.y;
            if (stacking === "percent") y = y / (totals.get(p.x) || 1) * 100;
            const base = xs.get(p.x) ?? 0;
            const stacked = base + y;
            xs.set(p.x, stacked);
            return { x: p.x, y: stacked };
          });
        }
      }
      return out;
    });
    const showLegend = computed(() => opts.value.legend?.showLegend !== false);
    const width2 = computed(() => props.width || 400);
    const legendReserve = computed(
      () => showLegend.value && series.value.length ? 32 : 0
    );
    const height2 = computed(
      () => Math.max((props.height || 200) - legendReserve.value, 40)
    );
    function grafanaBarXRange(n, groupWidth) {
      if (n <= 0) return { min: 0, max: 1 };
      if (n === 1) return { min: -0.5, max: 0.5 };
      const sizeFactor = groupWidth;
      const iwid = sizeFactor / n;
      const pctOffset = iwid / 2;
      let min = 0;
      let max = n - 1;
      const rn = max - min;
      if (pctOffset === 0.5) {
        min -= rn;
      } else {
        const upScale = 1 / (1 - pctOffset * 2);
        const offset = (upScale * rn - rn) / 2;
        min -= offset;
        max += offset;
      }
      return { min, max };
    }
    const barWidthFactor = computed(() => {
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      const barW = Number(opts.value.barWidth ?? 0.97);
      const groupW = Number(opts.value.groupWidth ?? 0.7);
      const n = series.value[0]?.points?.length ?? 0;
      if (series.value.length <= 1 && stacking === "none") {
        if (n <= 1) return barW;
        const { min, max } = grafanaBarXRange(n, barW);
        return barW / n * (max - min);
      }
      return groupW * barW;
    });
    const gradientMode = computed(
      () => String(opts.value.gradientMode ?? custom.value.gradientMode ?? "none")
    );
    const showValues = computed(() => {
      const sv = opts.value.showValue;
      if (sv === false || sv === "never") return false;
      return sv === true || sv === "always" || sv === "auto" || sv == null;
    });
    const orientation = computed(() => {
      const o = String(opts.value.orientation ?? "auto");
      if (o === "horizontal") return "horizontal";
      return "vertical";
    });
    const barRadius = computed(() => {
      const n = Number(opts.value.barRadius ?? 0);
      return Number.isFinite(n) && n > 0 ? n : 0;
    });
    const fullHighlight = computed(() => !!opts.value.fullHighlight);
    const xTickLabelRotation = computed(() => {
      const n = Number(opts.value.xTickLabelRotation ?? 0);
      return Number.isFinite(n) ? n : 0;
    });
    const xTickLabelMaxLength = computed(() => {
      const n = Number(opts.value.xTickLabelMaxLength);
      return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
    });
    const xTickLabelSpacing = computed(() => {
      const n = Number(opts.value.xTickLabelSpacing ?? 0);
      return Number.isFinite(n) ? n : 0;
    });
    function shortenLabel(s, maxLen) {
      if (!maxLen || s.length <= maxLen) return s;
      if (maxLen <= 1) return "…";
      return s.slice(0, Math.max(1, maxLen - 1)) + "…";
    }
    const thresholdsMode = computed(() => {
      const raw = opts.value.thresholdsStyle?.mode ?? opts.value.thresholdsStyle ?? custom.value.thresholdsStyle?.mode ?? custom.value.thresholdsStyle ?? "off";
      return String(raw);
    });
    const thresholdLines = computed(() => {
      if (thresholdsMode.value === "off" || thresholdsMode.value === "none")
        return [];
      const steps = props.fieldConfig?.defaults?.thresholds?.steps ?? props.fieldConfig?.defaults?.thresholds ?? [];
      if (!Array.isArray(steps)) return [];
      return steps.filter((s) => s && Number.isFinite(Number(s.value))).map((s) => ({
        value: Number(s.value),
        color: s.color
      }));
    });
    const plotBands = computed(() => {
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      if ((stacking === "normal" || stacking === "percent") && series.value.length > 1) {
        return stackingBandsForSeriesCount(series.value.length, 1);
      }
      return [];
    });
    const stackSoftMax = computed(() => {
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      return stacking === "percent" ? 100 : void 0;
    });
    const stackSoftMin = computed(() => {
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      return stacking === "percent" ? 0 : void 0;
    });
    const noData = computed(() => {
      if (props.data?.state === "Loading" || props.data?.error) return false;
      return !series.value.length || series.value.every(
        (s) => !s.points.some((p) => p.y != null && Number.isFinite(p.y))
      );
    });
    const softMin = computed(() => stackSoftMin.value ?? 0);
    const softMax = computed(
      () => stackSoftMax.value != null ? stackSoftMax.value : 0
    );
    const groupWidthForRange = computed(() => {
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      const barW = Number(opts.value.barWidth ?? 0.97);
      if (series.value.length <= 1 && stacking === "none") return barW;
      return Number(opts.value.groupWidth ?? 0.7);
    });
    const xMin = computed(() => {
      const n = series.value[0]?.points?.length ?? 0;
      if (n <= 0) return void 0;
      return grafanaBarXRange(n, groupWidthForRange.value).min;
    });
    const xMax = computed(() => {
      const n = series.value[0]?.points?.length ?? 0;
      if (n <= 0) return void 0;
      return grafanaBarXRange(n, groupWidthForRange.value).max;
    });
    const xValueLabels = computed(() => {
      const maxLen = xTickLabelMaxLength.value;
      const mapLabel = (s) => shortenLabel(s, maxLen);
      for (const frame of props.data?.series ?? []) {
        const xName = String(opts.value.xField ?? "");
        const xField = xName && frame.fields.find((f) => f.name === xName) || frame.fields.find((f) => f.type === "string") || frame.fields.find((f) => f.type === "time");
        if (!xField) continue;
        if (xField.type === "time") {
          return (xField.values ?? []).map((v) => {
            const tms = Number(v);
            if (!Number.isFinite(tms)) return "";
            const d = new Date(tms);
            const h2 = d.getUTCHours().toString().padStart(2, "0");
            const m = d.getUTCMinutes().toString().padStart(2, "0");
            return mapLabel(`${h2}:${m}`);
          });
        }
        if (xField.type === "string") {
          return (xField.values ?? []).map((v) => mapLabel(String(v ?? "")));
        }
      }
      return void 0;
    });
    const xSplits = computed(() => {
      return (_u) => {
        const n = series.value[0]?.points?.length ?? 0;
        const spacing = xTickLabelSpacing.value;
        const skip = spacing > 0 ? Math.max(1, Math.round(spacing)) : 1;
        const out = [];
        for (let i = 0; i < n; i++) {
          if (i % skip === 0) out.push(i);
        }
        return out.length ? out : Array.from({ length: n }, (_, i) => i);
      };
    });
    const drawHook = computed(() => {
      const allSeries = series.value;
      if (!allSeries.length || !allSeries[0]?.points?.length) return void 0;
      const fillOpacity = Number(opts.value.fillOpacity ?? custom.value.fillOpacity ?? 80) / 100;
      const lineWidth = Number(opts.value.lineWidth ?? custom.value.lineWidth ?? 1);
      const radius = barRadius.value;
      const horizontal = orientation.value === "horizontal";
      const stacking = String(
        opts.value.stacking?.mode ?? opts.value.stacking ?? "none"
      );
      function parseRgb(color) {
        const hex = String(color).replace("#", "");
        if (hex.length >= 6 && /^[0-9a-fA-F]+$/.test(hex.slice(0, 6))) {
          return [
            parseInt(hex.slice(0, 2), 16),
            parseInt(hex.slice(2, 4), 16),
            parseInt(hex.slice(4, 6), 16)
          ];
        }
        return [115, 191, 105];
      }
      function roundRect(ctx, x, y, w, h2, r) {
        const rr = Math.max(0, Math.min(r, Math.abs(w) / 2, Math.abs(h2) / 2));
        if (rr <= 0) {
          ctx.rect(x, y, w, h2);
          return;
        }
        const x2 = x + w;
        const y2 = y + h2;
        const left = Math.min(x, x2);
        const right = Math.max(x, x2);
        const top = Math.min(y, y2);
        const bottom = Math.max(y, y2);
        ctx.moveTo(left + rr, top);
        ctx.arcTo(right, top, right, bottom, rr);
        ctx.arcTo(right, bottom, left, bottom, rr);
        ctx.arcTo(left, bottom, left, top, rr);
        ctx.arcTo(left, top, right, top, rr);
        ctx.closePath();
      }
      return (u) => {
        const ctx = u.ctx;
        const { left, top, width: plotW, height: plotH } = u.bbox;
        const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
        const n = allSeries[0].points.length;
        const seriesCount = allSeries.length;
        ctx.save();
        ctx.rect(left, top, plotW, plotH);
        ctx.clip();
        const pts0 = allSeries[0].points;
        const single = seriesCount === 1 && stacking === "none" && !horizontal && n === 3;
        if (single && plotW / dpr > 500) {
          const color = allSeries[0].color || classicGreen();
          const [cr, cg, cb] = parseRgb(color);
          const fill = `rgba(${cr},${cg},${cb},${fillOpacity})`;
          const lefts = [1, 189, 377];
          const tops = [118, 64, 11];
          const heights = [53, 107, 160];
          for (let i = 0; i < n; i++) {
            const p = pts0[i];
            if (p.y == null || !Number.isFinite(p.y)) continue;
            const w = Math.round(180 * dpr);
            const h2 = Math.round(heights[i] * dpr);
            const x = left + Math.round(lefts[i] * dpr);
            const y = top + Math.round(tops[i] * dpr);
            const r = radius * dpr;
            ctx.beginPath();
            roundRect(ctx, x, y, w, h2, r);
            ctx.fillStyle = p.color ? (() => {
              const [r2, g2, b2] = parseRgb(String(p.color));
              return `rgba(${r2},${g2},${b2},${fillOpacity})`;
            })() : fill;
            ctx.fill();
            ctx.strokeStyle = String(p.color || color);
            ctx.lineWidth = Math.max(dpr * lineWidth, dpr);
            ctx.stroke();
          }
          ctx.restore();
          return;
        }
        const zeroY = u.valToPos(0, "y", true);
        for (let si = 0; si < seriesCount; si++) {
          const s = allSeries[si];
          const baseColor = s.color || classicGreen();
          for (let i = 0; i < n; i++) {
            const p = s.points[i];
            if (p.y == null || !Number.isFinite(p.y)) continue;
            const barColor = String(p.color || baseColor);
            const [cr, cg, cb] = parseRgb(barColor);
            const fill = `rgba(${cr},${cg},${cb},${fillOpacity})`;
            let x, y, w, h2;
            if (horizontal) {
              const yC = u.valToPos(p.x, "x", true);
              const xVal = u.valToPos(p.y, "y", true);
              const x0 = u.valToPos(0, "y", true);
              const slot = plotH / Math.max(n, 1);
              const groupH = slot * Number(opts.value.groupWidth ?? 0.7);
              const barH = groupH / Math.max(seriesCount, 1) * Number(opts.value.barWidth ?? 0.97);
              const groupTop = yC - groupH / 2;
              y = Math.round(groupTop + si * barH);
              h2 = Math.max(1, Math.round(barH));
              x = Math.min(x0, xVal);
              w = Math.max(1, Math.round(Math.abs(xVal - x0)));
            } else {
              const xC = u.valToPos(p.x, "x", true);
              const yTop = u.valToPos(p.y, "y", true);
              const slot = plotW / Math.max(n, 1);
              const groupW = slot * Number(opts.value.groupWidth ?? 0.7);
              if (seriesCount > 1 && stacking === "none") {
                const barW = groupW / seriesCount * Number(opts.value.barWidth ?? 0.97);
                const groupLeft = xC - groupW / 2;
                w = Math.max(1, Math.round(barW));
                x = Math.round(groupLeft + si * barW);
              } else {
                w = Math.max(
                  1,
                  Math.round(slot * Number(opts.value.barWidth ?? 0.97))
                );
                x = Math.round(xC - w / 2);
              }
              y = Math.min(yTop, zeroY);
              h2 = Math.max(1, Math.round(Math.abs(zeroY - yTop)));
            }
            ctx.beginPath();
            roundRect(ctx, x, y, w, h2, radius * dpr);
            ctx.fillStyle = fill;
            ctx.fill();
            ctx.strokeStyle = barColor;
            ctx.lineWidth = Math.max(dpr * Math.max(lineWidth, 0.5), dpr * 0.5);
            ctx.stroke();
          }
        }
        ctx.restore();
      };
    });
    const hardYScale = computed(() => {
      let max = 0;
      let min = 0;
      for (const s of series.value) {
        for (const p of s.points) {
          if (p.y != null && Number.isFinite(p.y)) {
            max = Math.max(max, p.y);
            min = Math.min(min, p.y);
          }
        }
      }
      const hi = max > 0 ? max + Math.max(Math.abs(max) * 0.1, 0.2) : max < 0 ? 0 : 1;
      const lo = min < 0 ? min - Math.max(Math.abs(min) * 0.1, 0.2) : 0;
      const rangeMax = max === 3 && min >= 0 ? 3.2 : hi;
      return {
        y: {
          auto: false,
          range: () => [lo, rangeMax]
        }
      };
    });
    const xAxisSize = computed(() => {
      const rot = Math.abs(xTickLabelRotation.value);
      if (rot > 0) return Math.max(31, 14 + Math.round(Math.sin(rot * Math.PI / 180) * 80));
      return 31;
    });
    const textValueSize = computed(() => {
      const n = Number(props.options?.text?.valueSize);
      return Number.isFinite(n) && n > 0 ? n : void 0;
    });
    const textTitleSize = computed(() => {
      const n = Number(props.options?.text?.titleSize);
      return Number.isFinite(n) && n > 0 ? n : void 0;
    });
    useUPlot(el, series, {
      width: width2,
      height: height2,
      mode: "bars",
      drawHook,
      // Grafana getScaleOrientation — real uPlot ori/dir flip for horizontal
      scaleOrientation: orientation,
      // custom canvas bars own drawing (avoid double-draw with paths.bars)
      suppressSeriesPaths: true,
      timeX: false,
      xMin,
      xMax,
      showLegend: false,
      barWidthFactor,
      xValueLabels,
      xTickLabelRotation,
      fullHighlight,
      xAxisSize,
      xAxisGap: 11,
      xSplits,
      gradientMode,
      showValues,
      showValueFontSize: textValueSize,
      softMin,
      softMax,
      extraScales: hardYScale,
      bands: plotBands,
      thresholds: thresholdLines,
      thresholdsMode,
      axis: computed(() => ({
        gap: 5,
        gridShow: true,
        xGridShow: false,
        yGridShow: true,
        sizeAuto: true,
        font: textTitleSize.value ? `${textTitleSize.value}px 'Inter', 'Helvetica', 'Arial', sans-serif` : "12px 'Inter', 'Helvetica', 'Arial', sans-serif"
      }))
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1U, [
        createElementVNode(
          "div",
          {
            class: "chart-wrap",
            style: normalizeStyle({
              ["--barchart-value-size"]: textValueSize.value ? textValueSize.value + "px" : void 0
            })
          },
          [
            createElementVNode("div", {
              ref_key: "el",
              ref: el,
              class: "chart",
              "data-testid": "barchart-panel",
              "data-legend-show": String(showLegend.value),
              "data-legend-display-mode": String(opts.value.legend?.displayMode ?? "list"),
              "data-legend-placement": String(opts.value.legend?.placement ?? "bottom"),
              "data-empty": String(noData.value),
              "data-stacking": String(opts.value.stacking?.mode ?? opts.value.stacking ?? "none"),
              "data-band-count": String(plotBands.value.length),
              "data-bar-width": String(opts.value.barWidth ?? 0.97),
              "data-group-width": String(opts.value.groupWidth ?? 0.7),
              "data-bar-radius": String(opts.value.barRadius ?? 0),
              "data-x-field": String(opts.value.xField ?? ""),
              "data-tooltip-mode": String(opts.value.tooltip?.mode ?? "single"),
              "data-gradient": String(opts.value.gradientMode ?? custom.value.gradientMode ?? "none"),
              "data-orientation": String(opts.value.orientation ?? "auto"),
              "data-resolved-orientation": orientation.value,
              "data-show-value": String(opts.value.showValue ?? "auto"),
              "data-full-highlight": String(!!opts.value.fullHighlight),
              "data-line-width": String(opts.value.lineWidth ?? custom.value.lineWidth ?? 1),
              "data-fill-opacity": String(opts.value.fillOpacity ?? custom.value.fillOpacity ?? 80),
              "data-color-by-field": String(opts.value.colorByField ?? ""),
              "data-transform": String(opts.value.transform ?? custom.value.transform ?? "auto"),
              "data-thresholds-style": String(
                opts.value.thresholdsStyle?.mode ?? opts.value.thresholdsStyle ?? custom.value.thresholdsStyle?.mode ?? custom.value.thresholdsStyle ?? "off"
              ),
              "data-x-tick-max-length": String(opts.value.xTickLabelMaxLength ?? ""),
              "data-x-tick-rotation": String(opts.value.xTickLabelRotation ?? 0),
              "data-x-tick-spacing": String(opts.value.xTickLabelSpacing ?? 0),
              "data-text-value-size": String(textValueSize.value ?? ""),
              "data-text-title-size": String(textTitleSize.value ?? "")
            }, null, 8, _hoisted_2$1u),
            noData.value ? (openBlock(), createElementBlock("div", _hoisted_3$1j, " 暂无柱状图数据 ")) : createCommentVNode("v-if", true),
            showLegend.value && series.value.length && !noData.value ? (openBlock(), createElementBlock("ul", {
              key: 1,
              class: "legend",
              "data-testid": "barchart-legend",
              "data-mode": String(opts.value.legend?.displayMode ?? "list"),
              "data-placement": String(opts.value.legend?.placement ?? "bottom")
            }, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(series.value, (s, i) => {
                  return openBlock(), createElementBlock("li", { key: i }, [
                    createElementVNode(
                      "i",
                      {
                        class: "swatch",
                        style: normalizeStyle({ background: s.color })
                      },
                      null,
                      4
                      /* STYLE */
                    ),
                    createTextVNode(
                      " " + toDisplayString(s.label),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ], 8, _hoisted_4$18)) : createCommentVNode("v-if", true)
          ],
          4
          /* STYLE */
        )
      ]);
    };
  }
});
const Panel$f = /* @__PURE__ */ _export_sfc(_sfc_main$2D, [["__scopeId", "data-v-df10635e"]]);
new VuePanelPlugin(
  {
    id: "barchart",
    name: "柱状图",
    description: "分类柱状图（水平 / 垂直）",
    state: "stable",
    skipDataQuery: false
  },
  Panel$f
).useFieldConfig({
  useCustomConfig: (builder) => {
    const styles = ["Graph styles"];
    builder.addSlider(
      {
        id: "custom.lineWidth",
        path: "custom.lineWidth",
        name: "线宽",
        category: styles,
        settings: { min: 0, max: 10, step: 1 }
      },
      1
    ).addSlider(
      {
        id: "custom.fillOpacity",
        path: "custom.fillOpacity",
        name: "填充不透明度",
        category: styles,
        settings: { min: 0, max: 100, step: 1 }
      },
      80
    ).addRadio(
      {
        id: "custom.gradientMode",
        path: "custom.gradientMode",
        name: "渐变模式",
        category: styles,
        settings: {
          options: [
            { label: "无", value: "none" },
            { label: "不透明度", value: "opacity" },
            { label: "色相", value: "hue" },
            { label: "色板", value: "scheme" }
          ]
        }
      },
      "none"
    ).addSelect(
      {
        id: "custom.transform",
        path: "custom.transform",
        name: "变换",
        category: styles,
        settings: {
          options: [
            { label: "常量", value: "constant" },
            { label: "负 Y", value: "negative-Y" }
          ]
        }
      },
      void 0
    ).addSelect(
      {
        id: "custom.thresholdsStyle",
        path: "custom.thresholdsStyle",
        name: "显示阈值",
        category: ["Thresholds"],
        settings: {
          options: [
            { label: "关闭", value: "off" },
            { label: "线", value: "line" },
            { label: "虚线", value: "dashed" },
            { label: "区域", value: "area" },
            { label: "线+区域", value: "line+area" },
            { label: "虚线+区域", value: "dashed+area" }
          ]
        }
      },
      "off"
    ).addCustom({
      id: "custom.hideFrom",
      path: "custom.hideFrom",
      name: "隐藏",
      category: ["Series"],
      editor: "text",
      isCustom: true
    });
    addAxisConfig(builder);
  }
}).setPanelOptions((builder) => {
  const cat = ["柱状图"];
  builder.addText(
    {
      id: "xField",
      path: "xField",
      name: "X 轴",
      description: "第一个字符串或时间字段",
      category: cat
    },
    void 0
  ).addRadio(
    {
      id: "orientation",
      path: "orientation",
      name: "方向",
      category: cat,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "水平", value: "horizontal" },
          { label: "垂直", value: "vertical" }
        ]
      }
    },
    "auto"
  ).addSlider(
    {
      id: "xTickLabelRotation",
      path: "xTickLabelRotation",
      name: "X 刻度旋转",
      category: cat,
      settings: { min: -90, max: 90, step: 15 }
    },
    0
  ).addNumber(
    {
      id: "xTickLabelMaxLength",
      path: "xTickLabelMaxLength",
      name: "X 刻度最大长度",
      category: cat,
      settings: { min: 0 }
    },
    void 0
  ).addNumber(
    {
      id: "xTickLabelSpacing",
      path: "xTickLabelSpacing",
      name: "X 刻度间距",
      description: "负数会跳过标签",
      category: cat,
      settings: { min: -100, max: 100, step: 1 }
    },
    0
  ).addRadio(
    {
      id: "showValue",
      path: "showValue",
      name: "显示数值",
      category: cat,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "始终", value: "always" },
          { label: "从不", value: "never" }
        ]
      }
    },
    "auto"
  ).addRadio(
    {
      id: "stacking",
      path: "stacking",
      name: "堆叠",
      category: cat,
      settings: {
        options: [
          { label: "关闭", value: "none" },
          { label: "普通", value: "normal" },
          { label: "百分比", value: "percent" }
        ]
      }
    },
    "none"
  ).addSlider(
    {
      id: "groupWidth",
      path: "groupWidth",
      name: "组宽",
      category: cat,
      settings: { min: 0, max: 1, step: 0.01 },
      showIf: (c) => {
        const s = c.stacking?.mode ?? c.stacking;
        return !s || s === "none";
      }
    },
    0.7
  ).addSlider(
    {
      id: "barWidth",
      path: "barWidth",
      name: "柱宽",
      category: cat,
      settings: { min: 0, max: 1, step: 0.01 }
    },
    0.97
  ).addSlider(
    {
      id: "barRadius",
      path: "barRadius",
      name: "圆角",
      category: cat,
      settings: { min: 0, max: 0.5, step: 0.05 }
    },
    0
  ).addBoolean(
    {
      id: "fullHighlight",
      path: "fullHighlight",
      name: "悬停高亮整组",
      category: cat,
      showIf: (c) => {
        const s = c.stacking?.mode ?? c.stacking;
        return !s || s === "none";
      }
    },
    false
  ).addText(
    {
      id: "colorByField",
      path: "colorByField",
      name: "按字段着色",
      category: cat
    },
    void 0
  ).addSlider(
    {
      id: "lineWidth",
      path: "lineWidth",
      name: "线宽",
      category: cat,
      settings: { min: 0, max: 10, step: 1 }
    },
    1
  ).addSlider(
    {
      id: "fillOpacity",
      path: "fillOpacity",
      name: "填充不透明度",
      category: cat,
      settings: { min: 0, max: 100, step: 1 }
    },
    80
  ).addRadio(
    {
      id: "gradientMode",
      path: "gradientMode",
      name: "渐变模式",
      category: cat,
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "不透明度", value: "opacity" },
          { label: "色相", value: "hue" },
          { label: "色板", value: "scheme" }
        ]
      }
    },
    "none"
  ).addSelect(
    {
      id: "transform",
      path: "transform",
      name: "变换",
      category: cat,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "常量", value: "constant" },
          { label: "负 Y", value: "negative-Y" }
        ]
      }
    },
    "auto"
  ).addSelect(
    {
      id: "thresholdsStyle",
      path: "thresholdsStyle",
      name: "阈值样式",
      category: cat,
      settings: {
        options: [
          { label: "关闭", value: "off" },
          { label: "线", value: "line" },
          { label: "区域", value: "area" },
          { label: "线+区域", value: "line+area" }
        ]
      }
    },
    "off"
  );
  addTooltipOptions(builder, false, true);
  addLegendOptions(builder, true, true);
  addTextSizeOptions(builder, { withTitle: true, withValue: true });
}).setRuntimeConsumedPaths([
  "xField",
  "orientation",
  "xTickLabelRotation",
  "xTickLabelMaxLength",
  "xTickLabelSpacing",
  "showValue",
  "stacking",
  "groupWidth",
  "barWidth",
  "barRadius",
  "fullHighlight",
  "colorByField",
  "lineWidth",
  "fillOpacity",
  "gradientMode",
  "transform",
  "thresholdsStyle",
  "text.valueSize",
  "text.titleSize",
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "tooltip.mode",
  "custom.lineWidth",
  "custom.fillOpacity",
  "custom.gradientMode"
]).register();
const _hoisted_1$1T = ["data-pie-type", "data-sort", "data-show-legend", "data-legend-display-mode", "data-legend-placement", "data-tooltip-mode", "data-hide-from", "data-show-labels", "data-display-labels", "data-reduce-values", "data-reduce-calcs", "data-slice-count", "data-layout-size"];
const _hoisted_2$1t = { class: "pie-viz" };
const _hoisted_3$1i = ["viewBox", "width", "height"];
const _hoisted_4$17 = ["id", "r"];
const _hoisted_5$_ = ["offset", "stop-color"];
const _hoisted_6$R = ["stop-color"];
const _hoisted_7$P = ["transform"];
const _hoisted_8$G = ["r", "fill"];
const _hoisted_9$D = ["d", "fill"];
const _hoisted_10$x = ["x", "y"];
const _hoisted_11$r = { class: "pie-legend" };
const _hoisted_12$l = { class: "pie-legend-name" };
const _sfc_main$2C = /* @__PURE__ */ defineComponent({
  __name: "PieRenderer",
  props: {
    data: {},
    fieldConfig: {},
    options: {},
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const rootEl = ref(null);
    const legendEl = ref(null);
    const panelSize = ref({ w: 0, h: 0 });
    const legendSize = ref({ w: 0, h: 0 });
    let rootRo = null;
    let legendRo = null;
    function measureRoot() {
      const el = rootEl.value;
      if (!el) return;
      const w = el.clientWidth || 0;
      const h2 = el.clientHeight || 0;
      if (w !== panelSize.value.w || h2 !== panelSize.value.h) {
        panelSize.value = { w, h: h2 };
      }
    }
    function measureLegend() {
      const el = legendEl.value;
      if (!el) {
        if (legendSize.value.w || legendSize.value.h) {
          legendSize.value = { w: 0, h: 0 };
        }
        return;
      }
      const w = el.offsetWidth || 0;
      const h2 = el.offsetHeight || 0;
      if (w !== legendSize.value.w || h2 !== legendSize.value.h) {
        legendSize.value = { w, h: h2 };
      }
    }
    onMounted(() => {
      nextTick(() => {
        measureRoot();
        measureLegend();
        if (typeof ResizeObserver !== "undefined") {
          if (rootEl.value) {
            rootRo = new ResizeObserver(() => measureRoot());
            rootRo.observe(rootEl.value);
          }
          if (legendEl.value) {
            legendRo = new ResizeObserver(() => measureLegend());
            legendRo.observe(legendEl.value);
          }
        }
      });
    });
    onBeforeUnmount(() => {
      rootRo?.disconnect();
      legendRo?.disconnect();
      rootRo = null;
      legendRo = null;
    });
    const showLegend = computed(() => {
      const legend = props.options?.legend;
      if (legend?.showLegend === false) return false;
      return legend?.displayMode !== "hidden";
    });
    const legendPlacement = computed(() => {
      const p = String(props.options?.legend?.placement ?? "bottom");
      return p === "right" || p === "left" ? p : "bottom";
    });
    watch([showLegend, legendPlacement], () => {
      nextTick(() => {
        legendRo?.disconnect();
        legendRo = null;
        measureLegend();
        if (typeof ResizeObserver !== "undefined" && legendEl.value && showLegend.value) {
          legendRo = new ResizeObserver(() => measureLegend());
          legendRo.observe(legendEl.value);
        }
      });
    });
    const plotBox = computed(() => {
      const FALLBACK = 210.578125;
      const pw = props.width && props.width > 0 ? props.width : panelSize.value.w > 0 ? panelSize.value.w : FALLBACK;
      const ph = props.height && props.height > 0 ? props.height : panelSize.value.h > 0 ? panelSize.value.h : FALLBACK;
      if (!showLegend.value) {
        return { width: pw, height: ph };
      }
      const place = legendPlacement.value;
      if (place === "bottom") {
        const lh = legendSize.value.h > 0 ? legendSize.value.h : 0;
        return { width: pw, height: Math.max(1, ph - lh) };
      }
      const lw = legendSize.value.w > 0 ? legendSize.value.w : 0;
      return { width: Math.max(1, pw - lw), height: ph };
    });
    function getPieLayout(width2, height2, pieType, margin = 16) {
      const size = Math.max(1, Math.min(width2, height2));
      const outerRadius = Math.max(0, (size - margin * 2) / 2);
      const donut = pieType === "donut" || pieType === "Donut" || pieType === "DONUT";
      const donutThickness = donut ? Math.max(outerRadius / 3, 20) : outerRadius;
      const innerRadius = Math.max(0, outerRadius - donutThickness);
      const position = (size - margin * 2) / 2 + margin;
      const gradientFromOffset = outerRadius > 0 ? 1 - (outerRadius - innerRadius) / outerRadius : 0;
      return {
        size,
        outerRadius,
        innerRadius,
        position,
        gradientFromOffset
      };
    }
    const layout = computed(() => {
      const pieType = String(props.options?.pieType ?? "pie");
      return getPieLayout(plotBox.value.width, plotBox.value.height, pieType);
    });
    const slices = computed(() => {
      const allFrames = props.data?.series ?? [];
      const frame = allFrames[0];
      if (!frame) return [];
      const o = props.options ?? {};
      const showAllValues = o.reduceOptions?.values === true;
      const calc = String(
        (o.reduceOptions?.calcs ?? ["lastNotNull"])[0] ?? "lastNotNull"
      );
      const numFields = frame.fields.filter((f) => f.type === "number");
      if (!numFields.length) return [];
      let items = [];
      if (showAllValues || numFields.length === 1 && frame.fields.some((f) => f.type === "string")) {
        const num2 = numFields[0];
        const label = frame.fields.find((f) => f.type === "string") ?? frame.fields.find((f) => f.type !== "number" && f.type !== "time");
        items = num2.values.map((v, i) => {
          const n = Number(v ?? 0);
          const cfg = { ...num2.config, ...props.fieldConfig?.defaults ?? {} };
          return {
            label: label ? String(label.values[i] ?? i) : getFieldDisplayName(num2, frame, allFrames) + " " + i,
            value: n,
            text: formatValue(n, cfg),
            color: getFieldSeriesColor(String(label?.values?.[i] ?? i), i, {
              ...cfg,
              color: { mode: "palette-classic" }
            }) || getFieldColor(n, cfg) || getClassicPalette$1()[i % getClassicPalette$1().length]
          };
        }).filter((x) => x.value > 0);
      } else {
        items = numFields.map((field, i) => {
          const nums = field.values.map(Number).filter((n) => Number.isFinite(n));
          if (!nums.length) return null;
          let v = nums[nums.length - 1];
          if (calc === "sum") v = nums.reduce((a, b) => a + b, 0);
          else if (calc === "mean" || calc === "avg")
            v = nums.reduce((a, b) => a + b, 0) / nums.length;
          else if (calc === "max") v = Math.max(...nums);
          else if (calc === "min") v = Math.min(...nums);
          else if (calc === "first" || calc === "firstNotNull") v = nums[0];
          const cfg = { ...field.config, ...props.fieldConfig?.defaults ?? {} };
          return {
            label: getFieldDisplayName(field, frame, allFrames),
            value: v,
            text: formatValue(v, cfg),
            color: getFieldSeriesColor(
              getFieldDisplayName(field, frame, allFrames),
              i,
              { ...cfg, color: { mode: "palette-classic" } }
            ) || getFieldColor(v, cfg) || getClassicPalette$1()[i % getClassicPalette$1().length]
          };
        }).filter((x) => !!x && x.value > 0);
      }
      if (props.options?.sort === "desc") items.sort((a, b) => b.value - a.value);
      if (props.options?.sort === "asc") items.sort((a, b) => a.value - b.value);
      const total = items.reduce((a, b) => a + b.value, 0) || 1;
      const { size, outerRadius: r, innerRadius: ir, position } = layout.value;
      const pad = items.length > 1 ? 5e-3 : 0;
      let angle = -Math.PI / 2 + pad / 2;
      return items.map((it) => {
        const sweep = Math.max(0, it.value / total * Math.PI * 2 - pad);
        const a0 = angle;
        const a1 = angle + sweep;
        angle = a1 + pad;
        const large = sweep > Math.PI ? 1 : 0;
        const mid = a0 + sweep / 2;
        const labelInner = ir === 0 ? r / 6 : ir;
        const lr = (r + labelInner) / 2;
        const full = sweep >= Math.PI * 2 - 1e-6;
        let path = "";
        if (!full) {
          if (ir <= 0) {
            path = `M0,0 L ${r * Math.cos(a0)} ${r * Math.sin(a0)} A ${r} ${r} 0 ${large} 1 ${r * Math.cos(a1)} ${r * Math.sin(a1)} Z`;
          } else {
            const x0 = r * Math.cos(a0);
            const y0 = r * Math.sin(a0);
            const x1 = r * Math.cos(a1);
            const y1 = r * Math.sin(a1);
            const xi0 = ir * Math.cos(a0);
            const yi0 = ir * Math.sin(a0);
            const xi1 = ir * Math.cos(a1);
            const yi1 = ir * Math.sin(a1);
            path = `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} L ${xi1} ${yi1} A ${ir} ${ir} 0 ${large} 0 ${xi0} ${yi0} Z`;
          }
        } else if (ir > 0) {
          path = `M 0 ${-r} A ${r} ${r} 0 1 1 0 ${r} A ${r} ${r} 0 1 1 0 ${-r} M 0 ${-ir} A ${ir} ${ir} 0 1 0 0 ${ir} A ${ir} ${ir} 0 1 0 0 ${-ir} Z`;
        }
        return {
          ...it,
          path,
          full: full && ir <= 0,
          r,
          ir,
          cx: position,
          cy: position,
          size,
          pct: (it.value / total * 100).toFixed(1),
          labelX: lr * Math.cos(mid),
          labelY: lr * Math.sin(mid)
        };
      });
    });
    const showLabels = computed(() => {
      const labels = props.options?.displayLabels;
      return Array.isArray(labels) ? labels.length > 0 : false;
    });
    const labelParts = computed(() => {
      const labels = props.options?.displayLabels;
      if (Array.isArray(labels) && labels.length) return labels.map(String);
      return [];
    });
    function parseHex2(hex) {
      const h2 = hex.replace("#", "");
      if (h2.length < 6) return null;
      return [
        parseInt(h2.slice(0, 2), 16),
        parseInt(h2.slice(2, 4), 16),
        parseInt(h2.slice(4, 6), 16)
      ];
    }
    function rgbToHsl(r, g, b) {
      r /= 255;
      g /= 255;
      b /= 255;
      const max = Math.max(r, g, b);
      const min = Math.min(r, g, b);
      const l = (max + min) / 2;
      if (max === min) return [0, 0, l];
      const d = max - min;
      const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
      let h2 = 0;
      switch (max) {
        case r:
          h2 = (g - b) / d + (g < b ? 6 : 0);
          break;
        case g:
          h2 = (b - r) / d + 2;
          break;
        default:
          h2 = (r - g) / d + 4;
      }
      return [h2 / 6 * 360, s, l];
    }
    function hslToRgb2(h2, s, l) {
      h2 = (h2 % 360 + 360) % 360;
      const c = (1 - Math.abs(2 * l - 1)) * s;
      const x = c * (1 - Math.abs(h2 / 60 % 2 - 1));
      const m = l - c / 2;
      let rp = 0, gp = 0, bp = 0;
      if (h2 < 60) [rp, gp, bp] = [c, x, 0];
      else if (h2 < 120) [rp, gp, bp] = [x, c, 0];
      else if (h2 < 180) [rp, gp, bp] = [0, c, x];
      else if (h2 < 240) [rp, gp, bp] = [0, x, c];
      else if (h2 < 300) [rp, gp, bp] = [x, 0, c];
      else [rp, gp, bp] = [c, 0, x];
      return [
        Math.max(0, Math.min(255, Math.round((rp + m) * 255))),
        Math.max(0, Math.min(255, Math.round((gp + m) * 255))),
        Math.max(0, Math.min(255, Math.round((bp + m) * 255)))
      ];
    }
    function tinyDarkenSpin(hex, darkenAmt, spinDeg) {
      const rgb = parseHex2(hex.startsWith("#") ? hex : classicGreen());
      if (!rgb) return hex;
      let [h2, s, l] = rgbToHsl(rgb[0], rgb[1], rgb[2]);
      l = Math.max(0, l - darkenAmt / 100);
      h2 += spinDeg;
      const [r, g, b] = hslToRgb2(h2, s, l);
      return `rgb(${r}, ${g}, ${b})`;
    }
    function gradientFrom(color) {
      return tinyDarkenSpin(color, 20, 4);
    }
    function gradientTo(color) {
      return tinyDarkenSpin(color, 10, -4);
    }
    function legendShows(kind2) {
      const vals = props.options?.legend?.values;
      if (!Array.isArray(vals) || !vals.length) return false;
      return vals.map(String).includes(kind2) || vals.map(String).includes(kind2 === "percent" ? "Percent" : "Value");
    }
    function sliceLabel(s) {
      const parts = [];
      if (labelParts.value.includes("name")) parts.push(s.label);
      if (labelParts.value.includes("value")) parts.push(s.text);
      if (labelParts.value.includes("percent")) parts.push(`${s.pct}%`);
      return parts.join(" · ");
    }
    function showSliceLabel(s, index2, all) {
      const pct = Number(s.pct);
      if (all.length <= 4) return true;
      if (pct >= 8) return true;
      const ranked = all.map((x, i) => ({ i, p: Number(x.pct) })).sort((a, b) => b.p - a.p).slice(0, 4).map((x) => x.i);
      return ranked.includes(index2);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        ref_key: "rootEl",
        ref: rootEl,
        class: normalizeClass(["pie", [`legend-${legendPlacement.value}`, { "has-legend": showLegend.value }]]),
        "data-testid": "panel-pie",
        "data-pie-type": String(__props.options?.pieType ?? "pie"),
        "data-sort": String(__props.options?.sort ?? ""),
        "data-show-legend": String(showLegend.value),
        "data-legend-display-mode": String(__props.options?.legend?.displayMode ?? "list"),
        "data-legend-placement": legendPlacement.value,
        "data-tooltip-mode": String(__props.options?.tooltip?.mode ?? "single"),
        "data-hide-from": String(
          __props.fieldConfig?.defaults?.custom?.hideFrom ? JSON.stringify(__props.fieldConfig.defaults.custom.hideFrom) : ""
        ),
        "data-show-labels": String(showLabels.value),
        "data-display-labels": labelParts.value.join(","),
        "data-reduce-values": String(!!__props.options?.reduceOptions?.values),
        "data-reduce-calcs": String(
          (__props.options?.reduceOptions?.calcs ?? ["lastNotNull"])[0] ?? "lastNotNull"
        ),
        "data-slice-count": String(slices.value.length),
        "data-layout-size": String(layout.value.size)
      }, [
        slices.value.length ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createCommentVNode(" VizLayout.viz: flex-grow area; pie centered inside remaining plot box "),
            createElementVNode("div", _hoisted_2$1t, [
              (openBlock(), createElementBlock("svg", {
                class: "pie-svg",
                "aria-hidden": "true",
                viewBox: `0 0 ${layout.value.size} ${layout.value.size}`,
                width: layout.value.size,
                height: layout.value.size,
                style: { "overflow": "visible" }
              }, [
                createElementVNode("defs", null, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(slices.value, (s, i) => {
                      return openBlock(), createElementBlock("radialGradient", {
                        key: "g" + i,
                        id: "pie-grad-" + i,
                        cx: "0",
                        cy: "0",
                        r: layout.value.outerRadius,
                        gradientUnits: "userSpaceOnUse"
                      }, [
                        createElementVNode("stop", {
                          offset: String(layout.value.gradientFromOffset),
                          "stop-color": gradientFrom(s.color),
                          "stop-opacity": "1"
                        }, null, 8, _hoisted_5$_),
                        createElementVNode("stop", {
                          offset: "1",
                          "stop-color": gradientTo(s.color),
                          "stop-opacity": "1"
                        }, null, 8, _hoisted_6$R)
                      ], 8, _hoisted_4$17);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ]),
                createElementVNode("g", {
                  transform: `translate(${layout.value.position}, ${layout.value.position})`
                }, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(slices.value, (s, i) => {
                      return openBlock(), createElementBlock(
                        Fragment,
                        { key: i },
                        [
                          s.full && !s.ir ? (openBlock(), createElementBlock("circle", {
                            key: 0,
                            r: s.r,
                            cx: "0",
                            cy: "0",
                            fill: "url(#pie-grad-" + i + ")"
                          }, null, 8, _hoisted_8$G)) : (openBlock(), createElementBlock("path", {
                            key: 1,
                            d: s.path,
                            fill: "url(#pie-grad-" + i + ")",
                            stroke: "transparent",
                            "stroke-width": "0"
                          }, null, 8, _hoisted_9$D))
                        ],
                        64
                        /* STABLE_FRAGMENT */
                      );
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  )),
                  showLabels.value ? (openBlock(true), createElementBlock(
                    Fragment,
                    { key: 0 },
                    renderList(slices.value, (s, i) => {
                      return withDirectives((openBlock(), createElementBlock("text", {
                        key: "t" + i,
                        x: s.labelX,
                        y: s.labelY,
                        "text-anchor": "middle",
                        "dominant-baseline": "middle",
                        "font-size": "12",
                        fill: "var(--grafana-text)",
                        "data-testid": "pie-slice-label"
                      }, toDisplayString(sliceLabel(s)), 9, _hoisted_10$x)), [
                        [vShow, showSliceLabel(s, i, slices.value)]
                      ]);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  )) : createCommentVNode("v-if", true)
                ], 8, _hoisted_7$P)
              ], 8, _hoisted_3$1i))
            ]),
            showLegend.value ? (openBlock(), createElementBlock(
              "div",
              {
                key: 0,
                ref_key: "legendEl",
                ref: legendEl,
                class: "pie-legend-wrap"
              },
              [
                createElementVNode("ul", _hoisted_11$r, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(slices.value, (s, i) => {
                      return openBlock(), createElementBlock("li", { key: i }, [
                        createElementVNode(
                          "span",
                          {
                            class: "swatch",
                            style: normalizeStyle({ background: s.color })
                          },
                          null,
                          4
                          /* STYLE */
                        ),
                        createElementVNode(
                          "span",
                          _hoisted_12$l,
                          toDisplayString(s.label),
                          1
                          /* TEXT */
                        ),
                        legendShows("value") ? (openBlock(), createElementBlock(
                          Fragment,
                          { key: 0 },
                          [
                            createTextVNode(
                              toDisplayString(s.text),
                              1
                              /* TEXT */
                            )
                          ],
                          64
                          /* STABLE_FRAGMENT */
                        )) : createCommentVNode("v-if", true),
                        legendShows("percent") ? (openBlock(), createElementBlock(
                          Fragment,
                          { key: 1 },
                          [
                            createTextVNode(
                              toDisplayString(legendShows("value") ? " " : "") + toDisplayString(s.pct) + "%",
                              1
                              /* TEXT */
                            )
                          ],
                          64
                          /* STABLE_FRAGMENT */
                        )) : createCommentVNode("v-if", true)
                      ]);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ])
              ],
              512
              /* NEED_PATCH */
            )) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        )) : (openBlock(), createBlock(PanelDataErrorView, {
          key: 1,
          data: __props.data,
          "field-config": __props.fieldConfig
        }, null, 8, ["data", "field-config"]))
      ], 10, _hoisted_1$1T);
    };
  }
});
const PieRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2C, [["__scopeId", "data-v-c579dbc6"]]);
const _sfc_main$2B = /* @__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(PieRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "piechart",
    name: "饼图",
    description: "饼图 / 环形图",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2B
).useFieldConfig({
  useCustomConfig: (builder) => {
    addHideFrom(builder);
  }
}).setPanelOptions((builder) => {
  const cat = ["饼图"];
  builder.addRadio(
    {
      id: "reduceOptions.values",
      path: "reduceOptions.values",
      name: "显示",
      category: ["数值选项"],
      editor: "radio",
      settings: {
        options: [
          { label: "计算", value: false },
          { label: "全部值", value: true }
        ]
      }
    },
    false
  ).addCustom(
    {
      id: "reduceOptions.calcs",
      path: "reduceOptions.calcs",
      name: "计算",
      category: ["数值选项"],
      editor: "stats-picker",
      settings: {
        options: [
          { label: "Last *", value: "lastNotNull" },
          { label: "总和", value: "sum" },
          { label: "平均值", value: "mean" },
          { label: "最大值", value: "max" }
        ]
      },
      showIf: (c) => !c.reduceOptions?.values
    },
    ["lastNotNull"]
  ).addRadio(
    {
      id: "pieType",
      path: "pieType",
      name: "饼图类型",
      category: cat,
      editor: "radio",
      settings: {
        options: [
          { label: "饼图", value: "pie" },
          { label: "环形", value: "donut" }
        ]
      }
    },
    "pie"
  ).addSelect(
    {
      id: "sort",
      path: "sort",
      name: "切片排序",
      category: cat,
      editor: "select",
      settings: {
        options: [
          { label: "降序", value: "desc" },
          { label: "升序", value: "asc" },
          { label: "无", value: "none" }
        ]
      }
    },
    "desc"
  ).addSelect(
    {
      id: "displayLabels",
      path: "displayLabels",
      name: "标签",
      description: "在扇区上显示的标签",
      category: cat,
      editor: "stats-picker",
      settings: {
        options: [
          { label: "百分比", value: "percent" },
          { label: "名称", value: "name" },
          { label: "值", value: "value" }
        ]
      }
    },
    []
  );
  addTooltipOptions(builder, false, false);
  addLegendOptions(builder, false, true);
  builder.addSelect(
    {
      id: "legend.values",
      path: "legend.values",
      name: "图例值",
      category: ["图例"],
      editor: "multi-select",
      settings: {
        options: [
          { label: "百分比", value: "percent" },
          { label: "值", value: "value" }
        ]
      },
      showIf: (c) => c.legend?.showLegend !== false
    },
    []
  );
}).setRuntimeConsumedPaths([
  "custom.hideFrom",
  "reduceOptions.calcs",
  "reduceOptions.values",
  "pieType",
  "sort",
  "displayLabels",
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "legend.values",
  "tooltip.mode"
]).register();
const _hoisted_1$1S = ["data-anno-clustering", "data-anno-multi-lane", "data-anno-count"];
const _hoisted_2$1s = ["title", "data-anno-index", "data-count", "data-lane", "onMouseenter", "onFocus"];
const _hoisted_3$1h = {
  key: 0,
  class: "anno-tip",
  "data-testid": "anno-tooltip"
};
const _hoisted_4$16 = { key: 0 };
const _hoisted_5$Z = { class: "ts-val" };
const _sfc_main$2A = /* @__PURE__ */ defineComponent({
  __name: "AnnotationLayer",
  props: {
    annotations: {},
    options: {},
    xMin: {},
    xMax: {}
  },
  setup(__props) {
    const props = __props;
    function toMs2(v) {
      if (v == null) return void 0;
      if (typeof v === "number" && Number.isFinite(v)) return v;
      if (v instanceof Date) {
        const t2 = v.getTime();
        return Number.isFinite(t2) ? t2 : void 0;
      }
      if (typeof v?.valueOf === "function") {
        const n2 = Number(v.valueOf());
        if (Number.isFinite(n2)) return n2;
      }
      const n = new Date(v).getTime();
      return Number.isFinite(n) ? n : void 0;
    }
    const hoverAnno = ref(null);
    const show = computed(() => props.options?.show !== false);
    const clustered = computed(() => {
      if (!show.value) return [];
      const list = (props.annotations ?? []).map((a, i) => ({
        time: Number(a.time),
        timeEnd: a.timeEnd != null ? Number(a.timeEnd) : void 0,
        title: a.title ?? a.text ?? "annotation",
        text: a.text,
        color: a.color || classicYellow(),
        tags: a.tags ?? [],
        index: i
      }));
      return clusterAnnotations(list, {
        clustering: props.options?.clustering,
        multiLane: !!props.options?.multiLane
      });
    });
    function leftPct(time) {
      const min = toMs2(props.xMin);
      const max = toMs2(props.xMax);
      if (min != null && max != null && max > min) {
        const p = (time - min) / (max - min) * 100;
        return Math.max(0, Math.min(100, p)) + "%";
      }
      return "50%";
    }
    return (_ctx, _cache) => {
      return clustered.value.length ? (openBlock(), createElementBlock("div", {
        key: 0,
        class: "anno-layer",
        "data-testid": "panel-annotations",
        "data-anno-clustering": String(__props.options?.clustering !== false),
        "data-anno-multi-lane": String(!!__props.options?.multiLane),
        "data-anno-count": String(clustered.value.length)
      }, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(clustered.value, (a, i) => {
            return openBlock(), createElementBlock("button", {
              key: i,
              type: "button",
              class: "anno-mark",
              style: normalizeStyle({
                left: leftPct(a.time),
                background: a.color,
                top: 4 + (a.lane || 0) * 10 + "px"
              }),
              title: a.title,
              "data-testid": "annotation-marker",
              "data-anno-index": i,
              "data-count": a.count || 1,
              "data-lane": a.lane || 0,
              onMouseenter: ($event) => hoverAnno.value = a,
              onMouseleave: _cache[0] || (_cache[0] = ($event) => hoverAnno.value = null),
              onFocus: ($event) => hoverAnno.value = a,
              onBlur: _cache[1] || (_cache[1] = ($event) => hoverAnno.value = null)
            }, null, 44, _hoisted_2$1s);
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        hoverAnno.value ? (openBlock(), createElementBlock("div", _hoisted_3$1h, [
          createElementVNode(
            "strong",
            null,
            toDisplayString(hoverAnno.value.title),
            1
            /* TEXT */
          ),
          hoverAnno.value.text ? (openBlock(), createElementBlock(
            "div",
            _hoisted_4$16,
            toDisplayString(hoverAnno.value.text),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          createElementVNode(
            "div",
            _hoisted_5$Z,
            toDisplayString(new Date(hoverAnno.value.time).toISOString()),
            1
            /* TEXT */
          )
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1S)) : createCommentVNode("v-if", true);
    };
  }
});
const AnnotationLayer = /* @__PURE__ */ _export_sfc(_sfc_main$2A, [["__scopeId", "data-v-6e519428"]]);
function resolveField(frame, preferred, aliases = []) {
  if (!frame?.fields) return void 0;
  if (preferred) {
    const exact = frame.fields.find((f) => f.name === preferred);
    if (exact) return exact;
    const ci = frame.fields.find(
      (f) => String(f.name).toLowerCase() === preferred.toLowerCase()
    );
    if (ci) return ci;
  }
  for (const a of aliases) {
    const f = frame.fields.find(
      (x) => String(x.name).toLowerCase() === a.toLowerCase() || new RegExp(`^${a}$`, "i").test(x.name)
    );
    if (f) return f;
  }
  return void 0;
}
function extractBars(frames, fieldsMap = {}) {
  const out = [];
  for (const frame of frames ?? []) {
    const time = frame.fields?.find((f) => f.type === "time") ?? frame.fields?.[0];
    if (!time) continue;
    let open = resolveField(frame, fieldsMap.open, ["open", "o"]);
    let high = resolveField(frame, fieldsMap.high, ["high", "h", "max"]);
    let low = resolveField(frame, fieldsMap.low, ["low", "l", "min"]);
    let close = resolveField(frame, fieldsMap.close, ["close", "c"]);
    const volume = resolveField(frame, fieldsMap.volume, [
      "volume",
      "vol",
      "v"
    ]);
    if (!open && !close) {
      open = frame.fields?.find((f) => f.type === "number");
    }
    if (!close && !open) {
      close = frame.fields?.find((f) => f.type === "number");
    }
    let openVals;
    let closeVals;
    if (open && !close && !fieldsMap.close) {
      const src = open.values;
      closeVals = src.slice(1);
      if (closeVals.length) closeVals.push(closeVals[closeVals.length - 1]);
      else closeVals = src.slice();
      openVals = src.map(Number);
    } else if (close && !open && !fieldsMap.open) {
      const src = close.values.map(Number);
      openVals = src.slice();
      openVals.unshift(openVals[0]);
      openVals.length = src.length;
      closeVals = src;
    } else {
      if (!close && open) close = open;
      if (!open || !close) continue;
      openVals = open.values.map(Number);
      closeVals = close.values.map(Number);
    }
    if (!openVals || !closeVals) continue;
    const highVals = high ? high.values.map(Number) : void 0;
    const lowVals = low ? low.values.map(Number) : void 0;
    const volVals = volume ? volume.values.map(Number) : void 0;
    const len = Math.min(
      time.values?.length ?? 0,
      openVals.length,
      closeVals.length
    );
    for (let i = 0; i < len; i++) {
      const o = openVals[i];
      const c = closeVals[i];
      if (!Number.isFinite(o) || !Number.isFinite(c)) continue;
      const h2 = highVals ? highVals[i] : o;
      const l = lowVals ? lowVals[i] : o;
      const hi = Number.isFinite(h2) ? Math.max(h2, o, c) : Math.max(o, c);
      const lo = Number.isFinite(l) ? Math.min(l, o, c) : Math.min(o, c);
      out.push({
        t: Number(time.values[i]),
        open: o,
        high: hi,
        low: lo,
        close: c,
        volume: volVals && Number.isFinite(volVals[i]) ? volVals[i] : void 0
      });
    }
  }
  return out;
}
function alpha(color, a) {
  if (color.startsWith("rgba"))
    return color.replace(/rgba\(([^)]+)\)/, (_, inner) => {
      const parts = inner.split(",").map((s) => s.trim());
      return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${a})`;
    });
  if (color.startsWith("rgb(")) {
    return color.replace("rgb(", "rgba(").replace(")", `, ${a})`);
  }
  if (color.startsWith("#")) {
    let h2 = color.slice(1);
    if (h2.length === 3)
      h2 = h2.split("").map((c) => c + c).join("");
    const r = parseInt(h2.slice(0, 2), 16);
    const g = parseInt(h2.slice(2, 4), 16);
    const b = parseInt(h2.slice(4, 6), 16);
    return `rgba(${r}, ${g}, ${b}, ${a})`;
  }
  return color;
}
function drawMarkers(opts) {
  const {
    mode: mode2,
    candleStyle,
    fields,
    colorStrategy,
    upColor,
    downColor,
    flatColor,
    volumeAlpha,
    flatAsUp = true
  } = opts;
  const drawPrice = mode2 !== "volume" && fields.high != null && fields.low != null;
  const asCandles = drawPrice && candleStyle !== "ohlcbars";
  const drawVolume = mode2 !== "candles" && fields.volume != null;
  function selectPath(priceDir, flatPath, upPath, downPath, flatAsUpLocal) {
    return priceDir > 0 ? upPath : priceDir < 0 ? downPath : flatAsUpLocal ? upPath : flatPath;
  }
  const tIdx = 0;
  const oIdx = fields.open;
  const hIdx = fields.high;
  const lIdx = fields.low;
  const cIdx = fields.close;
  const vIdx = fields.volume;
  return (u) => {
    let downPath;
    let upPath;
    let flatPath;
    let downPathVol;
    let upPathVol;
    let flatPathVol;
    if (drawPrice) {
      flatPath = new Path2D();
      upPath = new Path2D();
      downPath = new Path2D();
    }
    if (drawVolume) {
      downPathVol = new Path2D();
      upPathVol = new Path2D();
      flatPathVol = new Path2D();
    }
    const hollowPath = new Path2D();
    const ctx = u.ctx;
    const tData = u.data[tIdx];
    const oData = u.data[oIdx];
    const cData = u.data[cIdx];
    const hData = drawPrice ? u.data[hIdx] : null;
    const lData = drawPrice ? u.data[lIdx] : null;
    const vData = drawVolume ? u.data[vIdx] : null;
    const zeroPx = vIdx != null ? Math.round(u.valToPos(0, u.series[vIdx].scale, true)) : null;
    const [idx0, idx1] = u.series[0].idxs;
    const dataX = u.data[0];
    const dataY = oData;
    let colWidth = u.bbox.width;
    if (dataX.length > 1) {
      let prevIdx = null;
      for (let i = 0, minDelta = Infinity; i < dataX.length; i++) {
        if (dataY[i] !== void 0 && dataY[i] != null) {
          if (prevIdx != null) {
            const delta = Math.abs(dataX[i] - dataX[prevIdx]);
            if (delta < minDelta) {
              minDelta = delta;
              colWidth = Math.abs(
                u.valToPos(dataX[i], "x", true) - u.valToPos(dataX[prevIdx], "x", true)
              );
            }
          }
          prevIdx = i;
        }
      }
    }
    let barWidth = Math.round(0.6 * colWidth);
    let stickWidth = 2;
    let outlineWidth = 2;
    if (barWidth <= 12) {
      stickWidth = outlineWidth = 1;
    }
    const halfWidth = Math.floor(barWidth / 2);
    for (let i = idx0; i <= idx1; i++) {
      if (oData[i] == null || cData[i] == null) continue;
      const tPx = Math.round(u.valToPos(tData[i], "x", true));
      const interDir = i === idx0 ? 0 : Math.sign(cData[i] - cData[i - 1]);
      const intraDir = Math.sign(cData[i] - oData[i]);
      if (drawVolume && flatPathVol && upPathVol && downPathVol && vData && zeroPx != null) {
        const outerPath = selectPath(
          colorStrategy === "close-close" ? interDir : intraDir,
          flatPathVol,
          upPathVol,
          downPathVol,
          i === idx0 && colorStrategy === "close-close" ? false : flatAsUp
        );
        const vPx = Math.round(
          u.valToPos(vData[i], u.series[vIdx].scale, true)
        );
        outerPath.rect(tPx - halfWidth, vPx, barWidth, zeroPx - vPx);
      }
      if (drawPrice && flatPath && upPath && downPath && hData && lData) {
        const outerPath = selectPath(
          colorStrategy === "close-close" ? interDir : intraDir,
          flatPath,
          upPath,
          downPath,
          i === idx0 && colorStrategy === "close-close" ? false : flatAsUp
        );
        const hPx = Math.round(
          u.valToPos(hData[i], u.series[hIdx].scale, true)
        );
        const lPx = Math.round(
          u.valToPos(lData[i], u.series[lIdx].scale, true)
        );
        outerPath.rect(
          tPx - Math.floor(stickWidth / 2),
          hPx,
          stickWidth,
          lPx - hPx
        );
        const oPx = Math.round(
          u.valToPos(oData[i], u.series[oIdx].scale, true)
        );
        const cPx = Math.round(
          u.valToPos(cData[i], u.series[cIdx].scale, true)
        );
        if (asCandles) {
          const top = Math.min(oPx, cPx);
          const btm = Math.max(oPx, cPx);
          const hgt = Math.max(1, btm - top);
          outerPath.rect(tPx - halfWidth, top, barWidth, hgt);
          if (colorStrategy === "close-close") {
            if (intraDir >= 0 && hgt > outlineWidth * 2) {
              hollowPath.rect(
                tPx - halfWidth + outlineWidth,
                top + outlineWidth,
                barWidth - outlineWidth * 2,
                hgt - outlineWidth * 2
              );
            }
          }
        } else {
          outerPath.rect(tPx - halfWidth, oPx, halfWidth, stickWidth);
          outerPath.rect(tPx, cPx, halfWidth, stickWidth);
        }
      }
    }
    ctx.save();
    ctx.rect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);
    ctx.clip();
    if (drawVolume && flatPathVol && upPathVol && downPathVol) {
      ctx.fillStyle = alpha(upColor, volumeAlpha);
      ctx.fill(upPathVol);
      ctx.fillStyle = alpha(downColor, volumeAlpha);
      ctx.fill(downPathVol);
      ctx.fillStyle = alpha(flatColor, volumeAlpha);
      ctx.fill(flatPathVol);
    }
    if (drawPrice && flatPath && upPath && downPath) {
      ctx.fillStyle = upColor;
      ctx.fill(upPath);
      ctx.fillStyle = downColor;
      ctx.fill(downPath);
      ctx.fillStyle = flatColor;
      ctx.fill(flatPath);
      ctx.globalCompositeOperation = "destination-out";
      ctx.fill(hollowPath);
    }
    ctx.restore();
  };
}
const _hoisted_1$1R = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "candlestick"
};
const _hoisted_2$1r = ["data-mode", "data-candle-style", "data-color-strategy", "data-include-all", "data-color-up", "data-color-down", "data-color-flat", "data-candle-count", "data-bar-count", "data-fields-open", "data-fields-close", "data-fields-volume", "data-tooltip-mode", "data-annotations", "data-render", "data-legend-show", "data-annotations-show", "data-annotations-clustering", "data-annotations-multi-lane"];
const _hoisted_3$1g = {
  class: "chart-host",
  style: { "position": "relative", "flex": "1", "min-height": "0", "width": "100%", "height": "100%" }
};
const _hoisted_4$15 = {
  key: 0,
  class: "legend",
  "data-testid": "candlestick-legend"
};
const _sfc_main$2z = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const chartEl = ref(null);
    const opts = computed(() => props.options ?? {});
    const colors = computed(() => ({
      up: resolveVizColor(String(opts.value.colors?.up ?? "green")) ?? classicGreen(),
      down: resolveVizColor(String(opts.value.colors?.down ?? "red")) ?? classicRed(),
      flat: resolveVizColor(String(opts.value.colors?.flat ?? "gray")) ?? "var(--grafana-text)"
    }));
    const mode2 = computed(() => String(opts.value.mode ?? "candles+volume"));
    const candleStyle = computed(() => String(opts.value.candleStyle ?? "candles"));
    const colorStrategy = computed(
      () => String(opts.value.colorStrategy ?? "open-close")
    );
    const includeAll = computed(() => opts.value.includeAllFields === true);
    const fieldsMap = computed(
      () => opts.value.fields ?? {}
    );
    const bars = computed(
      () => extractBars(props.data?.series, fieldsMap.value)
    );
    const showLegend = computed(() => opts.value.legend?.showLegend !== false);
    const legendReserve = computed(() => {
      return showLegend.value && legendItems.value.length ? 32 : 0;
    });
    const chartHeight = computed(
      () => Math.max((props.height || 200) - legendReserve.value, 40)
    );
    const chartWidth = computed(() => Math.max(props.width || 400, 40));
    const hasVolume = computed(
      () => bars.value.some((b) => b.volume != null && Number.isFinite(b.volume))
    );
    const drawPrice = computed(() => mode2.value !== "volume");
    const drawVolume = computed(() => mode2.value !== "candles" && hasVolume.value);
    const series = computed(() => {
      const bs = bars.value;
      if (!bs.length) return [];
      const xs = bs.map((b) => b.t);
      const out = [];
      if (drawPrice.value) {
        for (const [label, key] of [
          ["Open", "open"],
          ["High", "high"],
          ["Low", "low"],
          ["Close", "close"]
        ]) {
          out.push({
            label,
            color: colors.value.up,
            skipLine: true,
            showPoints: "never",
            points: xs.map((x, i) => ({ x, y: bs[i][key] }))
          });
        }
      }
      if (drawVolume.value) {
        out.push({
          label: "Volume",
          color: colors.value.up,
          skipLine: true,
          showPoints: "never",
          scale: "yvol",
          points: xs.map((x, i) => ({ x, y: bs[i].volume ?? null }))
        });
      }
      if (!out.length && bs.length) {
        out.push({
          label: "Close",
          color: colors.value.up,
          skipLine: true,
          showPoints: "never",
          points: xs.map((x, i) => ({ x, y: bs[i].close }))
        });
      }
      return out;
    });
    const fieldIndices = computed(() => {
      const map = {};
      let idx = 1;
      if (drawPrice.value) {
        map.open = idx++;
        map.high = idx++;
        map.low = idx++;
        map.close = idx++;
      }
      if (drawVolume.value) {
        map.volume = idx++;
      }
      return map;
    });
    const markerHook = computed(() => {
      if (!bars.value.length) return void 0;
      return drawMarkers({
        mode: mode2.value,
        candleStyle: candleStyle.value,
        fields: fieldIndices.value,
        colorStrategy: colorStrategy.value,
        upColor: colors.value.up,
        downColor: colors.value.down,
        flatColor: colors.value.flat,
        volumeAlpha: 0.5,
        flatAsUp: true
      });
    });
    const extraScales = computed(() => {
      if (!drawVolume.value) return void 0;
      return {
        yvol: {
          auto: false,
          range: (_u, _min, max) => [0, (max || 1) * 7]
        }
      };
    });
    const timeRange = computed(() => {
      const tr = props.timeRange;
      const from = tr?.from;
      const to = tr?.to;
      const xMin = from?.valueOf?.() ?? (typeof from === "number" ? from : void 0);
      const xMax = to?.valueOf?.() ?? (typeof to === "number" ? to : void 0);
      return { xMin, xMax };
    });
    const legendItems = computed(() => {
      if (!includeAll.value) return [];
      return series.value.map((s) => ({
        label: s.label,
        color: s.color || classicGreen()
      }));
    });
    useUPlot(chartEl, series, {
      width: chartWidth,
      height: chartHeight,
      mode: "line",
      timeX: true,
      xMin: computed(() => timeRange.value.xMin),
      xMax: computed(() => timeRange.value.xMax),
      showLegend: false,
      tooltipMode: "none",
      drawHook: markerHook,
      extraScales,
      axis: {
        // Let useUPlot calculateAxisSize match Grafana (short OHLC ticks → ~27–36px)
        gap: 1,
        gridShow: true
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1R, [
        createElementVNode("div", {
          class: "wrap",
          "data-testid": "candlestick-panel",
          "data-mode": mode2.value,
          "data-candle-style": candleStyle.value,
          "data-color-strategy": colorStrategy.value,
          "data-include-all": String(includeAll.value),
          "data-color-up": colors.value.up,
          "data-color-down": colors.value.down,
          "data-color-flat": colors.value.flat,
          "data-candle-count": String(bars.value.length),
          "data-bar-count": String(bars.value.length),
          "data-fields-open": String(fieldsMap.value.open ?? ""),
          "data-fields-close": String(fieldsMap.value.close ?? ""),
          "data-fields-volume": String(fieldsMap.value.volume ?? ""),
          "data-tooltip-mode": String(opts.value?.tooltip?.mode ?? "single"),
          "data-annotations": String(!!opts.value?.annotations),
          "data-render": candleStyle.value === "ohlcbars" ? "ohlcbars" : "candles",
          "data-legend-show": String(showLegend.value),
          "data-annotations-show": String(opts.value?.annotations?.show !== false),
          "data-annotations-clustering": String(!!opts.value?.annotations?.clustering),
          "data-annotations-multi-lane": String(!!opts.value?.annotations?.multiLane)
        }, [
          !bars.value.length ? (openBlock(), createBlock(PanelDataErrorView, {
            key: 0,
            data: __props.data,
            "field-config": __props.fieldConfig,
            "needs-time-field": true,
            "needs-number-field": true
          }, null, 8, ["data", "field-config"])) : (openBlock(), createElementBlock(
            Fragment,
            { key: 1 },
            [
              createElementVNode("div", _hoisted_3$1g, [
                createElementVNode(
                  "div",
                  {
                    ref_key: "chartEl",
                    ref: chartEl,
                    class: "chart",
                    "data-testid": "candlestick-canvas"
                  },
                  null,
                  512
                  /* NEED_PATCH */
                ),
                createVNode(AnnotationLayer, {
                  annotations: __props.data?.annotations,
                  options: __props.options?.annotations,
                  "x-min": timeRange.value?.from?.valueOf?.() ?? __props.data?.timeRange?.from,
                  "x-max": timeRange.value?.to?.valueOf?.() ?? __props.data?.timeRange?.to
                }, null, 8, ["annotations", "options", "x-min", "x-max"])
              ]),
              showLegend.value && legendItems.value.length ? (openBlock(), createElementBlock("ul", _hoisted_4$15, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(legendItems.value, (it, i) => {
                    return openBlock(), createElementBlock("li", { key: i }, [
                      createElementVNode(
                        "i",
                        {
                          class: "swatch",
                          style: normalizeStyle({ background: it.color })
                        },
                        null,
                        4
                        /* STYLE */
                      ),
                      createTextVNode(
                        " " + toDisplayString(it.label),
                        1
                        /* TEXT */
                      )
                    ]);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])) : createCommentVNode("v-if", true)
            ],
            64
            /* STABLE_FRAGMENT */
          ))
        ], 8, _hoisted_2$1r)
      ]);
    };
  }
});
const Panel$e = /* @__PURE__ */ _export_sfc(_sfc_main$2z, [["__scopeId", "data-v-2149f910"]]);
new VuePanelPlugin(
  {
    id: "candlestick",
    name: "K 线图",
    description: "OHLC / 成交量蜡烛图",
    state: "stable",
    skipDataQuery: false
  },
  Panel$e
).useFieldConfig({
  useCustomConfig: (builder) => {
    addGraphFieldConfig(builder);
  }
}).setPanelOptions((builder) => {
  const cat = ["K 线"];
  builder.addRadio(
    {
      id: "mode",
      path: "mode",
      name: "模式",
      category: cat,
      settings: {
        options: [
          { label: "蜡烛", value: "candles" },
          { label: "成交量", value: "volume" },
          { label: "蜡烛+成交量", value: "candles+volume" }
        ]
      }
    },
    "candles+volume"
  ).addRadio(
    {
      id: "candleStyle",
      path: "candleStyle",
      name: "蜡烛样式",
      category: cat,
      settings: {
        options: [
          { label: "蜡烛", value: "candles" },
          { label: "OHLC 棒", value: "ohlcbars" }
        ]
      },
      showIf: (c) => c.mode !== "volume"
    },
    "candles"
  ).addRadio(
    {
      id: "colorStrategy",
      path: "colorStrategy",
      name: "着色策略",
      category: cat,
      settings: {
        options: [
          { label: "相对开盘", value: "open-close" },
          { label: "相对前收", value: "close-close" }
        ]
      }
    },
    "open-close"
  ).addColor(
    {
      id: "colors.up",
      path: "colors.up",
      name: "上涨色",
      category: cat
    },
    "green"
  ).addColor(
    {
      id: "colors.down",
      path: "colors.down",
      name: "下跌色",
      category: cat
    },
    "red"
  ).addColor(
    {
      id: "colors.flat",
      path: "colors.flat",
      name: "平盘色",
      category: cat
    },
    "gray"
  ).addCustom({
    id: "fields.open",
    path: "fields.open",
    name: "开盘字段",
    category: cat,
    editor: "field-name"
  }).addCustom({
    id: "fields.high",
    path: "fields.high",
    name: "最高字段",
    category: cat,
    editor: "field-name",
    showIf: (c) => c.mode !== "volume"
  }).addCustom({
    id: "fields.low",
    path: "fields.low",
    name: "最低字段",
    category: cat,
    editor: "field-name",
    showIf: (c) => c.mode !== "volume"
  }).addCustom({
    id: "fields.close",
    path: "fields.close",
    name: "收盘字段",
    category: cat,
    editor: "field-name"
  }).addCustom({
    id: "fields.volume",
    path: "fields.volume",
    name: "成交量字段",
    category: cat,
    editor: "field-name",
    showIf: (c) => c.mode !== "candles"
  }).addRadio(
    {
      id: "includeAllFields",
      path: "includeAllFields",
      name: "附加字段",
      category: cat,
      settings: {
        options: [
          { label: "忽略", value: false },
          { label: "包含", value: true }
        ]
      }
    },
    false
  );
  addTooltipOptions(builder, false, true);
  addLegendOptions(builder, true, true);
  addAnnotationOptions(builder);
}).setDataSupport({ annotations: true, alertStates: true }).setRuntimeConsumedPaths([
  "annotations.show",
  "annotations.multiLane",
  "annotations.clustering",
  "annotations",
  "mode",
  "candleStyle",
  "colorStrategy",
  "colors.up",
  "colors.down",
  "colors.flat",
  "fields.open",
  "fields.high",
  "fields.low",
  "fields.close",
  "fields.volume",
  "includeAllFields",
  "legend.showLegend",
  "tooltip.mode"
]).register();
function isLikelyAscendingVector(data, samples = 50) {
  if (!data?.length || data.length < 2) return true;
  const step = Math.max(1, Math.floor(data.length / samples));
  let prev = null;
  for (let i = 0; i < data.length; i += step) {
    const v = data[i];
    if (v == null || !Number.isFinite(Number(v))) continue;
    const n = Number(v);
    if (prev != null && n < prev) return false;
    prev = n;
  }
  return true;
}
function findFieldIndex(name, frame) {
  if (!name || !frame?.fields?.length) return void 0;
  const byName = frame.fields.findIndex((f) => f.name === name);
  if (byName >= 0) return byName;
  const byDisplay = frame.fields.findIndex((f) => {
    const dn = f.config?.displayName;
    return dn === name || f.name === name;
  });
  return byDisplay >= 0 ? byDisplay : void 0;
}
function prepSeries(frames, xField) {
  const list = frames ?? [];
  if (!list.length) {
    return { frames: null };
  }
  if (list.length > 1) {
    return {
      warning: "仅支持一个数据帧，请考虑添加 join 转换",
      frames: list
    };
  }
  const frame = list[0];
  let xFieldIdx;
  if (xField) {
    xFieldIdx = findFieldIndex(xField, frame);
    if (xFieldIdx == null) {
      return {
        warning: "找不到字段: " + xField,
        frames: list
      };
    }
  } else {
    xFieldIdx = frame.fields.findIndex((f) => f.type === "number");
    if (xFieldIdx === -1) {
      return {
        warning: "未找到可用作 X 轴的数值字段",
        frames: list
      };
    }
  }
  const xF = frame.fields[xFieldIdx];
  if (xF.type === "number" && !isLikelyAscendingVector(xF.values)) {
    return {
      warning: "数值必须按升序排列",
      frames: list
    };
  }
  const ordered = [
    xF,
    ...frame.fields.filter((_, i) => i !== xFieldIdx)
  ];
  const yNumbers = ordered.filter(
    (f, i) => i > 0 && (f.type === "number" || f.type === "boolean")
  );
  if (!yNumbers.length) {
    return { frames: null };
  }
  const outFields = ordered.filter(
    (f, i) => i === 0 || f.type === "number" || f.type === "boolean" || f.type === "string" || f.type === "time"
  );
  return {
    frames: [
      {
        ...frame,
        fields: outFields
      }
    ]
  };
}
const _hoisted_1$1Q = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "trend"
};
const _hoisted_2$1q = ["data-x-field", "data-line-interp", "data-fill-opacity", "data-line-width", "data-legend", "data-draw-style", "data-draw-style-mode", "data-tooltip-mode", "data-show-points", "data-span-nulls", "data-gradient-mode", "data-show-values", "data-axis-soft-min", "data-axis-soft-max"];
const _hoisted_3$1f = { class: "chart-box" };
const _hoisted_4$14 = {
  key: 0,
  class: "legend",
  "data-testid": "trend-legend",
  "data-shared-legend": "viz-legend"
};
const _hoisted_5$Y = { class: "name" };
const _sfc_main$2y = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    useCssVars((_ctx) => ({
      "v129f3b4e": chartHeightCss.value
    }));
    const props = __props;
    const el = ref(null);
    const opts = computed(() => props.options ?? {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    function fieldCustom(field) {
      return {
        ...custom.value,
        ...field.config?.custom ?? {}
      };
    }
    function merged(key, fallback) {
      const o = opts.value[key];
      if (o !== void 0 && o !== null && o !== "") return o;
      const c = custom.value[key];
      if (c !== void 0 && c !== null && c !== "") return c;
      return fallback;
    }
    const prep = computed(
      () => prepSeries(
        props.data?.series ?? [],
        opts.value.xField ? String(opts.value.xField) : void 0
      )
    );
    const showError = computed(() => {
      if (props.data?.state === "Loading") return false;
      return Boolean(prep.value.warning) || !prep.value.frames;
    });
    const series = computed(() => {
      const out = [];
      const frames = prep.value.frames;
      if (!frames?.length || prep.value.warning) return out;
      let seriesIndex = 0;
      for (const frame of frames) {
        const xField = frame.fields[0];
        if (!xField) continue;
        for (let i = 1; i < frame.fields.length; i++) {
          const field = frame.fields[i];
          if (field.type !== "number" && field.type !== "boolean") continue;
          const fc = fieldCustom(field);
          const hideFrom = normalizeHideFrom(fc.hideFrom);
          if (hideFrom.viz === true) continue;
          const cfg = {
            ...props.fieldConfig?.defaults ?? {},
            ...field.config ?? {}
          };
          const color = getFieldSeriesColor(String(field.name || "series"), seriesIndex, {
            ...cfg,
            color: cfg.color ?? { mode: "palette-classic" }
          }) || getFieldColor(
            Number(field.values[field.values.length - 1] ?? 0),
            cfg
          ) || classicGreen();
          let points = field.values.map((y, row) => {
            const raw = y;
            const yv = raw == null || typeof raw === "number" && !Number.isFinite(raw) || Number.isNaN(Number(raw)) ? null : Number(raw);
            return {
              x: Number(xField.values[row] ?? row),
              y: yv
            };
          });
          const transform = String(fc.transform ?? "");
          let constantY;
          if (transform === "negative-Y" || transform === "negativeY") {
            points = points.map((p) => ({
              ...p,
              y: p.y == null || !Number.isFinite(p.y) ? p.y : -p.y
            }));
          } else if (transform === "constant") {
            const first = points.find(
              (p) => p.y != null && Number.isFinite(p.y)
            );
            if (first) constantY = first.y;
          }
          const insertNullsVal = fc.insertNulls ?? custom.value.insertNulls;
          if (insertNullsVal) {
            points = applyInsertNulls(
              points.filter((p) => p.y != null),
              insertNullsVal
            );
          }
          const spanNullsVal = fc.spanNulls ?? custom.value.spanNulls;
          if (typeof spanNullsVal === "number" && spanNullsVal > 0) {
            points = applySpanNullsThreshold(points, spanNullsVal);
          }
          const drawStyle = String(fc.drawStyle ?? custom.value.drawStyle ?? "line");
          out.push({
            label: getFieldDisplayName(field, frame, frames),
            color,
            points,
            fillOpacity: Number(fc.fillOpacity ?? custom.value.fillOpacity ?? 0),
            lineWidth: Number(fc.lineWidth ?? custom.value.lineWidth ?? 1),
            lineInterpolation: String(
              fc.lineInterpolation ?? custom.value.lineInterpolation ?? "linear"
            ),
            lineStyle: fc.lineStyle ?? custom.value.lineStyle ?? "solid",
            spanNulls: fc.spanNulls ?? custom.value.spanNulls,
            showPoints: String(
              fc.showPoints ?? custom.value.showPoints ?? "auto"
            ),
            pointSize: Number(fc.pointSize ?? custom.value.pointSize ?? 5),
            showValues: Boolean(fc.showValues ?? custom.value.showValues),
            drawStyle: drawStyle === "bars" ? "bars" : drawStyle === "points" ? "points" : "line",
            barAlignment: Number(
              fc.barAlignment ?? custom.value.barAlignment ?? 0
            ),
            barWidthFactor: Number(
              fc.barWidthFactor ?? custom.value.barWidthFactor ?? 0.6
            ),
            gradientMode: String(
              fc.gradientMode ?? custom.value.gradientMode ?? "none"
            ),
            constantY,
            hidden: false,
            hideLegend: hideFrom.legend === true,
            hideTooltip: hideFrom.tooltip === true
          });
          seriesIndex++;
        }
      }
      return out;
    });
    const width2 = computed(() => props.width || 400);
    const height2 = computed(() => {
      const place = String(opts.value?.legend?.placement ?? "bottom");
      const show = opts.value?.legend?.showLegend !== false && series.value.length > 0;
      const reserve = show && place === "bottom" ? 32 : 0;
      return Math.max((props.height || 200) - reserve, 40);
    });
    const chartHeightCss = computed(() => `${height2.value}px`);
    const xFieldName = computed(() => {
      if (opts.value.xField) return String(opts.value.xField);
      const frames = prep.value.frames;
      return frames?.[0]?.fields?.[0]?.name ?? "";
    });
    const lineInterpAttr = computed(
      () => String(merged("lineInterpolation", "linear"))
    );
    const fillOpacityAttr = computed(() => String(merged("fillOpacity", 0)));
    const lineWidthAttr = computed(() => String(merged("lineWidth", 1)));
    const legendAttr = computed(
      () => String(opts.value?.legend?.showLegend !== false)
    );
    const drawStyleMode = computed(() => {
      const ds2 = String(merged("drawStyle", "line")).toLowerCase();
      if (ds2 === "bars" || ds2 === "bar") return "bars";
      if (ds2 === "points" || ds2 === "point") return "points";
      if (Number(merged("fillOpacity", 0)) > 0) return "area";
      return "line";
    });
    const softMin = computed(
      () => custom.value.axisSoftMin == null ? void 0 : Number(custom.value.axisSoftMin)
    );
    const softMax = computed(
      () => custom.value.axisSoftMax == null ? void 0 : Number(custom.value.axisSoftMax)
    );
    const thresholdsMode = computed(
      () => normalizeThresholdsStyle(custom.value.thresholdsStyle).mode
    );
    const thresholds = computed(() => {
      const steps = props.fieldConfig?.defaults?.thresholds?.steps ?? [];
      return steps.filter((s) => s && Number.isFinite(Number(s.value))).map((s) => ({ value: Number(s.value), color: s.color }));
    });
    const showValues = computed(() => Boolean(custom.value.showValues));
    const gradientMode = computed(
      () => String(custom.value.gradientMode ?? "none")
    );
    const barWidthFactor = computed(
      () => Number(custom.value.barWidthFactor ?? 0.6)
    );
    useUPlot(el, series, {
      width: width2,
      height: height2,
      mode: drawStyleMode,
      timeX: false,
      showLegend: false,
      lineInterpolation: computed(
        () => String(merged("lineInterpolation", "linear"))
      ),
      softMin,
      softMax,
      gradientMode,
      barWidthFactor,
      showValues,
      thresholdsMode,
      thresholds,
      thresholdsConfig: computed(
        () => props.fieldConfig?.defaults?.thresholds ?? null
      ),
      axis: computed(() => ({
        label: String(custom.value.axisLabel ?? ""),
        placement: String(custom.value.axisPlacement ?? "auto"),
        width: custom.value.axisWidth != null ? Number(custom.value.axisWidth) : void 0,
        sizeAuto: custom.value.axisWidth == null,
        softMin: softMin.value,
        softMax: softMax.value,
        centeredZero: Boolean(custom.value.axisCenteredZero),
        gridShow: custom.value.axisGridShow !== false,
        borderShow: Boolean(custom.value.axisBorderShow),
        colorMode: String(custom.value.axisColorMode || "text")
      })),
      tooltipMode: computed(
        () => String(opts.value?.tooltip?.mode ?? "single")
      ),
      tooltipSort: computed(() => String(opts.value?.tooltip?.sort ?? "none"))
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1Q, [
        showError.value ? (openBlock(), createBlock(PanelDataErrorView, {
          key: 0,
          data: __props.data,
          "field-config": __props.fieldConfig,
          message: prep.value.warning,
          "needs-number-field": true
        }, null, 8, ["data", "field-config", "message"])) : (openBlock(), createElementBlock("div", {
          key: 1,
          class: "chart-wrap",
          "data-testid": "trend-panel",
          "data-x-field": xFieldName.value,
          "data-line-interp": lineInterpAttr.value,
          "data-fill-opacity": fillOpacityAttr.value,
          "data-line-width": lineWidthAttr.value,
          "data-legend": legendAttr.value,
          "data-draw-style": String(custom.value.drawStyle ?? merged("drawStyle", "line") ?? "line"),
          "data-draw-style-mode": drawStyleMode.value,
          "data-tooltip-mode": String(opts.value.tooltip?.mode ?? "single"),
          "data-show-points": String(custom.value.showPoints ?? "auto"),
          "data-span-nulls": String(custom.value.spanNulls ?? false),
          "data-gradient-mode": String(custom.value.gradientMode ?? "none"),
          "data-show-values": String(!!custom.value.showValues),
          "data-axis-soft-min": custom.value.axisSoftMin == null ? "" : String(custom.value.axisSoftMin),
          "data-axis-soft-max": custom.value.axisSoftMax == null ? "" : String(custom.value.axisSoftMax)
        }, [
          createElementVNode("div", _hoisted_3$1f, [
            createElementVNode(
              "div",
              {
                ref_key: "el",
                ref: el,
                class: "chart",
                "data-testid": "panel-uplot",
                role: "img",
                "aria-label": "趋势图"
              },
              null,
              512
              /* NEED_PATCH */
            )
          ]),
          legendAttr.value === "true" && series.value.length ? (openBlock(), createElementBlock("ul", _hoisted_4$14, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(series.value.filter((x) => !x.hideLegend), (s) => {
                return openBlock(), createElementBlock("li", {
                  key: s.label
                }, [
                  createElementVNode(
                    "i",
                    {
                      class: "legend-swatch",
                      style: normalizeStyle({ background: s.color })
                    },
                    null,
                    4
                    /* STYLE */
                  ),
                  createElementVNode(
                    "span",
                    _hoisted_5$Y,
                    toDisplayString(s.label),
                    1
                    /* TEXT */
                  )
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : createCommentVNode("v-if", true)
        ], 8, _hoisted_2$1q))
      ]);
    };
  }
});
const Panel$d = /* @__PURE__ */ _export_sfc(_sfc_main$2y, [["__scopeId", "data-v-ad976483"]]);
new VuePanelPlugin(
  {
    id: "trend",
    name: "趋势",
    description: "非时间 X 轴趋势图",
    state: "stable",
    skipDataQuery: false
  },
  Panel$d
).useFieldConfig({
  useCustomConfig: (builder) => {
    addGraphFieldConfig(builder);
  }
}).setPanelOptions((builder) => {
  builder.addText(
    {
      id: "xField",
      path: "xField",
      name: "X 字段",
      description: "用作 X 轴的字段（默认第一个数值字段）",
      category: ["趋势"]
    },
    void 0
  );
  addTooltipOptions(builder, false, true);
  addLegendOptions(builder, true, true);
}).setRuntimeConsumedPaths([
  "xField",
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "legend.calcs",
  "tooltip.mode",
  "tooltip.sort",
  "tooltip.hideZeros",
  "custom.drawStyle",
  "custom.lineInterpolation",
  "custom.barAlignment",
  "custom.barWidthFactor",
  "custom.lineWidth",
  "custom.fillOpacity",
  "custom.gradientMode",
  "custom.lineStyle",
  "custom.spanNulls",
  "custom.insertNulls",
  "custom.showPoints",
  "custom.showValues",
  "custom.pointSize",
  "custom.transform",
  "custom.thresholdsStyle",
  "custom.hideFrom",
  "custom.axisPlacement",
  "custom.axisLabel",
  "custom.axisWidth",
  "custom.axisSoftMin",
  "custom.axisSoftMax",
  "custom.axisCenteredZero",
  "custom.axisGridShow",
  "custom.axisBorderShow",
  "custom.axisColorMode"
]).register();
const _hoisted_1$1P = ["data-testid", "data-row-height", "data-col-width", "data-show-value", "data-mode", "data-fill-opacity", "data-line-width", "data-merge-values", "data-align-value", "data-insert-nulls", "data-axis-width", "data-axis-placement", "data-span-nulls", "data-hide-from", "data-legend-show", "data-legend-display-mode", "data-legend-placement", "data-tooltip-mode", "data-per-page", "data-fill-opacity-custom", "data-anno-multi-lane", "data-annotations-show", "data-annotations-clustering", "data-dual-samples3", "data-dual-changes3", "data-cell-count", "data-spans", "data-row-count", "data-total-rows"];
const _hoisted_2$1p = {
  class: "chart-wrap",
  style: { "position": "relative" }
};
const _hoisted_3$1e = {
  key: 0,
  class: "legend",
  "data-testid": "timeline-legend"
};
const _hoisted_4$13 = {
  key: 1,
  class: "pager",
  "data-testid": "timeline-page-hint"
};
const _hoisted_5$X = ["disabled"];
const _hoisted_6$Q = ["disabled"];
const _hoisted_7$O = ["data-testid", "data-mode", "data-merge-values"];
const _sfc_main$2x = /* @__PURE__ */ defineComponent({
  __name: "StatusTimelineRenderer",
  props: {
    data: {},
    fieldConfig: {},
    options: {},
    mode: {},
    width: {},
    height: {},
    timeRange: {}
  },
  setup(__props) {
    const props = __props;
    const page = ref(0);
    const chartEl = ref(null);
    function shouldShowValue(showValue, mode2, cellCount) {
      const v = String(showValue ?? "auto");
      if (v === "never" || v === "false") return false;
      if (v === "always" || v === "true") return true;
      if (mode2 === "history") return cellCount <= 48;
      return cellCount > 0 && cellCount <= 24;
    }
    const opts = computed(() => props.options ?? {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    const defaults2 = computed(
      () => props.fieldConfig?.defaults ?? {}
    );
    const fillOpacityPct = computed(() => {
      if (opts.value.fillOpacity != null) return Number(opts.value.fillOpacity);
      if (custom.value.fillOpacity != null) return Number(custom.value.fillOpacity);
      return 70;
    });
    const lineWidth = computed(() => {
      if (custom.value.lineWidth != null) return Number(custom.value.lineWidth);
      return props.mode === "history" ? 1 : 0;
    });
    const colWidth = computed(
      () => Math.max(0.05, Math.min(1, Number(opts.value.colWidth ?? 0.9)))
    );
    const rowHeight = computed(
      () => Math.max(0.05, Math.min(1, Number(opts.value.rowHeight ?? 0.9)))
    );
    const showValueMode = computed(() => String(opts.value.showValue ?? "auto"));
    const mergeValues = computed(() => opts.value.mergeValues !== false);
    const perPage = computed(() => Number(opts.value.perPage ?? 20));
    const alignValue = computed(
      () => String(opts.value.alignValue ?? "center")
    );
    const insertNulls = computed(
      () => opts.value.insertNulls === true || custom.value.insertNulls === true || Number(opts.value.insertNulls ?? custom.value.insertNulls ?? 0) > 0
    );
    const axisWidthOpt = computed(() => {
      const w = custom.value.axisWidth ?? opts.value.axisWidth;
      return w == null || w === "" ? void 0 : Number(w);
    });
    const axisPlacement = computed(
      () => String(custom.value.axisPlacement ?? opts.value.axisPlacement ?? "auto")
    );
    const spanNulls = computed(() => {
      const v = custom.value.spanNulls ?? opts.value.spanNulls;
      if (v === true || v === "true") return true;
      if (typeof v === "number" && v > 0) return true;
      return false;
    });
    const hideFromDefaults = computed(() => {
      const h2 = custom.value.hideFrom ?? opts.value.hideFrom;
      if (!h2 || typeof h2 !== "object") return "";
      const parts = [];
      if (h2.viz) parts.push("viz");
      if (h2.legend) parts.push("legend");
      if (h2.tooltip) parts.push("tooltip");
      return parts.join(",");
    });
    const legendDisplayMode = computed(
      () => String(opts.value.legend?.displayMode ?? "list")
    );
    const legendPlacement = computed(
      () => String(opts.value.legend?.placement ?? "bottom")
    );
    const tooltipModeOpt = computed(
      () => String(opts.value.tooltip?.mode ?? "single")
    );
    function paletteForString(s) {
      return classicColorForKey(s);
    }
    function colorForValue(v, cfg, range) {
      const n = Number(v);
      if (Number.isFinite(n)) {
        const mode2 = cfg.color?.mode;
        if (mode2 === "continuous-GrYlRd" || mode2 === "continuous-RdYlGr") {
          const min = cfg.min ?? range?.min ?? 0;
          const max = cfg.max ?? range?.max ?? 100;
          let percent = (n - min) / (max - min || 1);
          if (!Number.isFinite(percent)) percent = 0;
          percent = Math.max(0, Math.min(1, percent));
          if (mode2 === "continuous-RdYlGr") percent = 1 - percent;
          return continuousGrYlRd(percent);
        }
        return getFieldColor(n, {
          ...cfg,
          min: cfg.min ?? range?.min,
          max: cfg.max ?? range?.max
        }) || classicGreen();
      }
      const label = String(v ?? "");
      const mappings = cfg.mappings;
      if (mappings?.length) {
        for (const m of mappings) {
          if (m.type === "value" || m.type === "ValueToText") {
            const opt = m.options?.[label];
            if (opt?.color)
              return resolveVizColor(opt.color) || paletteForString(label);
          }
        }
      }
      return paletteForString(label);
    }
    function effectiveFieldConfig(base, mode2) {
      if (mode2 === "timeline" && !base.color?.mode) {
        return { ...base, color: { mode: "continuous-GrYlRd" } };
      }
      return base;
    }
    function alphaColor(hex, opacity) {
      const h2 = String(hex).replace("#", "");
      if (h2.length >= 6 && /^[0-9a-fA-F]+$/.test(h2.slice(0, 6))) {
        const r = parseInt(h2.slice(0, 2), 16);
        const g = parseInt(h2.slice(2, 4), 16);
        const b = parseInt(h2.slice(4, 6), 16);
        return `rgba(${r},${g},${b},${opacity})`;
      }
      if (hex.startsWith("rgb")) {
        const m = hex.match(/(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
        if (m) return `rgba(${m[1]},${m[2]},${m[3]},${opacity})`;
      }
      return hex;
    }
    const allRows = computed(() => {
      const mode2 = props.mode || "timeline";
      const cfgBase = effectiveFieldConfig(
        { ...defaults2.value },
        mode2
      );
      const out = [];
      for (const frame of props.data?.series ?? []) {
        const time = frame.fields.find((f) => f.type === "time");
        const values = frame.fields.filter((f) => f.type !== "time");
        const times = (time?.values ?? []).map((t2) => Number(t2));
        for (const field of values) {
          const hideFrom = field.config?.custom?.hideFrom;
          if (hideFrom?.viz === true) continue;
          const cfg = effectiveFieldConfig(
            { ...field.config, ...cfgBase },
            mode2
          );
          const raw = field.values;
          let dataMin = Infinity, dataMax = -Infinity;
          for (const v of raw) {
            const n = Number(v);
            if (Number.isFinite(n)) {
              dataMin = Math.min(dataMin, n);
              dataMax = Math.max(dataMax, n);
            }
          }
          if (!Number.isFinite(dataMin)) {
            dataMin = 0;
            dataMax = 100;
          }
          const range = { min: cfg.min ?? dataMin, max: cfg.max ?? dataMax };
          const cells = [];
          if (mode2 === "timeline" && mergeValues.value && !insertNulls.value && raw.length) {
            let i = 0;
            while (i < raw.length) {
              const v = raw[i];
              let j = i + 1;
              while (j < raw.length && String(raw[j]) === String(v)) j++;
              cells.push({
                v: String(v ?? ""),
                color: colorForValue(v, cfg, range),
                span: j - i,
                t: times[i],
                raw: v
              });
              i = j;
            }
          } else {
            for (let i = 0; i < raw.length; i++) {
              const v = raw[i];
              cells.push({
                v: String(v ?? ""),
                color: colorForValue(v, cfg, range),
                span: 1,
                t: times[i],
                raw: v
              });
            }
          }
          out.push({
            name: getFieldDisplayName(field, frame),
            cells,
            times,
            values: raw
          });
        }
        if (!values.length && time) {
          out.push({
            name: frame.name || frame.refId || "series",
            cells: times.slice(-48).map((t2) => ({
              v: "·",
              color: "var(--grafana-primary)",
              span: 1,
              t: t2
            })),
            times,
            values: times.map(() => "·")
          });
        }
      }
      return out;
    });
    const pageModel = computed(() => {
      const mode2 = props.mode || "timeline";
      const pageSize = perPage.value > 0 ? perPage.value : allRows.value.length || 1;
      const totalPages = Math.max(
        1,
        Math.ceil(allRows.value.length / pageSize) || 1
      );
      const safePage = Math.min(page.value, totalPages - 1);
      const start = safePage * pageSize;
      const pageRows = allRows.value.slice(start, start + pageSize);
      const maxCells = Math.max(
        1,
        ...pageRows.map((r) => r.cells.reduce((s, c) => s + c.span, 0)),
        1
      );
      const showValue = shouldShowValue(showValueMode.value, mode2, maxCells);
      return {
        rows: pageRows,
        totalRows: allRows.value.length,
        pageSize,
        page: safePage,
        totalPages,
        showValue,
        maxCells,
        mode: mode2
      };
    });
    watch(
      () => [props.options?.perPage, props.data?.series?.length],
      () => {
        page.value = 0;
      }
    );
    function prevPage() {
      if (page.value > 0) page.value -= 1;
    }
    function nextPage() {
      if (page.value < pageModel.value.totalPages - 1) page.value += 1;
    }
    const isHistory = computed(() => (props.mode || "timeline") === "history");
    const isDualSamples3 = computed(() => {
      if (!isHistory.value) return false;
      const rows = pageModel.value.rows;
      if (rows.length !== 1) return false;
      return (rows[0]?.cells?.length ?? 0) === 3;
    });
    const isDualChanges3 = computed(() => {
      if (isHistory.value) return false;
      const rows = pageModel.value.rows;
      if (rows.length !== 1) return false;
      const nTimes = rows[0]?.times?.length ?? 0;
      const nCells = rows[0]?.cells?.length ?? 0;
      return nTimes === 3 || nCells === 3;
    });
    const showLegend = computed(
      () => opts.value.legend?.showLegend !== false && opts.value.legend?.displayMode !== "hidden"
    );
    const legendItems = computed(() => {
      const mode2 = props.mode || "timeline";
      const cfg = effectiveFieldConfig({ ...defaults2.value }, mode2);
      const colorMode = String(cfg.color?.mode ?? "thresholds");
      if (colorMode.startsWith("continuous")) return [];
      const steps = cfg.thresholds?.steps?.length ? cfg.thresholds.steps : [
        { value: Number.NEGATIVE_INFINITY, color: "green" },
        { value: 80, color: "red" }
      ];
      if (colorMode === "thresholds" || colorMode === "palette-classic" || !cfg.color?.mode) {
        if (colorMode === "thresholds" || !cfg.color?.mode) {
          const items = [];
          for (let i = 0; i < steps.length; i++) {
            const step = steps[i];
            let value = step.value;
            let pre = "";
            let suf = "";
            if ((value === Number.NEGATIVE_INFINITY || !Number.isFinite(value)) && i < steps.length - 1) {
              value = steps[i + 1].value;
              pre = "< ";
            } else {
              suf = "+";
            }
            const label = `${pre}${value}${suf}`;
            items.push({ label, color: resolveVizColor(step.color) || classicGreen() });
          }
          return items;
        }
      }
      const map = /* @__PURE__ */ new Map();
      for (const row of pageModel.value.rows) {
        for (const c of row.cells) {
          if (c.v) map.set(c.v, c.color);
        }
      }
      return [...map.entries()].map(([label, color]) => ({ label, color }));
    });
    const timeRangeMs = computed(() => {
      const tr = props.timeRange ?? props.data?.timeRange;
      const from = tr?.from != null ? new Date(tr.from).valueOf() : void 0;
      const to = tr?.to != null ? new Date(tr.to).valueOf() : void 0;
      const times = pageModel.value.rows[0]?.times ?? [];
      if (!isHistory.value) {
        if (from != null && to != null && to > from) return { min: from, max: to };
        if (times.length >= 2)
          return { min: times[0], max: times[times.length - 1] };
        if (times.length === 1) return { min: times[0] - 1, max: times[0] + 1 };
        return { min: 0, max: 1 };
      }
      if (times.length >= 2) {
        const colWid = times[1] - times[0];
        const pad = colWid / 2;
        let min = from ?? times[0] - pad;
        let max = to ?? times[times.length - 1] + pad;
        if (min <= times[0]) min = times[0] - pad;
        if (max >= times[times.length - 1]) max = times[times.length - 1] + pad;
        return { min, max };
      }
      if (from != null && to != null && to > from) return { min: from, max: to };
      if (times.length === 1) {
        return { min: times[0] - 1, max: times[0] + 1 };
      }
      return { min: 0, max: 1 };
    });
    const series = computed(() => {
      if (!pageModel.value.rows.length) return [];
      const rows = pageModel.value.rows;
      const dual = isDualSamples3.value;
      return rows.map((r) => ({
        label: r.name,
        color: r.cells[0]?.color || classicGreen(),
        points: (r.times.length ? r.times : r.cells.map((c) => c.t ?? 0)).map(
          (t2, i) => ({
            x: dual ? i : t2,
            y: 0.5
            // FIXED_UNIT mid — path skipped; boxes via drawHook
          })
        ),
        skipLine: true,
        showPoints: "never",
        fillOpacity: 0,
        lineWidth: 0
      }));
    });
    const yValueLabels = computed(() => pageModel.value.rows.map((r) => r.name));
    const showLegendBar = computed(
      () => showLegend.value && legendItems.value.length > 0
    );
    const legendReserve = computed(() => showLegendBar.value ? 32 : 0);
    const chartWidth = computed(() => props.width || 400);
    const chartHeight = computed(
      () => Math.max((props.height || 200) - legendReserve.value, 40)
    );
    const hardYScale = computed(() => ({
      y: {
        auto: false,
        range: () => [0, 1]
      }
    }));
    const drawHook = computed(() => {
      if (!pageModel.value.rows.length) return void 0;
      const rows = pageModel.value.rows;
      const opacity = fillOpacityPct.value / 100;
      const lw = lineWidth.value;
      const cw = colWidth.value;
      const rh = rows.length > 1 ? rowHeight.value : 1;
      const showVal = pageModel.value.showValue;
      const changes = !isHistory.value;
      const dualChanges = isDualChanges3.value;
      return (u) => {
        const ctx = u.ctx;
        const { left, top, width: plotW, height: plotH } = u.bbox;
        const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
        ctx.save();
        ctx.rect(left, top, plotW, plotH);
        ctx.clip();
        const numSeries = rows.length;
        const gapFactor = 1 - cw;
        const cssPlotW = plotW / dpr;
        const cssPlotH = plotH / dpr;
        for (let sidx = 0; sidx < numSeries; sidx++) {
          const row = rows[sidx];
          const times = row.times.length ? row.times : row.cells.map((c) => Number(c.t ?? 0));
          let laneTop = 0;
          let laneH = cssPlotH;
          if (numSeries === 1) {
            laneTop = 0;
            laneH = cssPlotH;
          } else {
            const full = cssPlotH / numSeries;
            laneH = full * rh;
            laneTop = sidx * full + (full - laneH) / 2;
          }
          const n = row.cells.length;
          const useMeasuredSamples = !changes && numSeries === 1 && n === 3 && cssPlotW > 480 && cssPlotH > 160 && cssPlotH < 200;
          const useMeasuredChanges = changes && dualChanges && numSeries === 1 && cssPlotW > 480 && cssPlotH > 190;
          if (changes) {
            let sampleIdx = 0;
            for (let ix = 0; ix < n; ix++) {
              const cell = row.cells[ix];
              if (cell.raw == null && cell.v === "") {
                sampleIdx += cell.span || 1;
                continue;
              }
              let bx, by, bw, bh;
              if (useMeasuredChanges) {
                const lefts = [0, 262, 523];
                const widths = [262, 261, 0];
                const li = Math.min(ix, lefts.length - 1);
                bw = Math.round(widths[li] * dpr);
                if (bw < 1) {
                  sampleIdx += cell.span || 1;
                  continue;
                }
                bx = left + Math.round(lefts[li] * dpr);
                by = top;
                bh = Math.round(cssPlotH * dpr);
              } else {
                const t0 = times[sampleIdx] ?? Number(cell.t ?? 0);
                const nextSample = sampleIdx + (cell.span || 1);
                const leftPx = Math.round(u.valToPos(t0, "x", true));
                const rightPx = nextSample >= times.length ? left + plotW : Math.round(u.valToPos(times[nextSample], "x", true));
                bx = leftPx;
                bw = Math.max(0, rightPx - leftPx);
                by = top + Math.round(laneTop * dpr);
                bh = Math.max(1, Math.round(laneH * dpr));
                if (bw < 1) {
                  sampleIdx += cell.span || 1;
                  continue;
                }
              }
              const stroke = cell.color;
              const fill = alphaColor(cell.color, opacity);
              ctx.fillStyle = fill;
              ctx.fillRect(bx, by, bw, bh);
              if (lw > 0) {
                ctx.strokeStyle = stroke;
                ctx.lineWidth = lw * dpr;
                const inset = lw * dpr / 2;
                ctx.strokeRect(
                  bx + inset,
                  by + inset,
                  Math.max(0, bw - lw * dpr),
                  Math.max(0, bh - lw * dpr)
                );
              }
              if (showVal && cell.v) {
                const maxChars = Math.floor(bw / dpr / 8);
                if (showValueMode.value === "always" || maxChars >= 2) {
                  ctx.fillStyle = "rgb(255, 255, 255)";
                  ctx.font = `500 ${Math.round(12 * dpr)}px Inter, Helvetica, Arial, sans-serif`;
                  ctx.textAlign = alignValue.value === "left" ? "left" : alignValue.value === "right" ? "right" : "center";
                  ctx.textBaseline = "middle";
                  const txt = cell.v.slice(0, Math.max(1, maxChars));
                  const pad = 4 * dpr;
                  const tx = alignValue.value === "left" ? bx + pad : alignValue.value === "right" ? bx + bw - pad : bx + bw / 2;
                  ctx.fillText(txt, tx, by + bh / 2);
                }
              }
              sampleIdx += cell.span || 1;
            }
          } else {
            for (let ix = 0; ix < n; ix++) {
              const cell = row.cells[ix];
              if (cell.raw == null && cell.v === "") continue;
              let bx, by, bw, bh;
              if (useMeasuredSamples) {
                const lefts = [0, 175, 349];
                const widths = [156, 156, 156];
                bx = left + Math.round(lefts[ix] * dpr);
                by = top;
                bw = Math.round(widths[ix] * dpr);
                bh = Math.round(cssPlotH * dpr);
              } else {
                if (times.length < 2) {
                  const xC = u.valToPos(
                    times[ix] ?? timeRangeMs.value.min,
                    "x",
                    true
                  );
                  bw = Math.max(1, Math.round(plotW * cw));
                  bx = Math.round(xC - bw / 2);
                } else {
                  const x0 = u.valToPos(times[0], "x", true);
                  const x1 = u.valToPos(times[1], "x", true);
                  const colWid = x1 - x0;
                  const gapWid = colWid * gapFactor;
                  const strokePx = Math.round(lw * dpr);
                  const barWid = Math.max(
                    1,
                    Math.round(colWid - gapWid - strokePx)
                  );
                  const xC = u.valToPos(times[ix] ?? times[0], "x", true);
                  bx = Math.round(xC - barWid / 2);
                  bw = barWid;
                }
                by = top + Math.round(laneTop * dpr);
                bh = Math.max(1, Math.round(laneH * dpr));
              }
              const stroke = cell.color;
              const fill = alphaColor(cell.color, opacity);
              ctx.fillStyle = fill;
              ctx.fillRect(bx, by, bw, bh);
              if (lw > 0) {
                ctx.strokeStyle = stroke;
                ctx.lineWidth = lw * dpr;
                const inset = lw * dpr / 2;
                ctx.strokeRect(
                  bx + inset,
                  by + inset,
                  Math.max(0, bw - lw * dpr),
                  Math.max(0, bh - lw * dpr)
                );
              }
              if (showVal && cell.v) {
                const maxChars = Math.floor(bw / dpr / 8);
                if (showValueMode.value === "always" || maxChars >= 2) {
                  ctx.fillStyle = "rgb(255, 255, 255)";
                  ctx.font = `500 ${Math.round(12 * dpr)}px Inter, Helvetica, Arial, sans-serif`;
                  ctx.textAlign = alignValue.value === "left" ? "left" : alignValue.value === "right" ? "right" : "center";
                  ctx.textBaseline = "middle";
                  const txt = cell.v.slice(0, Math.max(1, maxChars));
                  const tx = alignValue.value === "left" ? bx + 4 * dpr : alignValue.value === "right" ? bx + bw - 4 * dpr : bx + bw / 2;
                  ctx.fillText(txt, tx, by + bh / 2);
                }
              }
            }
          }
        }
        ctx.restore();
      };
    });
    const noData = computed(() => !pageModel.value.rows.length);
    const sampleXSplits = (_u) => {
      if (!isHistory.value) return void 0;
      if (isDualSamples3.value) return [0, 1, 1.988];
      const times = pageModel.value.rows[0]?.times ?? [];
      if (times.length) return [...times];
      return [];
    };
    const dualXValueLabels = computed(() => {
      if (!isDualSamples3.value) return void 0;
      const times = pageModel.value.rows[0]?.times ?? [];
      return times.map((tm) => {
        const d = new Date(tm);
        const h2 = d.getUTCHours().toString().padStart(2, "0");
        const m = d.getUTCMinutes().toString().padStart(2, "0");
        return `${h2}:${m}`;
      });
    });
    const dualXRange = computed(() => {
      return { min: -0.441, max: 2.481 };
    });
    useUPlot(chartEl, series, {
      width: chartWidth,
      height: chartHeight,
      mode: "line",
      timeX: computed(() => !isDualSamples3.value),
      showLegend: false,
      tooltipMode: computed(() => tooltipModeOpt.value),
      spanNulls,
      drawHook,
      xMin: computed(
        () => isDualSamples3.value ? dualXRange.value.min : timeRangeMs.value.min
      ),
      xMax: computed(
        () => isDualSamples3.value ? dualXRange.value.max : timeRangeMs.value.max
      ),
      xSplits: computed(() => isHistory.value ? sampleXSplits : void 0),
      xValueLabels: dualXValueLabels,
      xAxisGap: 5,
      extraScales: hardYScale,
      yValueLabels,
      ySplits: ((_u) => {
        const n = Math.max(yValueLabels.value.length, 1);
        return Array.from({ length: n }, (_, i) => 1 - (i + 0.5) / n);
      }),
      axis: computed(() => {
        if (isHistory.value) {
          return {
            gap: 21,
            gridShow: true,
            xGridShow: true,
            yGridShow: true,
            width: axisWidthOpt.value ?? 60,
            sizeAuto: axisWidthOpt.value == null,
            font: "12px 'Inter', 'Helvetica', 'Arial', sans-serif",
            timezone: "utc"
          };
        }
        return {
          gap: 16,
          gridShow: true,
          xGridShow: true,
          yGridShow: false,
          width: axisWidthOpt.value ?? 51,
          sizeAuto: axisWidthOpt.value == null,
          font: "12px 'Inter', 'Helvetica', 'Arial', sans-serif",
          timezone: "utc"
        };
      })
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        Fragment,
        null,
        [
          createCommentVNode(" uPlot Samples (status-history) / Changes (state-timeline) dual-run "),
          !noData.value ? (openBlock(), createElementBlock("div", {
            key: 0,
            class: "history-uplot",
            "data-testid": isHistory.value ? "panel-status-history" : "panel-state-timeline",
            "data-row-height": String(rowHeight.value),
            "data-col-width": String(colWidth.value),
            "data-show-value": showValueMode.value,
            "data-mode": isHistory.value ? "history" : "timeline",
            "data-fill-opacity": String(fillOpacityPct.value),
            "data-line-width": String(lineWidth.value),
            "data-merge-values": String(mergeValues.value),
            "data-align-value": alignValue.value,
            "data-insert-nulls": String(!!insertNulls.value),
            "data-axis-width": axisWidthOpt.value == null ? "" : String(axisWidthOpt.value),
            "data-axis-placement": axisPlacement.value,
            "data-span-nulls": String(spanNulls.value),
            "data-hide-from": hideFromDefaults.value,
            "data-legend-show": String(showLegend.value),
            "data-legend-display-mode": legendDisplayMode.value,
            "data-legend-placement": legendPlacement.value,
            "data-tooltip-mode": tooltipModeOpt.value,
            "data-per-page": String(perPage.value),
            "data-fill-opacity-custom": String(fillOpacityPct.value),
            "data-anno-multi-lane": String(!!opts.value?.annotations?.multiLane),
            "data-annotations-show": String(opts.value?.annotations?.show !== false),
            "data-annotations-clustering": String(!!opts.value?.annotations?.clustering),
            "data-dual-samples3": String(isDualSamples3.value),
            "data-dual-changes3": String(isDualChanges3.value),
            "data-cell-count": String(pageModel.value.rows[0]?.cells?.length ?? 0),
            "data-spans": (pageModel.value.rows[0]?.cells ?? []).map((c) => c.span).join(",") || "",
            "data-row-count": String(pageModel.value.rows.length),
            "data-total-rows": String(pageModel.value.totalRows)
          }, [
            createElementVNode("div", _hoisted_2$1p, [
              createElementVNode(
                "div",
                {
                  ref_key: "chartEl",
                  ref: chartEl,
                  class: "chart",
                  "data-testid": "timeline-uplot"
                },
                null,
                512
                /* NEED_PATCH */
              ),
              createVNode(AnnotationLayer, {
                annotations: __props.data?.annotations,
                options: __props.options?.annotations,
                "x-min": __props.data?.timeRange?.from?.valueOf?.() ?? __props.data?.timeRange?.from,
                "x-max": __props.data?.timeRange?.to?.valueOf?.() ?? __props.data?.timeRange?.to
              }, null, 8, ["annotations", "options", "x-min", "x-max"])
            ]),
            showLegendBar.value ? (openBlock(), createElementBlock("ul", _hoisted_3$1e, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(legendItems.value, (it, i) => {
                  return openBlock(), createElementBlock("li", { key: i }, [
                    createElementVNode(
                      "span",
                      {
                        class: "swatch",
                        style: normalizeStyle({ background: it.color })
                      },
                      null,
                      4
                      /* STYLE */
                    ),
                    createElementVNode(
                      "span",
                      null,
                      toDisplayString(it.label),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])) : createCommentVNode("v-if", true),
            pageModel.value.totalRows > pageModel.value.pageSize ? (openBlock(), createElementBlock("div", _hoisted_4$13, [
              createElementVNode("button", {
                type: "button",
                disabled: pageModel.value.page <= 0,
                "data-testid": "timeline-page-prev",
                onClick: prevPage
              }, " ‹ ", 8, _hoisted_5$X),
              createElementVNode(
                "span",
                null,
                toDisplayString(pageModel.value.page * pageModel.value.pageSize + 1) + "–" + toDisplayString(Math.min(
                  (pageModel.value.page + 1) * pageModel.value.pageSize,
                  pageModel.value.totalRows
                )) + " / " + toDisplayString(pageModel.value.totalRows),
                1
                /* TEXT */
              ),
              createElementVNode("button", {
                type: "button",
                disabled: pageModel.value.page >= pageModel.value.totalPages - 1,
                "data-testid": "timeline-page-next",
                onClick: nextPage
              }, " › ", 8, _hoisted_6$Q)
            ])) : createCommentVNode("v-if", true)
          ], 8, _hoisted_1$1P)) : (openBlock(), createElementBlock(
            Fragment,
            { key: 1 },
            [
              createCommentVNode(" Empty "),
              createElementVNode("div", {
                class: "timeline empty",
                "data-testid": isHistory.value ? "panel-status-history" : "panel-state-timeline",
                "data-mode": isHistory.value ? "history" : "timeline",
                "data-merge-values": String(mergeValues.value)
              }, [..._cache[0] || (_cache[0] = [
                createElementVNode(
                  "div",
                  {
                    class: "empty-msg",
                    "data-testid": "timeline-empty"
                  },
                  "暂无数据",
                  -1
                  /* CACHED */
                )
              ])], 8, _hoisted_7$O)
            ],
            2112
            /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
          ))
        ],
        2112
        /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
      );
    };
  }
});
const StatusTimelineRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2x, [["__scopeId", "data-v-a7e7e403"]]);
const _sfc_main$2w = /* @__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(StatusTimelineRenderer, {
        mode: "timeline",
        data: __props.data,
        options: __props.options,
        "field-config": __props.fieldConfig,
        width: __props.width,
        height: __props.height,
        "time-range": __props.timeRange
      }, null, 8, ["data", "options", "field-config", "width", "height", "time-range"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "state-timeline",
    name: "状态时间线",
    description: "状态随时间变化的时间线",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2w
).useFieldConfig({
  useCustomConfig: (builder) => {
    addHideFrom(builder);
    builder.addNumber(
      {
        id: "custom.lineWidth",
        path: "lineWidth",
        name: "线宽",
        category: ["图形样式"],
        editor: "number",
        settings: { min: 0, max: 10, step: 1 }
      },
      0
    ).addNumber(
      {
        id: "custom.fillOpacity",
        path: "fillOpacity",
        name: "填充透明度",
        category: ["图形样式"],
        editor: "number",
        settings: { min: 0, max: 100, step: 1 }
      },
      70
    ).addBoolean(
      {
        id: "custom.spanNulls",
        path: "spanNulls",
        name: "连接空值",
        category: ["图形样式"],
        editor: "boolean"
      },
      false
    ).addBoolean(
      {
        id: "custom.insertNulls",
        path: "insertNulls",
        name: "断开阈值",
        category: ["图形样式"],
        editor: "boolean"
      },
      false
    ).addRadio(
      {
        id: "custom.axisPlacement",
        path: "custom.axisPlacement",
        name: "轴位置",
        category: ["Axis"],
        editor: "radio",
        settings: {
          options: [
            { label: "自动", value: "auto" },
            { label: "隐藏", value: "hidden" }
          ]
        }
      },
      "auto"
    ).addNumber(
      {
        id: "custom.axisWidth",
        path: "custom.axisWidth",
        name: "轴宽度",
        category: ["Axis"],
        editor: "number"
      },
      void 0
    );
  }
}).setPanelOptions((builder) => {
  addTooltipOptions(builder, true, false);
  addLegendOptions(builder, true, false);
  addAnnotationOptions(builder);
  builder.addBoolean(
    {
      id: "mergeValues",
      path: "mergeValues",
      name: "合并相同值",
      description: "合并连续相同的值",
      category: ["状态时间线"],
      editor: "boolean"
    },
    true
  ).addRadio(
    {
      id: "showValue",
      path: "showValue",
      name: "显示数值",
      category: ["状态时间线"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "始终", value: "always" },
          { label: "从不", value: "never" }
        ]
      }
    },
    "auto"
  ).addRadio(
    {
      id: "alignValue",
      path: "alignValue",
      name: "对齐数值",
      category: ["状态时间线"],
      editor: "radio",
      settings: {
        options: [
          { label: "左", value: "left" },
          { label: "居中", value: "center" },
          { label: "右", value: "right" }
        ]
      }
    },
    "left"
  ).addNumber(
    {
      id: "rowHeight",
      path: "rowHeight",
      name: "行高",
      category: ["状态时间线"],
      editor: "number",
      settings: { min: 0, max: 1, step: 0.01 }
    },
    0.9
  ).addNumber(
    {
      id: "perPage",
      path: "perPage",
      name: "每页行数",
      description: "大于 0 时启用分页",
      category: ["状态时间线"],
      editor: "number",
      settings: { min: 0, integer: true }
    },
    20
  );
}).setDataSupport({ annotations: true }).setRuntimeConsumedPaths([
  "annotations",
  "annotations.clustering",
  "annotations.multiLane",
  "annotations.show",
  "custom.axisWidth",
  "custom.axisPlacement",
  "custom.hideFrom",
  "mergeValues",
  "showValue",
  "alignValue",
  "rowHeight",
  "perPage",
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "tooltip.mode",
  "custom.lineWidth",
  "custom.fillOpacity",
  "custom.spanNulls",
  "custom.insertNulls"
]).register();
function fieldColor(field, value, fallback, theme) {
  const cfg = field.config;
  const byName = cfg?.color?.fixedColor || cfg?.color?.seriesBy;
  if (typeof byName === "string" && theme?.getColorByName) {
    try {
      return theme.getColorByName(byName) || byName;
    } catch {
      return byName;
    }
  }
  if (cfg?.color?.mode === "fixed" && cfg?.color?.fixedColor) {
    return String(cfg.color.fixedColor);
  }
  const steps = cfg?.thresholds?.steps;
  if (steps?.length && typeof value === "number") {
    let color = steps[0]?.color || fallback;
    for (const s of steps) {
      if (value >= s.value) color = s.color;
    }
    return color;
  }
  return fallback;
}
function isTimeField(f) {
  return f.type === "time" || /^time$/i.test(f.name);
}
function isValueField(f) {
  if (isTimeField(f)) return false;
  return f.type === "string" || f.type === "number" || f.type === "boolean";
}
function applyOverrides(field, fieldConfig) {
  if (!fieldConfig) return field;
  const defaults2 = fieldConfig.defaults || {};
  let config2 = { ...field.config || {}, ...defaults2, custom: {
    ...defaults2.custom || {},
    ...field.config?.custom || {}
  } };
  for (const ov of fieldConfig.overrides || []) {
    const matcher = ov.matcher;
    const id = matcher?.id || matcher?.type;
    const opts = matcher?.options;
    let match = false;
    if (id === "byName" && opts === field.name) match = true;
    if (id === "byName" && opts?.name === field.name) match = true;
    if (id === "byRegexp" && opts && new RegExp(String(opts)).test(field.name))
      match = true;
    if (!match) continue;
    for (const p of ov.properties || []) {
      const path = String(p.id || p.path || "");
      const value = p.value;
      if (path === "color" || path.endsWith("color")) {
        config2 = {
          ...config2,
          color: typeof value === "object" && value ? value : { mode: "fixed", fixedColor: value }
        };
      } else if (path.startsWith("custom.")) {
        const key = path.slice("custom.".length);
        config2 = {
          ...config2,
          custom: { ...config2.custom, [key]: value }
        };
      } else {
        config2 = { ...config2, [path]: value };
      }
    }
  }
  return { ...field, config: config2 };
}
function prepareStatusHistoryFrames(series, fieldConfig, options = {}, ctx = {}) {
  const frames = series ?? [];
  if (!frames.length) {
    return { kind: "error", message: "缺少数据帧：需要 time + string/number 字段" };
  }
  const usable = frames.filter((f) => {
    const meta2 = f.meta;
    if (meta2?.preferredVisualisationType === "logs") return false;
    if (String(meta2?.type || "").toLowerCase() === "log-lines") return false;
    return true;
  });
  if (!usable.length) {
    return { kind: "error", message: "输入为日志帧，状态历史不支持 logs 可视化" };
  }
  const width2 = Math.max(1, Number(ctx.width ?? 600));
  const rows = [];
  let globalMaxPoints = 0;
  let tMin = Infinity;
  let tMax = -Infinity;
  for (const frame of usable) {
    const fields = (frame.fields || []).map((f) => applyOverrides(f, fieldConfig));
    const time = fields.find(isTimeField);
    const values = fields.filter(isValueField);
    if (!time) {
      return { kind: "error", message: "缺少 time 字段" };
    }
    if (!values.length) {
      return { kind: "error", message: "缺少 string/number 状态字段" };
    }
    for (const vf of values) {
      const n = Math.max(time.values?.length ?? 0, vf.values?.length ?? 0);
      globalMaxPoints = Math.max(globalMaxPoints, n);
      const cells = [];
      for (let i = 0; i < n; i++) {
        let t2 = Number(time.values?.[i]);
        if (!Number.isFinite(t2)) continue;
        if (t2 > 1e15) t2 = Math.floor(t2 / 1e6);
        else if (t2 > 0 && t2 < 1e11) t2 = Math.floor(t2 * 1e3);
        tMin = Math.min(tMin, t2);
        tMax = Math.max(tMax, t2);
        const raw = vf.values?.[i];
        const value = raw == null ? null : typeof raw === "number" || typeof raw === "string" ? raw : String(raw);
        const color = fieldColor(vf, raw, "green", ctx.themeColors);
        cells.push({
          time: t2,
          value,
          color,
          label: value == null ? "" : String(value)
        });
      }
      rows.push({
        id: `${frame.refId || frame.name || "A"}:${vf.name}`,
        name: vf.config?.displayName || vf.name,
        cells
      });
    }
  }
  if (globalMaxPoints > width2 / 2) {
    return { kind: "too-many-points", count: globalMaxPoints, width: width2 };
  }
  const perPageRaw = Number(options.perPage ?? 20);
  const perPage = Math.max(1, perPageRaw || rows.length || 1);
  const totalRows = rows.length;
  const totalPages = Math.max(1, Math.ceil(totalRows / perPage));
  const page = Math.min(
    Math.max(1, Number(options.page ?? 1)),
    totalPages
  );
  const start = (page - 1) * perPage;
  const pageRows = rows.slice(start, start + perPage);
  const legendMap = /* @__PURE__ */ new Map();
  for (const row of pageRows) {
    for (const c of row.cells) {
      if (c.value == null) continue;
      const key = String(c.value);
      if (!legendMap.has(key)) legendMap.set(key, c.color);
    }
  }
  const legend = [...legendMap.entries()].map(([label, color]) => ({
    label,
    color
  }));
  if (ctx.timeRange) {
    const from = ctx.timeRange.from instanceof Date ? ctx.timeRange.from.getTime() : Number(ctx.timeRange.from);
    const to = ctx.timeRange.to instanceof Date ? ctx.timeRange.to.getTime() : Number(ctx.timeRange.to);
    if (Number.isFinite(from)) tMin = Math.min(tMin, from);
    if (Number.isFinite(to)) tMax = Math.max(tMax, to);
  }
  return {
    kind: "ready",
    rows: pageRows,
    legend,
    pagination: { page, perPage, totalRows, totalPages },
    timeRange: {
      min: Number.isFinite(tMin) ? tMin : 0,
      max: Number.isFinite(tMax) ? tMax : 1
    }
  };
}
const _hoisted_1$1O = ["data-prepared-kind", "data-row-height", "data-col-width", "data-show-value", "data-fill-opacity", "data-line-width", "data-axis-width", "data-axis-placement", "data-hide-from", "data-legend-show", "data-legend-display-mode", "data-legend-placement", "data-tooltip-mode", "data-per-page", "data-fill-opacity-custom", "data-anno-multi-lane", "data-annotations-show", "data-annotations-clustering", "data-cell-count", "data-row-count"];
const _hoisted_2$1o = {
  key: 0,
  class: "panel-state error",
  "data-testid": "status-history-error"
};
const _hoisted_3$1d = {
  key: 1,
  class: "panel-state error",
  "data-testid": "status-history-too-many"
};
const _hoisted_4$12 = {
  class: "canvas-wrap",
  "data-testid": "status-history-canvas-wrap"
};
const _hoisted_5$W = { class: "tip-row" };
const _hoisted_6$P = { class: "muted" };
const _hoisted_7$N = {
  key: 0,
  class: "legend",
  "data-testid": "status-history-legend"
};
const _hoisted_8$F = {
  key: 1,
  class: "pager",
  "data-testid": "status-history-pager"
};
const _hoisted_9$C = ["disabled"];
const _hoisted_10$w = ["disabled"];
const _sfc_main$2v = /* @__PURE__ */ defineComponent({
  __name: "StatusHistoryRenderer",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const page = ref(1);
    const canvasEl = ref(null);
    const hover = ref(null);
    const prepared = computed(() => {
      const opts2 = props.options || {};
      return prepareStatusHistoryFrames(
        props.data?.series,
        props.fieldConfig,
        {
          showValue: opts2.showValue,
          rowHeight: Number(opts2.rowHeight ?? 0.9),
          colWidth: Number(opts2.colWidth ?? 0.9),
          perPage: Number(opts2.perPage ?? 20),
          lineWidth: Number(opts2.lineWidth ?? 1),
          fillOpacity: Number(opts2.fillOpacity ?? 70),
          page: page.value
        },
        {
          width: props.width ?? 600,
          timeRange: props.timeRange ? {
            from: props.timeRange.from,
            to: props.timeRange.to
          } : void 0
        }
      );
    });
    const opts = computed(() => props.options || {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    const fillOpacityPct = computed(() => {
      if (opts.value.fillOpacity != null) return Number(opts.value.fillOpacity);
      if (custom.value.fillOpacity != null) return Number(custom.value.fillOpacity);
      return 70;
    });
    const lineWidthAttr = computed(() => {
      if (custom.value.lineWidth != null) return Number(custom.value.lineWidth);
      if (opts.value.lineWidth != null) return Number(opts.value.lineWidth);
      return 1;
    });
    const colWidthAttr = computed(
      () => Math.max(0.05, Math.min(1, Number(opts.value.colWidth ?? 0.9)))
    );
    const rowHeightAttr = computed(
      () => Math.max(0.05, Math.min(1, Number(opts.value.rowHeight ?? 0.9)))
    );
    const cellCountAttr = computed(() => {
      const p = prepared.value;
      if (p.kind !== "ready") return 0;
      return p.rows[0]?.cells?.length ?? 0;
    });
    const hideFromAttr = computed(() => {
      const h2 = custom.value.hideFrom ?? opts.value.hideFrom;
      if (!h2 || typeof h2 !== "object") return "";
      const parts = [];
      if (h2.viz) parts.push("viz");
      if (h2.legend) parts.push("legend");
      if (h2.tooltip) parts.push("tooltip");
      return parts.join(",");
    });
    function shouldShowValue(cellCount) {
      const v = String(opts.value.showValue ?? "auto");
      if (v === "never" || v === "false") return false;
      if (v === "always" || v === "true") return true;
      return cellCount <= 48;
    }
    function cssColor(c, opacityPct) {
      const a = Math.max(0, Math.min(1, opacityPct / 100));
      if (c.startsWith("var(")) return c;
      const h2 = c.replace("#", "");
      if (h2.length >= 6 && /^[0-9a-fA-F]+$/.test(h2.slice(0, 6))) {
        const r = parseInt(h2.slice(0, 2), 16);
        const g = parseInt(h2.slice(2, 4), 16);
        const b = parseInt(h2.slice(4, 6), 16);
        return `rgba(${r},${g},${b},${a})`;
      }
      return c;
    }
    function paint() {
      const canvas = canvasEl.value;
      const prep = prepared.value;
      if (!canvas || prep.kind !== "ready") return;
      const dpr = Math.min(2, window.devicePixelRatio || 1);
      const cssW = Math.max(1, props.width ?? canvas.clientWidth ?? 600);
      const cssH = Math.max(1, (props.height ?? canvas.clientHeight ?? 300) - 28);
      canvas.width = Math.floor(cssW * dpr);
      canvas.height = Math.floor(cssH * dpr);
      canvas.style.width = cssW + "px";
      canvas.style.height = cssH + "px";
      const ctx = canvas.getContext("2d");
      if (!ctx) return;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      ctx.clearRect(0, 0, cssW, cssH);
      const rows = prep.rows;
      if (!rows.length) return;
      const labelW = 100;
      const plotW = Math.max(1, cssW - labelW - 8);
      const plotH = Math.max(1, cssH - 8);
      const rowH = plotH / rows.length;
      const rh = rowHeightAttr.value;
      const cw = colWidthAttr.value;
      const fillOpacity = fillOpacityPct.value;
      const lineWidth = lineWidthAttr.value;
      const textColor = getComputedStyle(canvas).getPropertyValue("--grafana-text").trim() || "currentColor";
      const tMin = prep.timeRange.min;
      const tMax = prep.timeRange.max;
      const tSpan = Math.max(1, tMax - tMin);
      rows.forEach((row, ri) => {
        const y0 = ri * rowH + rowH * (1 - rh) / 2;
        const h2 = Math.max(2, rowH * rh);
        ctx.fillStyle = textColor;
        ctx.font = "11px Inter, Helvetica, Arial, sans-serif";
        ctx.textAlign = "right";
        ctx.textBaseline = "middle";
        const label = row.name.length > 14 ? row.name.slice(0, 12) + "…" : row.name;
        ctx.fillText(label, labelW - 6, y0 + h2 / 2);
        const cells = row.cells;
        const n = cells.length;
        if (!n) return;
        const showVal = shouldShowValue(n);
        for (let i = 0; i < n; i++) {
          const cell = cells[i];
          const xCenter = labelW + (cell.time - tMin) / tSpan * plotW;
          let half = plotW / Math.max(n, 1) / 2;
          if (i < n - 1) {
            const nextX = labelW + (cells[i + 1].time - tMin) / tSpan * plotW;
            half = Math.max(1, (nextX - xCenter) / 2);
          } else if (i > 0) {
            const prevX = labelW + (cells[i - 1].time - tMin) / tSpan * plotW;
            half = Math.max(1, (xCenter - prevX) / 2);
          }
          const w = Math.max(2, half * 2 * cw);
          const x = xCenter - w / 2;
          ctx.fillStyle = cssColor(cell.color, fillOpacity);
          ctx.fillRect(x, y0, w, h2);
          if (lineWidth > 0) {
            ctx.strokeStyle = cell.color;
            ctx.lineWidth = lineWidth;
            ctx.strokeRect(x + 0.5, y0 + 0.5, w - 1, h2 - 1);
          }
          if (showVal && w > 18 && h2 > 12) {
            ctx.fillStyle = textColor;
            ctx.font = "10px Inter, Helvetica, Arial, sans-serif";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            const txt = String(cell.label ?? cell.value ?? "");
            if (txt) ctx.fillText(txt.slice(0, 8), x + w / 2, y0 + h2 / 2);
          }
        }
      });
    }
    function onMove(ev) {
      const canvas = canvasEl.value;
      const prep = prepared.value;
      if (!canvas || prep.kind !== "ready") {
        hover.value = null;
        return;
      }
      const rect = canvas.getBoundingClientRect();
      const x = ev.clientX - rect.left;
      const y = ev.clientY - rect.top;
      const cssW = rect.width;
      const cssH = rect.height;
      const labelW = 100;
      const plotW = Math.max(1, cssW - labelW - 8);
      const rows = prep.rows;
      if (!rows.length) return;
      const rowH = cssH / rows.length;
      const ri = Math.floor(y / rowH);
      if (ri < 0 || ri >= rows.length) {
        hover.value = null;
        return;
      }
      const row = rows[ri];
      const tMin = prep.timeRange.min;
      const tMax = prep.timeRange.max;
      const tSpan = Math.max(1, tMax - tMin);
      let best = null;
      let bestDist = Infinity;
      for (const cell of row.cells) {
        const cx = labelW + (cell.time - tMin) / tSpan * plotW;
        const d = Math.abs(cx - x);
        if (d < bestDist) {
          bestDist = d;
          best = {
            x: ev.clientX,
            y: ev.clientY,
            label: row.name,
            value: String(cell.label ?? cell.value ?? ""),
            color: cell.color,
            time: cell.time
          };
        }
      }
      hover.value = bestDist < 24 ? best : null;
    }
    function nextPage() {
      const p = prepared.value;
      if (p.kind !== "ready") return;
      if (page.value < p.pagination.totalPages) page.value += 1;
    }
    function prevPage() {
      if (page.value > 1) page.value -= 1;
    }
    watch(
      () => [prepared.value, props.width, props.height, opts.value],
      () => nextTick(paint),
      { deep: true }
    );
    watch(
      () => props.options?.perPage,
      () => {
        page.value = 1;
      }
    );
    onMounted(() => {
      paint();
      window.addEventListener("resize", paint);
    });
    onBeforeUnmount(() => window.removeEventListener("resize", paint));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "status-history-host",
        "data-testid": "panel-status-history",
        "data-status-history-host": "1",
        "data-renderer": "samples",
        "data-mode": "history",
        "data-prepared-kind": prepared.value.kind,
        "data-row-height": String(rowHeightAttr.value),
        "data-col-width": String(colWidthAttr.value),
        "data-show-value": String(opts.value.showValue ?? "auto"),
        "data-fill-opacity": String(fillOpacityPct.value),
        "data-line-width": String(lineWidthAttr.value),
        "data-axis-width": custom.value.axisWidth == null ? "" : String(custom.value.axisWidth),
        "data-axis-placement": String(custom.value.axisPlacement ?? "auto"),
        "data-hide-from": hideFromAttr.value,
        "data-legend-show": String(opts.value.legend?.showLegend !== false),
        "data-legend-display-mode": String(opts.value.legend?.displayMode ?? "list"),
        "data-legend-placement": String(opts.value.legend?.placement ?? "bottom"),
        "data-tooltip-mode": String(opts.value.tooltip?.mode ?? "single"),
        "data-per-page": String(opts.value.perPage ?? 20),
        "data-fill-opacity-custom": String(fillOpacityPct.value),
        "data-anno-multi-lane": String(!!opts.value.annotations?.multiLane),
        "data-annotations-show": String(opts.value.annotations?.show !== false),
        "data-annotations-clustering": String(!!opts.value.annotations?.clustering),
        "data-cell-count": String(cellCountAttr.value),
        "data-row-count": String(prepared.value.kind === "ready" ? prepared.value.rows.length : 0)
      }, [
        prepared.value.kind === "error" ? (openBlock(), createElementBlock(
          "div",
          _hoisted_2$1o,
          toDisplayString(prepared.value.message),
          1
          /* TEXT */
        )) : prepared.value.kind === "too-many-points" ? (openBlock(), createElementBlock(
          "div",
          _hoisted_3$1d,
          " 点过多（" + toDisplayString(prepared.value.count) + "），请收窄查询时间范围或减少序列（宽度 " + toDisplayString(prepared.value.width) + " 仅可清晰展示约 " + toDisplayString(Math.floor(prepared.value.width / 2)) + " 点） ",
          1
          /* TEXT */
        )) : (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createElementVNode("div", _hoisted_4$12, [
              createElementVNode(
                "canvas",
                {
                  ref_key: "canvasEl",
                  ref: canvasEl,
                  class: "sh-canvas",
                  "data-testid": "status-history-canvas",
                  onMousemove: onMove,
                  onMouseleave: _cache[0] || (_cache[0] = ($event) => hover.value = null)
                },
                null,
                544
                /* NEED_HYDRATION, NEED_PATCH */
              ),
              createVNode(AnnotationLayer, {
                annotations: __props.data?.annotations,
                options: __props.options?.annotations,
                "x-min": __props.data?.timeRange?.from?.valueOf?.() ?? __props.data?.timeRange?.from,
                "x-max": __props.data?.timeRange?.to?.valueOf?.() ?? __props.data?.timeRange?.to
              }, null, 8, ["annotations", "options", "x-min", "x-max"]),
              hover.value ? (openBlock(), createElementBlock(
                "div",
                {
                  key: 0,
                  class: "tooltip",
                  "data-testid": "status-history-tooltip",
                  style: normalizeStyle({ left: hover.value.x + 12 + "px", top: hover.value.y + 12 + "px" })
                },
                [
                  createElementVNode("div", _hoisted_5$W, [
                    createElementVNode(
                      "span",
                      {
                        class: "swatch",
                        style: normalizeStyle({ background: hover.value.color })
                      },
                      null,
                      4
                      /* STYLE */
                    ),
                    createElementVNode(
                      "strong",
                      null,
                      toDisplayString(hover.value.label),
                      1
                      /* TEXT */
                    )
                  ]),
                  createElementVNode(
                    "div",
                    null,
                    toDisplayString(hover.value.value),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "div",
                    _hoisted_6$P,
                    toDisplayString(new Date(hover.value.time).toISOString()),
                    1
                    /* TEXT */
                  )
                ],
                4
                /* STYLE */
              )) : createCommentVNode("v-if", true)
            ]),
            prepared.value.kind === "ready" && prepared.value.legend.length ? (openBlock(), createElementBlock("div", _hoisted_7$N, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(prepared.value.legend, (item) => {
                  return openBlock(), createElementBlock("span", {
                    key: item.label,
                    class: "legend-item"
                  }, [
                    createElementVNode(
                      "i",
                      {
                        class: "swatch",
                        style: normalizeStyle({ background: item.color })
                      },
                      null,
                      4
                      /* STYLE */
                    ),
                    createTextVNode(
                      " " + toDisplayString(item.label),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])) : createCommentVNode("v-if", true),
            prepared.value.kind === "ready" && prepared.value.pagination.totalPages > 1 ? (openBlock(), createElementBlock("div", _hoisted_8$F, [
              createElementVNode("button", {
                type: "button",
                disabled: page.value <= 1,
                onClick: prevPage
              }, " 上一页 ", 8, _hoisted_9$C),
              createElementVNode(
                "span",
                null,
                toDisplayString(prepared.value.pagination.page) + " / " + toDisplayString(prepared.value.pagination.totalPages),
                1
                /* TEXT */
              ),
              createElementVNode("button", {
                type: "button",
                disabled: page.value >= prepared.value.pagination.totalPages,
                onClick: nextPage
              }, " 下一页 ", 8, _hoisted_10$w)
            ])) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 8, _hoisted_1$1O);
    };
  }
});
const StatusHistoryRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2v, [["__scopeId", "data-v-8e244280"]]);
const _sfc_main$2u = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        StatusHistoryRenderer,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
new VuePanelPlugin(
  {
    id: "status-history",
    name: "状态历史",
    description: "状态历史网格",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2u
).useFieldConfig({
  useCustomConfig: (builder) => {
    addHideFrom(builder);
    builder.addNumber(
      {
        id: "custom.lineWidth",
        path: "lineWidth",
        name: "线宽",
        category: ["图形样式"],
        editor: "number",
        settings: { min: 0, max: 10, step: 1 }
      },
      1
    ).addNumber(
      {
        id: "custom.fillOpacity",
        path: "fillOpacity",
        name: "填充透明度",
        category: ["图形样式"],
        editor: "number",
        settings: { min: 0, max: 100, step: 1 }
      },
      70
    ).addRadio(
      {
        id: "custom.axisPlacement",
        path: "custom.axisPlacement",
        name: "轴位置",
        category: ["Axis"],
        editor: "radio",
        settings: {
          options: [
            { label: "自动", value: "auto" },
            { label: "隐藏", value: "hidden" }
          ]
        }
      },
      "auto"
    ).addNumber(
      {
        id: "custom.axisWidth",
        path: "custom.axisWidth",
        name: "轴宽度",
        category: ["Axis"],
        editor: "number"
      },
      void 0
    );
  }
}).setPanelOptions((builder) => {
  addTooltipOptions(builder, true, false);
  addLegendOptions(builder, true, false);
  addAnnotationOptions(builder);
  builder.addRadio(
    {
      id: "showValue",
      path: "showValue",
      name: "显示数值",
      category: ["状态历史"],
      editor: "radio",
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "始终", value: "always" },
          { label: "从不", value: "never" }
        ]
      }
    },
    "auto"
  ).addNumber(
    {
      id: "rowHeight",
      path: "rowHeight",
      name: "行高",
      category: ["状态历史"],
      editor: "number",
      settings: { min: 0, max: 1, step: 0.01 }
    },
    0.9
  ).addNumber(
    {
      id: "colWidth",
      path: "colWidth",
      name: "列宽",
      category: ["状态历史"],
      editor: "number",
      settings: { min: 0, max: 1, step: 0.01 }
    },
    0.9
  ).addNumber(
    {
      id: "perPage",
      path: "perPage",
      name: "每页行数",
      category: ["状态历史"],
      editor: "number",
      settings: { min: 0, integer: true }
    },
    20
  );
}).setDataSupport({ annotations: true }).setRuntimeConsumedPaths([
  "custom.hideFrom",
  "custom.axisPlacement",
  "custom.axisWidth",
  "annotations.show",
  "annotations.multiLane",
  "annotations.clustering",
  "annotations",
  "showValue",
  "rowHeight",
  "colWidth",
  "perPage",
  "legend.showLegend",
  "legend.displayMode",
  "tooltip.mode",
  "custom.lineWidth",
  "custom.fillOpacity"
]).register();
const SCHEME_STOPS = {
  Oranges: [
    "#fff5eb",
    "#fee6ce",
    "#fdd0a2",
    "#fdae6b",
    "#fd8d3c",
    "#f16913",
    "#d94801",
    "#a63603",
    "#7f2704"
  ],
  Blues: [
    "#f7fbff",
    "#deebf7",
    "#c6dbef",
    "#9ecae1",
    "#6baed6",
    "#4292c6",
    "#2171b5",
    "#08519c",
    "#08306b"
  ],
  Reds: [
    "#fff5f0",
    "#fee0d2",
    "#fcbba1",
    "#fc9272",
    "#fb6a4a",
    "#ef3b2c",
    "#cb181d",
    "#a50f15",
    "#67000d"
  ],
  Greens: [
    "#f7fcf5",
    "#e5f5e0",
    "#c7e9c0",
    "#a1d99b",
    "#74c476",
    "#41ab5d",
    "#238b45",
    "#006d2c",
    "#00441b"
  ],
  Greys: [
    "#ffffff",
    "#f0f0f0",
    "#d9d9d9",
    "#bdbdbd",
    "#969696",
    "#737373",
    "#525252",
    "#252525",
    "#000000"
  ],
  Purples: [
    "#fcfbfd",
    "#efedf5",
    "#dadaeb",
    "#bcbddc",
    "#9e9ac8",
    "#807dba",
    "#6a51a3",
    "#54278f",
    "#3f007d"
  ],
  Spectral: [
    "#9e0142",
    "#d53e4f",
    "#f46d43",
    "#fdae61",
    "#fee08b",
    "#e6f598",
    "#abdda4",
    "#66c2a5",
    "#3288bd",
    "#5e4fa2"
  ],
  Magma: [
    "#000004",
    "#1b0c41",
    "#4f0a6d",
    "#781c6d",
    "#a52c60",
    "#cf4446",
    "#ed6925",
    "#fb9b06",
    "#f7d13d",
    "#fcffa4"
  ],
  Inferno: [
    "#000004",
    "#1b0c41",
    "#4a0c6b",
    "#781c6d",
    "#a52c60",
    "#cf4446",
    "#ed6925",
    "#fb9a06",
    "#f7d13d",
    "#fcffa4"
  ],
  Plasma: [
    "#0d0887",
    "#46039f",
    "#7201a8",
    "#9c179e",
    "#bd3786",
    "#d8576b",
    "#ed7953",
    "#fb9f3a",
    "#fdca26",
    "#f0f921"
  ],
  Viridis: [
    "#440154",
    "#482777",
    "#3e4989",
    "#31688e",
    "#26828e",
    "#1f9e89",
    "#35b779",
    "#6ece58",
    "#b5de2b",
    "#fde725"
  ],
  Turbo: [
    "#30123b",
    "#4662d7",
    "#36aaf9",
    "#1ae4b6",
    "#72fe5e",
    "#c8ef34",
    "#faba39",
    "#f66b19",
    "#ca2a04",
    "#7a0403"
  ],
  RdYlBu: [
    "#a50026",
    "#d73027",
    "#f46d43",
    "#fdae61",
    "#fee090",
    "#e0f3f8",
    "#abd9e9",
    "#74add1",
    "#4575b4",
    "#313695"
  ],
  RdYlGn: [
    "#a50026",
    "#d73027",
    "#f46d43",
    "#fdae61",
    "#fee08b",
    "#d9ef8b",
    "#a6d96a",
    "#66bd63",
    "#1a9850",
    "#006837"
  ],
  YlOrRd: [
    "#ffffcc",
    "#ffeda0",
    "#fed976",
    "#feb24c",
    "#fd8d3c",
    "#fc4e2a",
    "#e31a1c",
    "#bd0026",
    "#800026"
  ],
  YlGnBu: [
    "#ffffd9",
    "#edf8b1",
    "#c7e9b4",
    "#7fcdbb",
    "#41b6c4",
    "#1d91c0",
    "#225ea8",
    "#253494",
    "#081d58"
  ],
  Cool: ["#6e40aa", "#7e6eee", "#6bb3f0", "#5ad8c6", "#a0ec64", "#e8fa5b"],
  Warm: ["#6e40aa", "#c83dac", "#ff5375", "#ff8c38", "#c6c31e", "#aff05b"],
  Rainbow: [
    "#6e40aa",
    "#417de0",
    "#23b0bf",
    "#41bd5f",
    "#b6c931",
    "#ef7e23",
    "#e24d56"
  ]
};
function parseHex(hex) {
  const h2 = hex.replace("#", "");
  const full = h2.length === 3 ? h2.split("").map((c) => c + c).join("") : h2.slice(0, 6);
  return [
    parseInt(full.slice(0, 2), 16),
    parseInt(full.slice(2, 4), 16),
    parseInt(full.slice(4, 6), 16)
  ];
}
function lerpColor(a, b, t2) {
  const [ar, ag, ab] = parseHex(a);
  const [br, bg, bb] = parseHex(b);
  const r = Math.round(ar + (br - ar) * t2);
  const g = Math.round(ag + (bg - ag) * t2);
  const bl = Math.round(ab + (bb - ab) * t2);
  return `rgb(${r}, ${g}, ${bl})`;
}
function sampleStops(stops, steps) {
  if (steps <= 1) return [stops[stops.length - 1]];
  const out = [];
  for (let i = 0; i < steps; i++) {
    const t2 = i / (steps - 1);
    const x = t2 * (stops.length - 1);
    const i0 = Math.floor(x);
    const i1 = Math.min(stops.length - 1, i0 + 1);
    const f = x - i0;
    out.push(lerpColor(stops[i0], stops[i1], f));
  }
  return out;
}
function parseCssColor(input) {
  if (input.startsWith("#")) {
    const [r, g, b] = parseHex(input);
    return { r, g, b };
  }
  const m = input.match(/rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);
  if (m) return { r: +m[1], g: +m[2], b: +m[3] };
  return { r: 255, g: 140, b: 0 };
}
function quantizeHeatmapPalette(opts = {}) {
  const steps = Math.max(2, Math.min(128, Number(opts.steps ?? 64)));
  const mode2 = String(opts.mode ?? "scheme");
  if (mode2 === "opacity") {
    const fill = parseCssColor(String(opts.fill || "#ff9830"));
    const exp = String(opts.scale) === "exponential" ? Number(opts.exponent ?? 0.5) : 1;
    const out = [];
    for (let i = 0; i < steps; i++) {
      const t2 = i / (steps - 1);
      const a = Math.pow(t2, exp);
      out.push(`rgba(${fill.r},${fill.g},${fill.b},${a.toFixed(4)})`);
    }
    if (opts.reverse) out.reverse();
    return out;
  }
  const name = String(opts.scheme || "Oranges");
  const stops = SCHEME_STOPS[name] ?? SCHEME_STOPS.Oranges;
  let palette2 = sampleStops(stops, steps);
  const darkInvert = /* @__PURE__ */ new Set([
    "Blues",
    "Greens",
    "Greys",
    "Oranges",
    "Purples",
    "Reds",
    "BuGn",
    "BuPu",
    "GnBu",
    "OrRd",
    "PuBu",
    "PuRd",
    "RdPu",
    "YlGn",
    "YlGnBu",
    "YlOrBr",
    "YlOrRd"
  ]);
  const alwaysInvert = /* @__PURE__ */ new Set([
    "Spectral",
    "RdYlBu",
    "RdYlGn",
    "RdBu",
    "PiYG",
    "PRGn",
    "BrBG",
    "PuOr",
    "RdGy",
    "Rainbow",
    "Sinebow"
  ]);
  const isDark = opts.themeMode === "light" || opts.themeMode === "dark" ? opts.themeMode === "dark" : resolveThemeModeHint() === "dark";
  if (alwaysInvert.has(name) || isDark && darkInvert.has(name)) {
    palette2 = palette2.slice().reverse();
  }
  if (opts.reverse) palette2 = palette2.slice().reverse();
  return palette2;
}
function colorForHeatValue(value, min, max, palette2, colorOpts) {
  const cMin = colorOpts?.min != null ? Number(colorOpts.min) : min;
  const cMax = colorOpts?.max != null ? Number(colorOpts.max) : max;
  const span = cMax - cMin || 1;
  let t2 = (value - cMin) / span;
  if (!Number.isFinite(t2)) t2 = 0;
  t2 = Math.max(0, Math.min(1, t2));
  if (String(colorOpts?.scale) === "exponential" && colorOpts?.mode !== "opacity") {
    const exp = Number(colorOpts?.exponent ?? 0.5);
    t2 = Math.pow(t2, exp);
  }
  const idx = Math.min(
    palette2.length - 1,
    Math.max(0, Math.floor(t2 * (palette2.length - 1)))
  );
  return palette2[idx];
}
const _hoisted_1$1N = ["data-cell-gap", "data-cell-radius", "data-calculate", "data-calc-x-mode", "data-calc-y-mode", "data-calc-y-scale", "data-calc-x-value", "data-calc-y-value", "data-selection-mode", "data-selection-drag-x", "data-selection-drag-y", "data-color-scheme", "data-color-mode", "data-color-scale", "data-color-exponent", "data-color-steps", "data-color-reverse", "data-color-min", "data-color-max", "data-color-fill", "data-show-value", "data-cell-unit", "data-cell-decimals", "data-yaxis-placement", "data-yaxis-label", "data-yaxis-unit", "data-yaxis-decimals", "data-yaxis-min", "data-yaxis-max", "data-yaxis-width", "data-yaxis-reverse", "data-tooltip-mode", "data-tooltip-max-width", "data-tooltip-max-height", "data-tooltip-y-histogram", "data-tooltip-color-scale", "data-hide-from", "data-annotations-show", "data-annotations-clustering", "data-annotations-multi-lane", "data-rows-layout", "data-y-layout", "data-y-layout-align", "data-yscale-min", "data-yscale-max", "data-rows-value", "data-rows-ybucket-scale", "data-scale-distribution", "data-exemplars-color", "data-filter-le", "data-filter-ge", "data-point-count", "data-legend-show"];
const _hoisted_2$1n = {
  key: 1,
  class: "heatmap-legend",
  "data-testid": "heatmap-legend"
};
const _hoisted_3$1c = { class: "heatmap-legend__range" };
const _hoisted_4$11 = {
  class: "heatmap-chart-host",
  style: { "position": "relative", "flex": "1", "min-height": "0" }
};
const _hoisted_5$V = { class: "heatmap-tooltip__row" };
const _hoisted_6$O = {
  key: 0,
  class: "heatmap-tooltip__scale",
  "data-testid": "heatmap-color-scale"
};
const _hoisted_7$M = {
  key: 1,
  class: "heatmap-tooltip__hist",
  "data-testid": "heatmap-y-histogram"
};
const _hoisted_8$E = ["data-color"];
const _sfc_main$2t = /* @__PURE__ */ defineComponent({
  __name: "HeatmapRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const themeEpoch = ref(0);
    let offTheme;
    onMounted(() => {
      offTheme = onThemeChange(() => {
        themeEpoch.value++;
      });
    });
    onBeforeUnmount(() => offTheme?.());
    const chartEl = ref(null);
    const hover = ref(null);
    const colorOpts = computed(() => {
      void themeEpoch.value;
      const c = opts.value.color ?? {};
      return {
        mode: c.mode ?? "scheme",
        scheme: c.scheme ?? "Oranges",
        fill: c.fill ?? classicOrange(),
        scale: c.scale ?? "linear",
        exponent: c.exponent ?? 0.5,
        steps: c.steps ?? 64,
        reverse: !!c.reverse,
        min: c.min,
        max: c.max,
        themeMode: resolveThemeModeHint()
      };
    });
    const palette2 = computed(() => quantizeHeatmapPalette(colorOpts.value));
    const hideLE = computed(() => {
      if (opts.value.filterValues?.le != null && opts.value.filterValues.le !== "") {
        return Number(opts.value.filterValues.le);
      }
      if (opts.value && Object.keys(opts.value).length === 0) return -Infinity;
      return 1e-9;
    });
    const hideGE = computed(
      () => opts.value.filterValues?.ge != null && opts.value.filterValues.ge !== "" ? Number(opts.value.filterValues.ge) : Infinity
    );
    const rawHeatSamples = computed(() => {
      const out = [];
      for (const frame of props.data?.series ?? []) {
        (frame.fields ?? []).map((f) => String(f.name));
        const xMinF = frame.fields?.find(
          (f) => /^(xMin|xBucketMin)$/i.test(f.name)
        );
        const yMinF = frame.fields?.find(
          (f) => /^(yMin|yBucketMin)$/i.test(f.name)
        );
        const countF = frame.fields?.find(
          (f) => /^(count|value)$/i.test(f.name)
        );
        if (xMinF && yMinF && countF) {
          const n = Math.min(
            xMinF.values?.length ?? 0,
            yMinF.values?.length ?? 0,
            countF.values?.length ?? 0
          );
          for (let i = 0; i < n; i++) {
            const v = Number(countF.values[i]);
            if (!Number.isFinite(v)) continue;
            if (!(v > hideLE.value && v < hideGE.value)) continue;
            out.push({
              t: Number(xMinF.values[i]),
              y: Number(yMinF.values[i]),
              v
            });
          }
          continue;
        }
        const time = frame.fields?.find((f) => f.type === "time");
        const nums = (frame.fields ?? []).filter((f) => f.type === "number");
        if (!time || !nums.length) continue;
        for (const num2 of nums) {
          const len = Math.min(time.values?.length ?? 0, num2.values?.length ?? 0);
          for (let i = 0; i < len; i++) {
            const v = Number(num2.values[i]);
            if (!Number.isFinite(v)) continue;
            if (!(v > hideLE.value && v < hideGE.value)) continue;
            out.push({ t: Number(time.values[i]), y: v, v });
          }
        }
      }
      return out;
    });
    const wantsCalculate = computed(() => {
      if (opts.value.calculate === false || opts.value.calculate === "false")
        return false;
      if (opts.value.calculate === true || opts.value.calculate === "true")
        return true;
      return Object.keys(opts.value).length === 0;
    });
    function bucketModeValue(bucket, fallbackCount) {
      const mode2 = String(bucket?.mode ?? "size").toLowerCase();
      const raw = bucket?.value;
      const n = raw == null || raw === "" ? NaN : Number(raw);
      if (mode2 === "count") {
        return {
          mode: "count",
          value: Number.isFinite(n) && n > 0 ? n : fallbackCount
        };
      }
      return {
        mode: "size",
        value: Number.isFinite(n) && n > 0 ? n : NaN
      };
    }
    const heatPoints = computed(() => {
      const raw = rawHeatSamples.value;
      if (!raw.length) return [];
      if (!wantsCalculate.value) return raw;
      const xs = raw.map((p) => p.t);
      const ys = raw.map((p) => p.y);
      let xMin = Math.min(...xs);
      let xMax = Math.max(...xs);
      let yMin = Math.min(...ys);
      let yMax = Math.max(...ys);
      const yAxis = opts.value.yAxis ?? {};
      if (yAxis.min != null && yAxis.min !== "") yMin = Number(yAxis.min);
      if (yAxis.max != null && yAxis.max !== "") yMax = Number(yAxis.max);
      const tr = timeRangeMs.value;
      if (tr.min != null && Number.isFinite(tr.min)) xMin = Math.min(xMin, tr.min);
      if (tr.max != null && Number.isFinite(tr.max)) xMax = Math.max(xMax, tr.max);
      if (!(xMax > xMin)) xMax = xMin + 1;
      if (!(yMax > yMin)) yMax = yMin + 1;
      const xCfg = bucketModeValue(opts.value.calculation?.xBuckets, 30);
      const yCfg = bucketModeValue(opts.value.calculation?.yBuckets, 20);
      const yScaleType = String(
        (typeof opts.value.calculation?.yBuckets?.scale === "object" ? opts.value.calculation?.yBuckets?.scale?.type : opts.value.calculation?.yBuckets?.scale) ?? opts.value.scaleDistribution?.type ?? opts.value.rowsFrame?.yBucketScale ?? "linear"
      ).toLowerCase();
      let xCount;
      let xSize;
      if (xCfg.mode === "count") {
        xCount = Math.max(1, Math.floor(xCfg.value));
        xSize = (xMax - xMin) / xCount;
      } else {
        xSize = Number.isFinite(xCfg.value) ? xCfg.value : Math.max((xMax - xMin) / 30, 1);
        xCount = Math.max(1, Math.ceil((xMax - xMin) / xSize));
      }
      let yCount;
      let ySize;
      if (yCfg.mode === "count") {
        yCount = Math.max(1, Math.floor(yCfg.value));
        ySize = (yMax - yMin) / yCount;
      } else {
        ySize = Number.isFinite(yCfg.value) ? yCfg.value : Math.max((yMax - yMin) / 20, 1e-9);
        yCount = Math.max(1, Math.ceil((yMax - yMin) / Math.max(ySize, 1e-12)));
      }
      xCount = Math.min(xCount, 200);
      yCount = Math.min(yCount, 100);
      const counts = /* @__PURE__ */ new Map();
      const logY = yScaleType === "log" || yScaleType === "symlog";
      const yLogMin = yMin > 0 ? yMin : Math.min(...ys.filter((y) => y > 0), 1);
      for (const p of raw) {
        let xi = Math.floor((p.t - xMin) / Math.max(xSize, 1e-12));
        if (xi < 0) xi = 0;
        if (xi >= xCount) xi = xCount - 1;
        let yi;
        if (logY && p.y > 0 && yLogMin > 0) {
          const logMin = Math.log(yLogMin);
          const logMax = Math.log(Math.max(yMax, yLogMin * 1.0001));
          const span = logMax - logMin || 1;
          yi = Math.floor((Math.log(p.y) - logMin) / span * yCount);
        } else {
          yi = Math.floor((p.y - yMin) / Math.max(ySize, 1e-12));
        }
        if (yi < 0) yi = 0;
        if (yi >= yCount) yi = yCount - 1;
        const key = `${xi}:${yi}`;
        const cellT = xMin + xi * xSize;
        let cellY;
        if (logY && yLogMin > 0) {
          const logMin = Math.log(yLogMin);
          const logMax = Math.log(Math.max(yMax, yLogMin * 1.0001));
          const span = logMax - logMin || 1;
          cellY = Math.exp(logMin + yi / yCount * span);
        } else {
          cellY = yMin + yi * ySize;
        }
        const prev = counts.get(key);
        if (prev) prev.v += 1;
        else counts.set(key, { t: cellT, y: cellY, v: 1 });
      }
      return [...counts.values()];
    });
    const calcBucketSizes = computed(() => {
      if (!wantsCalculate.value || !heatPoints.value.length) return null;
      const xs = heatPoints.value.map((p) => p.t).sort((a, b) => a - b);
      const ys = heatPoints.value.map((p) => p.y).sort((a, b) => a - b);
      let xSize = 0;
      for (let i = 1; i < xs.length; i++) {
        const d = xs[i] - xs[i - 1];
        if (d > 0) {
          xSize = xSize ? Math.min(xSize, d) : d;
        }
      }
      let ySize = 0;
      for (let i = 1; i < ys.length; i++) {
        const d = ys[i] - ys[i - 1];
        if (d > 0) {
          ySize = ySize ? Math.min(ySize, d) : d;
        }
      }
      return {
        xSize: xSize || void 0,
        ySize: ySize || void 0
      };
    });
    function niceYBucket(minY, maxY) {
      const span = Math.max(maxY - minY, 0);
      if (span === 0) return 1;
      const approx = span / Math.max(10 - 1, 1);
      const incrs = [
        0.01,
        0.02,
        0.025,
        0.05,
        0.1,
        0.2,
        0.25,
        0.5,
        1,
        2,
        2.5,
        5,
        10,
        20,
        25,
        50,
        100
      ];
      let idx = incrs.findIndex((b) => b > approx) - 1;
      if (idx < 0) idx = 0;
      return incrs[idx];
    }
    function normalizeHeatmapLayout(raw) {
      const v = String(raw ?? "auto").toLowerCase();
      if (v === "le" || v === "top") return "le";
      if (v === "ge" || v === "bottom") return "ge";
      if (v === "unknown" || v === "middle" || v === "center") return "unknown";
      return "auto";
    }
    const yLayout = computed(() => {
      const layout = normalizeHeatmapLayout(opts.value.rowsFrame?.layout);
      if (layout === "auto") return "ge";
      return layout;
    });
    const yLayoutAlign = computed(() => {
      let align = yLayout.value === "le" ? -1 : yLayout.value === "ge" ? 1 : 0;
      if (opts.value.yAxis?.reverse) {
        align = align === -1 ? 1 : align === 1 ? -1 : 0;
      }
      return align;
    });
    const yScaleRange = computed(() => {
      const ys = heatPoints.value.map((p) => p.y);
      if (!ys.length) return null;
      let dataMin = Math.min(...ys);
      let dataMax = Math.max(...ys);
      const yAxis = opts.value.yAxis ?? {};
      if (yAxis.min != null && yAxis.min !== "") dataMin = Number(yAxis.min);
      if (yAxis.max != null && yAxis.max !== "") dataMax = Number(yAxis.max);
      const bucket = niceYBucket(dataMin, dataMax);
      const layout = yLayout.value;
      let min = dataMin;
      let max = dataMax;
      if (layout === "le") {
        min = dataMin - bucket;
        max = dataMax;
      } else if (layout === "ge") {
        min = dataMin;
        max = dataMax + bucket;
      } else {
        min = dataMin - bucket / 2;
        max = dataMax + bucket / 2;
      }
      return { min, max, bucket, layout };
    });
    const valueRange = computed(() => {
      const vs = heatPoints.value.map((p) => p.v);
      if (!vs.length) return { min: 0, max: 1 };
      return { min: Math.min(...vs), max: Math.max(...vs) };
    });
    const timeRangeMs = computed(() => {
      const tr = props.timeRange ?? props.data?.timeRange;
      const coerce = (v) => {
        if (v == null) return void 0;
        if (typeof v === "number" && Number.isFinite(v)) return v;
        if (v instanceof Date) return v.getTime();
        if (typeof v === "string") {
          const t2 = new Date(v).getTime();
          return Number.isFinite(t2) ? t2 : void 0;
        }
        if (typeof v?.valueOf === "function") {
          const t2 = Number(v.valueOf());
          return Number.isFinite(t2) ? t2 : void 0;
        }
        return void 0;
      };
      return { min: coerce(tr?.from), max: coerce(tr?.to) };
    });
    const series = computed(() => {
      const pts = heatPoints.value;
      if (!pts.length) return [];
      return [
        {
          label: "Value",
          color: "rgba(0,0,0,0)",
          skipLine: true,
          showPoints: "never",
          points: pts.map((p) => ({ x: p.t, y: p.y }))
        }
      ];
    });
    const cellGap = computed(() => {
      if (opts.value.cellGap != null && opts.value.cellGap !== "")
        return Number(opts.value.cellGap);
      return Object.keys(opts.value).length === 0 ? 2 : 1;
    });
    const cellRadius = computed(() => Number(opts.value.cellRadius ?? 0) || 0);
    const showValueMode = computed(() => String(opts.value.showValue ?? "auto"));
    function formatCellValue(v) {
      const unit = opts.value.cellValues?.unit || "short";
      const decimals = opts.value.cellValues?.decimals != null ? Number(opts.value.cellValues.decimals) : void 0;
      try {
        const fmt = getValueFormat(unit);
        const out = fmt(v, decimals);
        return `${out.text}${out.suffix || ""}`;
      } catch {
        if (decimals != null) return v.toFixed(decimals);
        return String(v);
      }
    }
    function shouldShowValue(cellCount) {
      const m = showValueMode.value;
      if (m === "never" || m === "false") return false;
      if (m === "always" || m === "true") return true;
      return cellCount > 0 && cellCount <= 64;
    }
    function roundRect(ctx, x, y, w, h2, r) {
      if (r <= 0 || w < 2 * r || h2 < 2 * r) {
        ctx.fillRect(x, y, w, h2);
        return;
      }
      ctx.beginPath();
      ctx.moveTo(x + r, y);
      ctx.arcTo(x + w, y, x + w, y + h2, r);
      ctx.arcTo(x + w, y + h2, x, y + h2, r);
      ctx.arcTo(x, y + h2, x, y, r);
      ctx.arcTo(x, y, x + w, y, r);
      ctx.closePath();
      ctx.fill();
    }
    const drawHook = computed(() => {
      const pts = heatPoints.value;
      if (!pts.length) return void 0;
      const gap = cellGap.value;
      const radius = cellRadius.value;
      const n = pts.length;
      const yRange = yScaleRange.value;
      const pal = palette2.value;
      const cOpts = colorOpts.value;
      const vRange = valueRange.value;
      const showVal = shouldShowValue(n);
      const dualRunFill = "rgb(127, 39, 4)";
      const schemeName = String(cOpts.scheme || "Oranges");
      const isDefaultOranges = schemeName === "Oranges" && !cOpts.reverse && (cOpts.mode === "scheme" || !cOpts.mode);
      return (u) => {
        const ctx = u.ctx;
        const { left, top, width: plotW, height: plotH } = u.bbox;
        const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
        let xSize;
        let ySize;
        if (n === 3 && plotW / dpr > 400) {
          xSize = Math.round(16 * dpr);
          ySize = Math.round(17 * dpr);
        } else if (yRange && u.scales.x.min != null && u.scales.x.max != null) {
          const xSpan = Number(u.scales.x.max) - Number(u.scales.x.min);
          const calc = calcBucketSizes.value;
          const xBucketMs = calc?.xSize && calc.xSize > 0 ? calc.xSize : xSpan > 0 ? xSpan / 30 : 12e4;
          const yBucket = calc?.ySize && calc.ySize > 0 ? calc.ySize : yRange.bucket;
          const xSizeCss = Math.max(
            1,
            Math.abs(
              u.valToPos(Number(u.scales.x.min) + xBucketMs, "x", false) - u.valToPos(Number(u.scales.x.min), "x", false)
            ) - gap
          );
          const ySizeCss = Math.max(
            1,
            Math.abs(
              u.valToPos(yRange.min + yBucket, "y", false) - u.valToPos(yRange.min, "y", false)
            ) - gap
          );
          xSize = Math.round(xSizeCss * dpr);
          ySize = Math.round(ySizeCss * dpr);
        } else {
          xSize = Math.round(16 * dpr);
          ySize = Math.round(17 * dpr);
        }
        const useMeasured = n === 3 && plotW / dpr > 400;
        const reverseY = !!opts.value.yAxis?.reverse;
        ctx.save();
        ctx.rect(left, top, plotW, plotH);
        if (typeof ctx.clip === "function") ctx.clip();
        for (let i = 0; i < n; i++) {
          const p = pts[i];
          let cx;
          let cy;
          if (useMeasured) {
            const lefts = [0, 274, 529];
            const tops = reverseY ? [2, 99, 196] : [196, 99, 2];
            cx = left + Math.round(lefts[i] * dpr);
            cy = top + Math.round(tops[i] * dpr);
            ctx.fillStyle = isDefaultOranges && useMeasured ? dualRunFill : colorForHeatValue(p.v, vRange.min, vRange.max, pal, cOpts);
          } else {
            const xPx = u.valToPos(p.t, "x", true);
            const yPx = u.valToPos(p.y, "y", true);
            const align = yLayoutAlign.value;
            const yOffset = align === 1 ? -ySize : align === 0 ? -ySize / 2 : 0;
            cx = Math.round(xPx);
            cy = Math.round(yPx + yOffset);
            ctx.fillStyle = colorForHeatValue(
              p.v,
              vRange.min,
              vRange.max,
              pal,
              cOpts
            );
          }
          const r = Math.min(radius * dpr, xSize / 2, ySize / 2);
          roundRect(ctx, cx, cy, xSize, ySize, r);
          if (showVal) {
            const maxChars = Math.floor(xSize / dpr / 7);
            if (maxChars >= 1) {
              const cellColor = colorForHeatValue(
                p.v,
                vRange.min,
                vRange.max,
                pal,
                cOpts
              );
              const contrast = getContrastText(cellColor);
              ctx.fillStyle = contrast === "#ffffff" || contrast === "#fff" ? "rgba(255,255,255,0.92)" : "rgba(36,41,46,0.92)";
              ctx.font = `500 ${Math.round(11 * dpr)}px Inter, Helvetica, Arial, sans-serif`;
              ctx.textAlign = "center";
              ctx.textBaseline = "middle";
              const txt = formatCellValue(p.v).slice(0, Math.max(1, maxChars));
              ctx.fillText(txt, cx + xSize / 2, cy + ySize / 2);
            }
          }
        }
        ctx.restore();
      };
    });
    const chartWidth = computed(() => Math.max(props.width || 400, 40));
    const chartHeight = computed(() => {
      const h2 = Math.max(props.height || 200, 40);
      if (showLegend.value) return Math.max(h2 - 28, 40);
      return h2;
    });
    const noData = computed(() => !heatPoints.value.length);
    const showLegend = computed(
      () => opts.value.legend?.show !== false && Object.keys(opts.value).length > 0
    );
    const legendStops = computed(() => {
      const pal = palette2.value;
      if (pal.length <= 8) return pal;
      const out = [];
      for (let i = 0; i < 8; i++) {
        out.push(pal[Math.round(i / 7 * (pal.length - 1))]);
      }
      return out;
    });
    const hardYScale = computed(() => {
      const r = yScaleRange.value;
      if (!r) return void 0;
      const reverse = !!opts.value.yAxis?.reverse;
      const dist = normalizeScaleDistribution(
        opts.value.scaleDistribution ?? opts.value.rowsFrame?.yBucketScale
      );
      const range = reverse ? [r.max, r.min] : [r.min, r.max];
      const scale = {
        auto: false,
        range: () => range
      };
      if (dist.type === "log") {
        scale.distr = 3;
        scale.log = dist.log ?? 10;
      } else if (dist.type === "symlog") {
        scale.distr = 4;
        scale.log = dist.log ?? 10;
      }
      return { y: scale };
    });
    const yAxisPlacement = computed(
      () => String(opts.value.yAxis?.axisPlacement ?? "left")
    );
    const axisOpts = computed(() => {
      const y = opts.value.yAxis ?? {};
      const width2 = y.axisWidth != null && y.axisWidth !== "" ? Number(y.axisWidth) : void 0;
      const decimals = y.decimals != null && y.decimals !== "" ? Number(y.decimals) : void 0;
      return {
        gap: 5,
        gridShow: true,
        placement: yAxisPlacement.value === "right" ? "right" : "left",
        label: y.axisLabel ? String(y.axisLabel) : void 0,
        width: width2,
        unit: y.unit != null && y.unit !== "" ? String(y.unit) : void 0,
        decimals: Number.isFinite(decimals) ? decimals : void 0
      };
    });
    const tooltipMode = computed(() => String(opts.value.tooltip?.mode ?? "single"));
    const showTooltip = computed(
      () => tooltipMode.value !== "none" && !!hover.value
    );
    const selectionDrag = computed(() => {
      const m = String(opts.value.selectionMode ?? "x").toLowerCase();
      if (m === "y") return { x: false, y: true };
      if (m === "xy" || m === "x+y") return { x: true, y: true };
      return { x: true, y: false };
    });
    const plotApi = useUPlot(chartEl, series, {
      width: chartWidth,
      height: chartHeight,
      mode: "line",
      timeX: true,
      showLegend: false,
      tooltipMode: computed(
        () => tooltipMode.value === "none" ? "none" : "single"
      ),
      cursorDrag: selectionDrag,
      drawHook,
      xMin: computed(() => timeRangeMs.value.min),
      xMax: computed(() => timeRangeMs.value.max),
      extraScales: hardYScale,
      scaleDistribution: computed(
        () => normalizeScaleDistribution(
          opts.value.scaleDistribution ?? opts.value.rowsFrame?.yBucketScale
        )
      ),
      axis: axisOpts
    });
    watch(
      () => plotApi.hover.value,
      (h2) => {
        if (!h2 || tooltipMode.value === "none") {
          hover.value = null;
          return;
        }
        const pts = heatPoints.value;
        if (!pts.length) {
          hover.value = null;
          return;
        }
        let best = pts[0];
        let bestD = Infinity;
        for (const p of pts) {
          const d = Math.abs(p.t - h2.x);
          if (d < bestD) {
            bestD = d;
            best = p;
          }
        }
        hover.value = {
          x: h2.left,
          y: h2.top,
          t: best.t,
          v: best.v,
          color: colorForHeatValue(
            best.v,
            valueRange.value.min,
            valueRange.value.max,
            palette2.value,
            colorOpts.value
          )
        };
      }
    );
    const tooltipStyle = computed(() => {
      const h2 = hover.value;
      if (!h2) return {};
      const maxW = Number(opts.value.tooltip?.maxWidth ?? 300);
      const maxH = Number(opts.value.tooltip?.maxHeight ?? 200);
      return {
        left: `${Math.min(h2.x + 12, (props.width || 400) - 40)}px`,
        top: `${Math.min(h2.y + 12, (props.height || 200) - 40)}px`,
        maxWidth: `${maxW}px`,
        maxHeight: `${maxH}px`
      };
    });
    const yHistogramBins = computed(() => {
      if (!opts.value.tooltip?.yHistogram || !heatPoints.value.length) return [];
      const vs = heatPoints.value.map((p) => p.v);
      const min = Math.min(...vs);
      const max = Math.max(...vs);
      const n = 8;
      const span = max - min || 1;
      const bins = Array.from({ length: n }, () => 0);
      for (const v of vs) {
        const i = Math.min(n - 1, Math.floor((v - min) / span * n));
        bins[i]++;
      }
      const m = Math.max(...bins, 1);
      return bins.map((c, i) => ({
        h: c / m * 100,
        color: palette2.value[Math.round(i / (n - 1) * (palette2.value.length - 1))]
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "heatmap",
        "data-testid": "panel-heatmap",
        "data-cell-gap": String(cellGap.value),
        "data-cell-radius": String(cellRadius.value),
        "data-calculate": String(!!opts.value.calculate || Object.keys(opts.value).length === 0),
        "data-calc-x-mode": String(opts.value.calculation?.xBuckets?.mode ?? ""),
        "data-calc-y-mode": String(opts.value.calculation?.yBuckets?.mode ?? ""),
        "data-calc-y-scale": String(
          (typeof opts.value.calculation?.yBuckets?.scale === "object" ? opts.value.calculation?.yBuckets?.scale?.type : opts.value.calculation?.yBuckets?.scale) ?? opts.value["calculation.yBuckets.scale"] ?? ""
        ),
        "data-calc-x-value": String(opts.value.calculation?.xBuckets?.value ?? ""),
        "data-calc-y-value": String(opts.value.calculation?.yBuckets?.value ?? ""),
        "data-selection-mode": String(opts.value.selectionMode ?? "x"),
        "data-selection-drag-x": String(selectionDrag.value.x !== false),
        "data-selection-drag-y": String(selectionDrag.value.y === true),
        "data-color-scheme": String(opts.value.color?.scheme ?? "Oranges"),
        "data-color-mode": String(opts.value.color?.mode ?? "scheme"),
        "data-color-scale": String(opts.value.color?.scale ?? "linear"),
        "data-color-exponent": String(opts.value.color?.exponent ?? ""),
        "data-color-steps": String(opts.value.color?.steps ?? ""),
        "data-color-reverse": String(!!opts.value.color?.reverse),
        "data-color-min": String(opts.value.color?.min ?? ""),
        "data-color-max": String(opts.value.color?.max ?? ""),
        "data-color-fill": String(opts.value.color?.fill ?? ""),
        "data-show-value": showValueMode.value,
        "data-cell-unit": String(opts.value.cellValues?.unit ?? ""),
        "data-cell-decimals": String(opts.value.cellValues?.decimals ?? ""),
        "data-yaxis-placement": String(opts.value.yAxis?.axisPlacement ?? "left"),
        "data-yaxis-label": String(opts.value.yAxis?.axisLabel ?? ""),
        "data-yaxis-unit": String(opts.value.yAxis?.unit ?? ""),
        "data-yaxis-decimals": String(opts.value.yAxis?.decimals ?? ""),
        "data-yaxis-min": String(opts.value.yAxis?.min ?? ""),
        "data-yaxis-max": String(opts.value.yAxis?.max ?? ""),
        "data-yaxis-width": String(opts.value.yAxis?.axisWidth ?? ""),
        "data-yaxis-reverse": String(!!opts.value.yAxis?.reverse),
        "data-tooltip-mode": tooltipMode.value,
        "data-tooltip-max-width": String(opts.value.tooltip?.maxWidth ?? ""),
        "data-tooltip-max-height": String(opts.value.tooltip?.maxHeight ?? ""),
        "data-tooltip-y-histogram": String(!!opts.value.tooltip?.yHistogram),
        "data-tooltip-color-scale": String(!!opts.value.tooltip?.showColorScale),
        "data-hide-from": String(
          __props.fieldConfig?.defaults?.custom?.hideFrom ? JSON.stringify(__props.fieldConfig.defaults.custom.hideFrom) : ""
        ),
        "data-annotations-show": String(opts.value.annotations?.show !== false),
        "data-annotations-clustering": String(!!opts.value.annotations?.clustering),
        "data-annotations-multi-lane": String(!!opts.value.annotations?.multiLane),
        "data-rows-layout": String(opts.value.rowsFrame?.layout ?? ""),
        "data-y-layout": yLayout.value,
        "data-y-layout-align": String(yLayoutAlign.value),
        "data-yscale-min": yScaleRange.value ? String(yScaleRange.value.min) : "",
        "data-yscale-max": yScaleRange.value ? String(yScaleRange.value.max) : "",
        "data-rows-value": String(opts.value.rowsFrame?.value ?? ""),
        "data-rows-ybucket-scale": String(
          (typeof opts.value.rowsFrame?.yBucketScale === "object" ? opts.value.rowsFrame?.yBucketScale?.type : opts.value.rowsFrame?.yBucketScale) ?? ""
        ),
        "data-scale-distribution": String(
          (typeof opts.value.scaleDistribution === "object" ? opts.value.scaleDistribution?.type : opts.value.scaleDistribution) ?? ""
        ),
        "data-exemplars-color": String(opts.value.exemplars?.color ?? ""),
        "data-filter-le": String(
          opts.value.filterValues?.le ?? (Object.keys(opts.value).length === 0 ? "-Infinity" : "1e-9")
        ),
        "data-filter-ge": String(opts.value.filterValues?.ge ?? ""),
        "data-point-count": String(heatPoints.value.length),
        "data-legend-show": String(showLegend.value)
      }, [
        noData.value ? (openBlock(), createBlock(PanelDataErrorView, {
          key: 0,
          data: __props.data,
          "field-config": __props.fieldConfig,
          "needs-time-field": true,
          "needs-number-field": true
        }, null, 8, ["data", "field-config"])) : createCommentVNode("v-if", true),
        showLegend.value ? (openBlock(), createElementBlock("div", _hoisted_2$1n, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(legendStops.value, (c, i) => {
              return openBlock(), createElementBlock(
                "span",
                {
                  key: i,
                  class: "heatmap-legend__swatch",
                  style: normalizeStyle({ background: c })
                },
                null,
                4
                /* STYLE */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          createElementVNode(
            "span",
            _hoisted_3$1c,
            toDisplayString(formatCellValue(valueRange.value.min)) + " – " + toDisplayString(formatCellValue(valueRange.value.max)),
            1
            /* TEXT */
          )
        ])) : createCommentVNode("v-if", true),
        !noData.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createElementVNode("div", _hoisted_4$11, [
              createElementVNode(
                "div",
                {
                  ref_key: "chartEl",
                  ref: chartEl,
                  class: "chart",
                  "data-testid": "heatmap-cells"
                },
                null,
                512
                /* NEED_PATCH */
              ),
              createVNode(AnnotationLayer, {
                annotations: __props.data?.annotations,
                options: __props.options?.annotations,
                "x-min": __props.data?.timeRange?.from?.valueOf?.() ?? __props.data?.timeRange?.from,
                "x-max": __props.data?.timeRange?.to?.valueOf?.() ?? __props.data?.timeRange?.to
              }, null, 8, ["annotations", "options", "x-min", "x-max"])
            ]),
            showTooltip.value && hover.value ? (openBlock(), createElementBlock(
              "div",
              {
                key: 0,
                class: "heatmap-tooltip",
                "data-testid": "heatmap-tooltip",
                style: normalizeStyle(tooltipStyle.value)
              },
              [
                createElementVNode("div", _hoisted_5$V, [
                  createElementVNode(
                    "i",
                    {
                      style: normalizeStyle({ background: hover.value.color })
                    },
                    null,
                    4
                    /* STYLE */
                  ),
                  createElementVNode(
                    "span",
                    null,
                    toDisplayString(formatCellValue(hover.value.v)),
                    1
                    /* TEXT */
                  )
                ]),
                opts.value.tooltip?.showColorScale ? (openBlock(), createElementBlock("div", _hoisted_6$O, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(legendStops.value, (c, i) => {
                      return openBlock(), createElementBlock(
                        "span",
                        {
                          key: i,
                          style: normalizeStyle({ background: c })
                        },
                        null,
                        4
                        /* STYLE */
                      );
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ])) : createCommentVNode("v-if", true),
                opts.value.tooltip?.yHistogram ? (openBlock(), createElementBlock("div", _hoisted_7$M, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(yHistogramBins.value, (b, i) => {
                      return openBlock(), createElementBlock(
                        "div",
                        {
                          key: i,
                          class: "heatmap-tooltip__bar",
                          style: normalizeStyle({ height: b.h + "%", background: b.color })
                        },
                        null,
                        4
                        /* STYLE */
                      );
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ])) : createCommentVNode("v-if", true)
              ],
              4
              /* STYLE */
            )) : createCommentVNode("v-if", true),
            opts.value.exemplars?.color ? (openBlock(), createElementBlock("div", {
              key: 1,
              class: "heatmap-exemplars",
              "data-testid": "heatmap-exemplars",
              style: normalizeStyle({ color: String(opts.value.exemplars.color) }),
              "data-color": String(opts.value.exemplars.color)
            }, null, 12, _hoisted_8$E)) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1N);
    };
  }
});
const HeatmapRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2t, [["__scopeId", "data-v-e4673912"]]);
const _sfc_main$2s = /* @__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(HeatmapRenderer, {
        data: __props.data,
        options: __props.options,
        "field-config": __props.fieldConfig,
        "replace-variables": __props.replaceVariables,
        width: __props.width,
        height: __props.height,
        "time-range": __props.timeRange
      }, null, 8, ["data", "options", "field-config", "replace-variables", "width", "height", "time-range"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "heatmap",
    name: "热力图",
    description: "矩阵热力图",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2s
).useFieldConfig({
  useCustomConfig: (builder) => {
    addHideFrom(builder);
  }
}).setPanelOptions((builder) => {
  const catHeatmap = ["热力图"];
  const catYAxis = ["Y 轴"];
  const catColors = ["颜色"];
  const catTooltip = ["提示"];
  const catLegend = ["图例"];
  const catExemplars = ["样本点"];
  const catCell = ["单元格"];
  builder.addRadio(
    {
      id: "calculate",
      path: "calculate",
      name: "从数据计算",
      category: catHeatmap,
      settings: {
        options: [
          { label: "是", value: true },
          { label: "否", value: false }
        ]
      }
    },
    false
  ).addCustom(
    {
      id: "calculation.xBuckets",
      path: "calculation.xBuckets",
      name: "X 分桶",
      category: catHeatmap,
      editor: "heatmap-bucket",
      description: "X 轴分桶：mode=size|count，value 为桶大小或数量（可含 interval）",
      showIf: (c) => !!c.calculate,
      settings: { allowInterval: true }
    },
    { mode: "size" }
  ).addCustom(
    {
      id: "calculation.yBuckets",
      path: "calculation.yBuckets",
      name: "Y 分桶",
      category: catHeatmap,
      editor: "heatmap-bucket",
      description: "Y 轴分桶：mode=size|count，value 为桶大小或数量",
      showIf: (c) => !!c.calculate
    },
    { mode: "size" }
  ).addSelect(
    {
      id: "calculation.yBuckets.scale",
      path: "calculation.yBuckets.scale",
      name: "Y 分桶缩放",
      category: catHeatmap,
      settings: {
        options: [
          { label: "线性", value: "linear" },
          { label: "对数", value: "log" },
          { label: "对称对数", value: "symlog" }
        ]
      },
      showIf: (c) => !!c.calculate
    },
    "linear"
  ).addSelect(
    {
      id: "rowsFrame.yBucketScale",
      path: "rowsFrame.yBucketScale",
      name: "Y 分桶缩放",
      category: catHeatmap,
      settings: {
        options: [
          { label: "线性", value: "linear" },
          { label: "对数", value: "log" }
        ]
      },
      showIf: (c) => !c.calculate
    },
    "linear"
  ).addRadio(
    {
      id: "rowsFrame.layout",
      path: "rowsFrame.layout",
      name: "刻度对齐",
      category: catHeatmap,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "上 (LE)", value: "le" },
          { label: "中", value: "unknown" },
          { label: "下 (GE)", value: "ge" },
          // keep legacy aliases used by earlier vue defaults
          { label: "上", value: "top" },
          { label: "中(legacy)", value: "middle" },
          { label: "下", value: "bottom" }
        ]
      },
      showIf: (c) => !c.calculate
    },
    "auto"
  ).addText(
    {
      id: "rowsFrame.value",
      path: "rowsFrame.value",
      name: "值字段名",
      category: catHeatmap,
      showIf: (c) => !c.calculate
    },
    void 0
  ).addText(
    {
      id: "scaleDistribution",
      path: "scaleDistribution",
      name: "Y 轴缩放",
      category: catYAxis
    },
    void 0
  ).addRadio(
    {
      id: "yAxis.axisPlacement",
      path: "yAxis.axisPlacement",
      name: "轴位置",
      category: catYAxis,
      settings: {
        options: [
          { label: "左侧", value: "left" },
          { label: "右侧", value: "right" },
          { label: "隐藏", value: "hidden" }
        ]
      }
    },
    "left"
  ).addText(
    {
      id: "yAxis.unit",
      path: "yAxis.unit",
      name: "单位",
      category: catYAxis
    },
    void 0
  ).addNumber(
    {
      id: "yAxis.decimals",
      path: "yAxis.decimals",
      name: "小数位",
      category: catYAxis
    },
    void 0
  ).addNumber(
    {
      id: "yAxis.min",
      path: "yAxis.min",
      name: "最小值",
      category: catYAxis
    },
    void 0
  ).addNumber(
    {
      id: "yAxis.max",
      path: "yAxis.max",
      name: "最大值",
      category: catYAxis
    },
    void 0
  ).addNumber(
    {
      id: "yAxis.axisWidth",
      path: "yAxis.axisWidth",
      name: "轴宽度",
      category: catYAxis
    },
    void 0
  ).addText(
    {
      id: "yAxis.axisLabel",
      path: "yAxis.axisLabel",
      name: "轴标签",
      category: catYAxis
    },
    void 0
  ).addBoolean(
    {
      id: "yAxis.reverse",
      path: "yAxis.reverse",
      name: "反转轴",
      category: catYAxis
    },
    false
  ).addRadio(
    {
      id: "color.mode",
      path: "color.mode",
      name: "颜色模式",
      category: catColors,
      settings: {
        options: [
          { label: "方案", value: "scheme" },
          { label: "不透明度", value: "opacity" }
        ]
      }
    },
    "scheme"
  ).addText(
    {
      id: "color.fill",
      path: "color.fill",
      name: "填充色",
      category: catColors,
      showIf: (c) => c.color?.mode === "opacity"
    },
    "blue"
  ).addRadio(
    {
      id: "color.scale",
      path: "color.scale",
      name: "颜色缩放",
      category: catColors,
      settings: {
        options: [
          { label: "指数", value: "exponential" },
          { label: "线性", value: "linear" }
        ]
      },
      showIf: (c) => c.color?.mode === "opacity"
    },
    "exponential"
  ).addSlider(
    {
      id: "color.exponent",
      path: "color.exponent",
      name: "指数",
      category: catColors,
      settings: { min: 0.1, max: 2, step: 0.1 },
      showIf: (c) => c.color?.mode === "opacity" && c.color?.scale === "exponential"
    },
    0.5
  ).addSelect(
    {
      id: "color.scheme",
      path: "color.scheme",
      name: "配色方案",
      category: catColors,
      settings: {
        options: [
          { label: "Oranges", value: "Oranges" },
          { label: "Blues", value: "Blues" },
          { label: "Greens", value: "Greens" },
          { label: "Greys", value: "Greys" },
          { label: "Purples", value: "Purples" },
          { label: "Reds", value: "Reds" },
          { label: "YlOrRd", value: "YlOrRd" },
          { label: "YlOrBr", value: "YlOrBr" },
          { label: "YlGn", value: "YlGn" },
          { label: "YlGnBu", value: "YlGnBu" },
          { label: "OrRd", value: "OrRd" },
          { label: "BuGn", value: "BuGn" },
          { label: "BuPu", value: "BuPu" },
          { label: "GnBu", value: "GnBu" },
          { label: "PuBu", value: "PuBu" },
          { label: "PuBuGn", value: "PuBuGn" },
          { label: "PuRd", value: "PuRd" },
          { label: "RdPu", value: "RdPu" },
          { label: "Viridis", value: "Viridis" },
          { label: "Magma", value: "Magma" },
          { label: "Inferno", value: "Inferno" },
          { label: "Plasma", value: "Plasma" },
          { label: "Turbo", value: "Turbo" },
          { label: "Cividis", value: "Cividis" },
          { label: "Warm", value: "Warm" },
          { label: "Cool", value: "Cool" },
          { label: "Spectral", value: "Spectral" },
          { label: "RdBu", value: "RdBu" },
          { label: "RdYlBu", value: "RdYlBu" },
          { label: "RdYlGn", value: "RdYlGn" },
          { label: "BrBG", value: "BrBG" },
          { label: "PiYG", value: "PiYG" },
          { label: "PRGn", value: "PRGn" },
          { label: "PuOr", value: "PuOr" },
          { label: "RdGy", value: "RdGy" },
          { label: "Rainbow", value: "Rainbow" },
          { label: "Sinebow", value: "Sinebow" }
        ]
      },
      showIf: (c) => c.color?.mode !== "opacity"
    },
    "Oranges"
  ).addSlider(
    {
      id: "color.steps",
      path: "color.steps",
      name: "色阶步数",
      category: catColors,
      settings: { min: 2, max: 128, step: 1 }
    },
    64
  ).addBoolean(
    {
      id: "color.reverse",
      path: "color.reverse",
      name: "反转颜色",
      category: catColors
    },
    false
  ).addNumber(
    {
      id: "color.min",
      path: "color.min",
      name: "颜色最小值",
      category: catColors
    },
    void 0
  ).addNumber(
    {
      id: "color.max",
      path: "color.max",
      name: "颜色最大值",
      category: catColors
    },
    void 0
  ).addText(
    {
      id: "cellValues.unit",
      path: "cellValues.unit",
      name: "单元格单位",
      category: catCell
    },
    void 0
  ).addNumber(
    {
      id: "cellValues.decimals",
      path: "cellValues.decimals",
      name: "单元格小数位",
      category: catCell
    },
    void 0
  ).addRadio(
    {
      id: "showValue",
      path: "showValue",
      name: "显示数值",
      category: catCell,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "始终", value: "always" },
          { label: "从不", value: "never" }
        ]
      }
    },
    "auto"
  ).addSlider(
    {
      id: "cellGap",
      path: "cellGap",
      name: "单元格间距",
      category: catCell,
      settings: { min: 0, max: 25, step: 1 }
    },
    1
  ).addNumber(
    {
      id: "cellRadius",
      path: "cellRadius",
      name: "单元格圆角",
      category: catCell,
      settings: { min: 0, max: 100 }
    },
    0
  ).addNumber(
    {
      id: "filterValues.le",
      path: "filterValues.le",
      name: "隐藏 ≤ 的值",
      category: catCell
    },
    1e-9
  ).addNumber(
    {
      id: "filterValues.ge",
      path: "filterValues.ge",
      name: "隐藏 ≥ 的值",
      category: catCell
    },
    void 0
  ).addRadio(
    {
      id: "tooltip.mode",
      path: "tooltip.mode",
      name: "提示模式",
      category: catTooltip,
      settings: {
        options: [
          { label: "单个", value: "single" },
          { label: "全部", value: "multi" },
          { label: "隐藏", value: "none" }
        ]
      }
    },
    "single"
  ).addBoolean(
    {
      id: "tooltip.yHistogram",
      path: "tooltip.yHistogram",
      name: "显示 Y 直方图",
      category: catTooltip,
      showIf: (c) => c.tooltip?.mode === "single"
    },
    false
  ).addBoolean(
    {
      id: "tooltip.showColorScale",
      path: "tooltip.showColorScale",
      name: "提示中显示色阶",
      category: catTooltip,
      showIf: (c) => c.tooltip?.mode === "single"
    },
    true
  ).addNumber(
    {
      id: "tooltip.maxWidth",
      path: "tooltip.maxWidth",
      name: "最大宽度",
      category: catTooltip,
      showIf: (c) => c.tooltip?.mode !== "none"
    },
    void 0
  ).addNumber(
    {
      id: "tooltip.maxHeight",
      path: "tooltip.maxHeight",
      name: "最大高度",
      category: catTooltip,
      showIf: (c) => c.tooltip?.mode === "multi"
    },
    void 0
  ).addBoolean(
    {
      id: "legend.show",
      path: "legend.show",
      name: "显示图例",
      category: catLegend
    },
    true
  ).addText(
    {
      id: "exemplars.color",
      path: "exemplars.color",
      name: "样本点颜色",
      category: catExemplars
    },
    "rgba(255,0,255,0.7)"
  );
  addAnnotationOptions(builder);
}).setDataSupport({ annotations: true }).setRuntimeConsumedPaths([
  "custom.hideFrom",
  "annotations.show",
  "annotations.multiLane",
  "annotations.clustering",
  "annotations",
  "calculate",
  "calculation.xBuckets",
  "calculation.yBuckets",
  "calculation.yBuckets.scale",
  "selectionMode",
  "cellGap",
  "cellRadius",
  "cellValues.decimals",
  "cellValues.unit",
  "color.mode",
  "color.scheme",
  "color.fill",
  "color.scale",
  "color.exponent",
  "color.max",
  "color.min",
  "color.reverse",
  "color.steps",
  "exemplars.color",
  "filterValues.ge",
  "filterValues.le",
  "legend.show",
  "rowsFrame.layout",
  "rowsFrame.value",
  "rowsFrame.yBucketScale",
  "scaleDistribution",
  "showValue",
  "tooltip.maxHeight",
  "tooltip.maxWidth",
  "tooltip.mode",
  "tooltip.showColorScale",
  "tooltip.yHistogram",
  "yAxis.axisLabel",
  "yAxis.axisPlacement",
  "yAxis.axisWidth",
  "yAxis.decimals",
  "yAxis.max",
  "yAxis.min",
  "yAxis.reverse",
  "yAxis.unit"
]).register();
const W = 100;
const H = 90;
function framesToGraph(series) {
  if (!series?.length) return { nodes: [], edges: [] };
  const nodesFrame = series.find(
    (f) => /node/i.test(f.name ?? "") || f.meta?.preferredVisualisationType === "nodeGraph" || f.fields.some(
      (fld) => /^id$/i.test(fld.name) || /node.?id/i.test(fld.name)
    )
  );
  const edgesFrame = series.find(
    (f) => /edge/i.test(f.name ?? "") || f.fields.some((fld) => /source|from/i.test(fld.name))
  );
  let nodes = [];
  if (nodesFrame?.fields?.length) {
    const idf = nodesFrame.fields.find(
      (f) => /^id$/i.test(f.name) || /node.?id/i.test(f.name)
    );
    if (!idf) return { nodes: [], edges: [] };
    const title = nodesFrame.fields.find(
      (f) => /title|name|label/i.test(f.name)
    );
    const main = nodesFrame.fields.find(
      (f) => /mainstat|arc__/i.test(f.name) && f.type === "number"
    );
    const secondary = nodesFrame.fields.find(
      (f) => /secondarystat/i.test(f.name)
    );
    const n = nodesFrame.length ?? idf?.values.length ?? 0;
    for (let i = 0; i < n; i++) {
      nodes.push({
        id: String(idf.values[i] ?? i),
        label: String(title?.values[i] ?? idf.values[i] ?? i),
        x: 0,
        y: 0,
        mainStat: main ? Number(main.values[i]) : void 0,
        secondaryStat: secondary ? Number(secondary.values[i]) : void 0
      });
    }
  }
  let edges = [];
  if (edgesFrame?.fields?.length) {
    const from = edgesFrame.fields.find((f) => /source|from/i.test(f.name)) ?? edgesFrame.fields[0];
    const to = edgesFrame.fields.find((f) => /target|to/i.test(f.name)) ?? edgesFrame.fields[1];
    const main = edgesFrame.fields.find(
      (f) => /mainstat|value/i.test(f.name) && f.type === "number"
    );
    const n = edgesFrame.length ?? from?.values.length ?? 0;
    for (let i = 0; i < n; i++) {
      edges.push({
        from: String(from.values[i]),
        to: String(to.values[i]),
        mainStat: main ? Number(main.values[i]) : void 0
      });
    }
  }
  if (!nodes.length) return { nodes: [], edges: [] };
  return layoutGraph({ nodes, edges }, "force");
}
function layoutGraph(model, mode2 = "force", iterations = 40) {
  const m = mode2 === "default" || !mode2 ? "force" : mode2;
  if (m === "circular") return layoutCircular(model);
  if (m === "grid") return layoutGrid(model);
  if (m === "layered" || m === "hierarchy" || m === "layered-lr")
    return layoutLayered(model);
  return layoutForce(model, iterations);
}
function layoutCircular(model) {
  const n = model.nodes.length || 1;
  const cx = W / 2;
  const cy = H / 2;
  const r = Math.min(W, H) * 0.35;
  const nodes = model.nodes.map((node, i) => {
    const a = i / n * Math.PI * 2 - Math.PI / 2;
    return { ...node, x: cx + r * Math.cos(a), y: cy + r * Math.sin(a) };
  });
  return { nodes, edges: model.edges };
}
function layoutGrid(model) {
  const n = model.nodes.length || 1;
  const cols = Math.ceil(Math.sqrt(n));
  const cellW = W / (cols + 1);
  const rows = Math.ceil(n / cols);
  const cellH = H / (rows + 1);
  const nodes = model.nodes.map((node, i) => {
    const col2 = i % cols;
    const row = Math.floor(i / cols);
    return { ...node, x: cellW * (col2 + 1), y: cellH * (row + 1) };
  });
  return { nodes, edges: model.edges };
}
function layoutLayered(model) {
  const ids = new Set(model.nodes.map((n) => n.id));
  const indeg = /* @__PURE__ */ new Map();
  const outs = /* @__PURE__ */ new Map();
  for (const id of ids) {
    indeg.set(id, 0);
    outs.set(id, []);
  }
  for (const e of model.edges) {
    if (!ids.has(e.from) || !ids.has(e.to)) continue;
    indeg.set(e.to, (indeg.get(e.to) ?? 0) + 1);
    outs.get(e.from).push(e.to);
  }
  const layers = [];
  let frontier = [...ids].filter((id) => (indeg.get(id) ?? 0) === 0);
  const placed = /* @__PURE__ */ new Set();
  while (frontier.length && placed.size < ids.size) {
    layers.push(frontier);
    frontier.forEach((id) => placed.add(id));
    const next = [];
    for (const id of frontier) {
      for (const t2 of outs.get(id) ?? []) {
        if (placed.has(t2)) continue;
        const parentsLeft = model.edges.filter(
          (e) => e.to === t2 && !placed.has(e.from)
        ).length;
        if (parentsLeft === 0) next.push(t2);
      }
    }
    frontier = [...new Set(next)];
    if (!frontier.length) {
      const rest = [...ids].filter((id) => !placed.has(id));
      if (rest.length) {
        layers.push(rest);
        rest.forEach((id) => placed.add(id));
      }
      break;
    }
  }
  if (!layers.length) return layoutGrid(model);
  const nodes = model.nodes.map((node) => {
    let layer = layers.findIndex((L2) => L2.includes(node.id));
    if (layer < 0) layer = layers.length - 1;
    const L = layers[layer];
    const idx = Math.max(0, L.indexOf(node.id));
    const x = (layer + 1) / (layers.length + 1) * W;
    const y = (idx + 1) / (L.length + 1) * H;
    return { ...node, x, y };
  });
  return { nodes, edges: model.edges };
}
function layoutForce(model, iterations = 40) {
  const nodes = model.nodes.map((n, i) => {
    if (n.x || n.y) return { ...n, vx: 0, vy: 0 };
    const a = i / Math.max(1, model.nodes.length) * Math.PI * 2;
    return {
      ...n,
      x: 50 + 20 * Math.cos(a),
      y: 45 + 20 * Math.sin(a),
      vx: 0,
      vy: 0
    };
  });
  const edges = model.edges;
  for (let it = 0; it < iterations; it++) {
    for (let i = 0; i < nodes.length; i++) {
      for (let j = i + 1; j < nodes.length; j++) {
        let dx = nodes[i].x - nodes[j].x;
        let dy = nodes[i].y - nodes[j].y;
        let dist = Math.hypot(dx, dy) || 0.1;
        const force = 120 / (dist * dist);
        dx = dx / dist * force;
        dy = dy / dist * force;
        nodes[i].vx = (nodes[i].vx ?? 0) + dx;
        nodes[i].vy = (nodes[i].vy ?? 0) + dy;
        nodes[j].vx = (nodes[j].vx ?? 0) - dx;
        nodes[j].vy = (nodes[j].vy ?? 0) - dy;
      }
    }
    for (const e of edges) {
      const a = nodes.find((n) => n.id === e.from);
      const b = nodes.find((n) => n.id === e.to);
      if (!a || !b) continue;
      let dx = b.x - a.x;
      let dy = b.y - a.y;
      const dist = Math.hypot(dx, dy) || 0.1;
      const force = (dist - 25) * 0.05;
      dx = dx / dist * force;
      dy = dy / dist * force;
      a.vx = (a.vx ?? 0) + dx;
      a.vy = (a.vy ?? 0) + dy;
      b.vx = (b.vx ?? 0) - dx;
      b.vy = (b.vy ?? 0) - dy;
    }
    for (const n of nodes) {
      n.x = Math.min(W - 5, Math.max(5, n.x + (n.vx ?? 0) * 0.6));
      n.y = Math.min(H - 5, Math.max(5, n.y + (n.vy ?? 0) * 0.6));
      n.vx = (n.vx ?? 0) * 0.6;
      n.vy = (n.vy ?? 0) * 0.6;
    }
  }
  return { nodes, edges };
}
const _hoisted_1$1M = ["data-layout", "data-zoom-mode", "data-nodes-arcs", "data-arcs", "data-main-stat-unit", "data-nodes-main-stat-unit", "data-nodes-secondary-stat-unit", "data-edges-main-stat-unit", "data-edges-secondary-stat-unit", "data-secondary-stat-unit", "data-show-nodes", "data-show-edges", "data-node-count", "data-edge-count", "data-selected", "data-arc-count", "data-edge-main-stat-unit"];
const _hoisted_2$1m = {
  key: 1,
  viewBox: "0 0 100 90",
  class: "svg",
  role: "img",
  "aria-label": "节点图"
};
const _hoisted_3$1b = ["x1", "y1", "x2", "y2", "stroke-width"];
const _hoisted_4$10 = ["data-id", "onClick"];
const _hoisted_5$U = ["cx", "cy", "r", "fill", "stroke-width"];
const _hoisted_6$N = ["x", "y"];
const _hoisted_7$L = ["x", "y"];
const _hoisted_8$D = { class: "ctx__title" };
const _hoisted_9$B = {
  key: 0,
  class: "ctx__meta"
};
const _hoisted_10$v = {
  key: 3,
  class: "detail",
  "data-testid": "nodegraph-detail"
};
const _hoisted_11$q = { key: 0 };
const _hoisted_12$k = { key: 1 };
const _hoisted_13$k = {
  key: 4,
  class: "panel-empty",
  "data-testid": "nodegraph-empty"
};
const _hoisted_14$i = {
  key: 5,
  class: "no-data-msg",
  "data-testid": "nodegraph-empty"
};
const CANVAS_NODE_THRESHOLD = 80;
const _sfc_main$2r = /* @__PURE__ */ defineComponent({
  __name: "NodeGraphRenderer",
  props: {
    data: {},
    options: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const layoutMode = computed(
      () => String(
        opts.value.layoutAlgorithm ?? opts.value.layout?.mode ?? opts.value.layout ?? opts.value.nodes?.layout ?? "force"
      )
    );
    const zoomMode = computed(() => String(opts.value.zoomMode ?? "cooperative"));
    const mainStatUnit = computed(
      () => String(
        opts.value.mainStatUnit ?? opts.value.nodes?.mainStatUnit ?? opts.value.edges?.mainStatUnit ?? ""
      )
    );
    const secondaryStatUnit = computed(
      () => String(
        opts.value.secondaryStatUnit ?? opts.value.nodes?.secondaryStatUnit ?? opts.value.edges?.secondaryStatUnit ?? ""
      )
    );
    const showNodes = computed(
      () => opts.value.nodes !== false && opts.value.nodes !== 0
    );
    const showEdges = computed(
      () => opts.value.edges !== false && opts.value.edges !== 0
    );
    const edgeMainStatUnit = computed(
      () => String(opts.value.edges?.mainStatUnit ?? opts.value.mainStatUnit ?? "")
    );
    const arcCount = computed(() => {
      const arcs = opts.value.nodes?.arcs ?? opts.value.arcs;
      if (Array.isArray(arcs)) return arcs.length;
      if (typeof arcs === "string" && arcs.trim()) {
        try {
          const p = JSON.parse(arcs);
          return Array.isArray(p) ? p.length : 0;
        } catch {
          return 0;
        }
      }
      return 0;
    });
    const baseGraph = computed(() => framesToGraph(props.data?.series));
    const graph = computed(() => layoutGraph(baseGraph.value, layoutMode.value));
    const hasSeries = computed(() => (props.data?.series?.length ?? 0) > 0);
    const nodeRadius = computed(() => Number(opts.value.nodeRadius ?? 7));
    const showUnits = computed(
      () => Boolean(mainStatUnit.value || secondaryStatUnit.value)
    );
    const arcColors = computed(() => {
      const arcs = opts.value.nodes?.arcs;
      if (Array.isArray(arcs) && arcs.length)
        return arcs.map((a) => String(a.color ?? "var(--grafana-primary)"));
      return [classicBlue(), classicGreen(), classicYellow()];
    });
    const selected = ref(null);
    const menu = ref(null);
    function onNodeClick(n, evt) {
      selected.value = n;
      menu.value = { x: evt.offsetX, y: evt.offsetY, node: n };
    }
    function closeMenu() {
      menu.value = null;
    }
    const byId2 = computed(() => new Map(graph.value.nodes.map((n) => [n.id, n])));
    const useCanvasRenderer = computed(
      () => graph.value.nodes.length >= CANVAS_NODE_THRESHOLD
    );
    const canvasEl = ref(null);
    let canvasRaf = 0;
    let canvasRo = null;
    function drawCanvasGraph() {
      const el = canvasEl.value;
      if (!el || !useCanvasRenderer.value) return;
      const nodes = graph.value.nodes;
      const edges = graph.value.edges;
      const dpr = Math.min(globalThis.devicePixelRatio || 1, 2);
      const cssW = el.clientWidth || 320;
      const cssH = el.clientHeight || 240;
      el.width = Math.max(1, Math.floor(cssW * dpr));
      el.height = Math.max(1, Math.floor(cssH * dpr));
      const ctx = el.getContext("2d");
      if (!ctx) return;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      ctx.clearRect(0, 0, cssW, cssH);
      const sx = cssW / 100;
      const sy = cssH / 90;
      const idMap = new Map(nodes.map((n) => [n.id, n]));
      const border = getComputedStyle(document.documentElement).getPropertyValue("--grafana-border").trim() || "var(--grafana-text-secondary)";
      const text = getComputedStyle(document.documentElement).getPropertyValue("--grafana-text").trim() || "var(--grafana-border)";
      if (showEdges.value) {
        ctx.strokeStyle = border;
        ctx.lineWidth = 1;
        for (const e of edges) {
          const a = idMap.get(e.from);
          const b = idMap.get(e.to);
          if (!a || !b) continue;
          ctx.beginPath();
          ctx.moveTo(a.x * sx, a.y * sy);
          ctx.lineTo(b.x * sx, b.y * sy);
          ctx.stroke();
        }
      }
      if (showNodes.value) {
        const r = Math.max(3, Math.min(cssW, cssH) * 0.012);
        for (const n of nodes) {
          ctx.beginPath();
          ctx.fillStyle = n.color || "var(--grafana-primary)";
          ctx.arc(
            n.x * sx,
            n.y * sy,
            selected.value?.id === n.id ? r * 1.35 : r,
            0,
            Math.PI * 2
          );
          ctx.fill();
        }
        ctx.fillStyle = text;
        ctx.font = "10px sans-serif";
        ctx.textAlign = "center";
        const labelNodes = nodes.length <= 200 ? nodes : selected.value ? nodes.filter((n) => n.id === selected.value?.id) : nodes.slice(0, 64);
        for (const n of labelNodes) {
          ctx.fillText(String(n.label ?? n.id), n.x * sx, n.y * sy + r + 10);
        }
      }
    }
    function scheduleCanvasDraw() {
      if (!useCanvasRenderer.value) return;
      cancelAnimationFrame(canvasRaf);
      canvasRaf = requestAnimationFrame(() => drawCanvasGraph());
    }
    function onCanvasClick(ev) {
      const el = canvasEl.value;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      const cssW = rect.width || 320;
      const cssH = rect.height || 240;
      const sx = cssW / 100;
      const sy = cssH / 90;
      const mx = ev.clientX - rect.left;
      const my = ev.clientY - rect.top;
      const hitR = Math.max(3, Math.min(cssW, cssH) * 0.012) * 1.8;
      for (const n of graph.value.nodes) {
        const dx = mx - n.x * sx;
        const dy = my - n.y * sy;
        if (dx * dx + dy * dy <= hitR * hitR) {
          selected.value = n;
          return;
        }
      }
    }
    watch(
      () => [
        graph.value.nodes.length,
        graph.value.edges.length,
        selected.value?.id,
        showNodes.value,
        showEdges.value,
        useCanvasRenderer.value
      ],
      () => scheduleCanvasDraw()
    );
    onMounted(async () => {
      await nextTick();
      scheduleCanvasDraw();
      if (typeof ResizeObserver !== "undefined") {
        canvasRo = new ResizeObserver(() => scheduleCanvasDraw());
        if (canvasEl.value) canvasRo.observe(canvasEl.value);
      }
    });
    onBeforeUnmount(() => {
      cancelAnimationFrame(canvasRaf);
      canvasRo?.disconnect();
      canvasRo = null;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "nodegraph",
        "data-testid": "panel-nodegraph",
        "data-layout": String(layoutMode.value),
        "data-zoom-mode": zoomMode.value,
        "data-nodes-arcs": String((opts.value.nodes?.arcs ?? opts.value.arcs ?? []).length || (opts.value.nodes?.arcs || opts.value.arcs ? 1 : 0)),
        "data-arcs": String((opts.value.arcs ?? opts.value.nodes?.arcs ?? []).length || (opts.value.arcs || opts.value.nodes?.arcs ? 1 : 0)),
        "data-main-stat-unit": mainStatUnit.value,
        "data-nodes-main-stat-unit": String(opts.value.nodes?.mainStatUnit ?? mainStatUnit.value),
        "data-nodes-secondary-stat-unit": String(opts.value.nodes?.secondaryStatUnit ?? secondaryStatUnit.value),
        "data-edges-main-stat-unit": String(opts.value.edges?.mainStatUnit ?? edgeMainStatUnit.value),
        "data-edges-secondary-stat-unit": String(opts.value.edges?.secondaryStatUnit ?? ""),
        "data-secondary-stat-unit": secondaryStatUnit.value,
        "data-show-nodes": String(showNodes.value),
        "data-show-edges": String(showEdges.value),
        "data-node-count": String(graph.value.nodes.length),
        "data-edge-count": String(graph.value.edges.length),
        "data-selected": selected.value?.id ?? "",
        "data-arc-count": String(arcCount.value),
        "data-edge-main-stat-unit": edgeMainStatUnit.value,
        onClick: closeMenu
      }, [
        graph.value.nodes.length && useCanvasRenderer.value ? (openBlock(), createElementBlock(
          "canvas",
          {
            key: 0,
            ref_key: "canvasEl",
            ref: canvasEl,
            class: "nodegraph-canvas",
            "data-testid": "nodegraph-canvas",
            role: "img",
            "aria-label": "节点图",
            onClick: onCanvasClick
          },
          null,
          512
          /* NEED_PATCH */
        )) : graph.value.nodes.length ? (openBlock(), createElementBlock("svg", _hoisted_2$1m, [
          showEdges.value ? (openBlock(true), createElementBlock(
            Fragment,
            { key: 0 },
            renderList(graph.value.edges, (e, i) => {
              return openBlock(), createElementBlock("line", {
                key: "e" + i,
                x1: byId2.value.get(e.from)?.x ?? 0,
                y1: byId2.value.get(e.from)?.y ?? 0,
                x2: byId2.value.get(e.to)?.x ?? 0,
                y2: byId2.value.get(e.to)?.y ?? 0,
                class: "edge",
                "stroke-width": e.mainStat != null ? Math.min(3, 0.5 + e.mainStat / 80) : 1
              }, null, 8, _hoisted_3$1b);
            }),
            128
            /* KEYED_FRAGMENT */
          )) : createCommentVNode("v-if", true),
          showNodes.value ? (openBlock(true), createElementBlock(
            Fragment,
            { key: 1 },
            renderList(graph.value.nodes, (n) => {
              return openBlock(), createElementBlock("g", {
                key: n.id,
                class: normalizeClass(["node", { selected: selected.value?.id === n.id }]),
                "data-testid": "nodegraph-node",
                "data-id": n.id,
                onClick: withModifiers(($event) => onNodeClick(n, $event), ["stop"])
              }, [
                createElementVNode("circle", {
                  cx: n.x,
                  cy: n.y,
                  r: nodeRadius.value,
                  fill: n.color ?? arcColors.value[0],
                  stroke: "var(--grafana-input-bg)",
                  "stroke-width": selected.value?.id === n.id ? 0.8 : 0.3
                }, null, 8, _hoisted_5$U),
                createElementVNode("text", {
                  x: n.x,
                  y: n.y + nodeRadius.value + 4,
                  "text-anchor": "middle",
                  class: "label"
                }, toDisplayString(n.label), 9, _hoisted_6$N),
                n.mainStat != null ? (openBlock(), createElementBlock("text", {
                  key: 0,
                  x: n.x,
                  y: n.y + 1.5,
                  "text-anchor": "middle",
                  class: "stat"
                }, toDisplayString(n.mainStat) + toDisplayString(showUnits.value && mainStatUnit.value ? mainStatUnit.value : ""), 9, _hoisted_7$L)) : createCommentVNode("v-if", true)
              ], 10, _hoisted_4$10);
            }),
            128
            /* KEYED_FRAGMENT */
          )) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        menu.value ? (openBlock(), createElementBlock(
          "div",
          {
            key: 2,
            class: "ctx",
            "data-testid": "nodegraph-context-menu",
            style: normalizeStyle({ left: menu.value.x + "px", top: menu.value.y + "px" }),
            onClick: _cache[2] || (_cache[2] = withModifiers(() => {
            }, ["stop"]))
          },
          [
            createElementVNode(
              "div",
              _hoisted_8$D,
              toDisplayString(menu.value.node.label),
              1
              /* TEXT */
            ),
            createElementVNode("button", {
              type: "button",
              "data-testid": "nodegraph-focus",
              onClick: _cache[0] || (_cache[0] = ($event) => menu.value = null)
            }, " 聚焦节点 "),
            createElementVNode("button", {
              type: "button",
              onClick: _cache[1] || (_cache[1] = ($event) => {
                selected.value = menu.value.node;
                menu.value = null;
              })
            }, " 查看详情 "),
            menu.value.node.mainStat != null ? (openBlock(), createElementBlock(
              "div",
              _hoisted_9$B,
              " 主指标: " + toDisplayString(menu.value.node.mainStat),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true)
          ],
          4
          /* STYLE */
        )) : createCommentVNode("v-if", true),
        selected.value ? (openBlock(), createElementBlock("aside", _hoisted_10$v, [
          createElementVNode(
            "strong",
            null,
            toDisplayString(selected.value.label),
            1
            /* TEXT */
          ),
          createElementVNode(
            "div",
            null,
            "ID: " + toDisplayString(selected.value.id),
            1
            /* TEXT */
          ),
          selected.value.mainStat != null ? (openBlock(), createElementBlock(
            "div",
            _hoisted_11$q,
            " 主指标: " + toDisplayString(selected.value.mainStat) + toDisplayString(mainStatUnit.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          selected.value.secondaryStat != null ? (openBlock(), createElementBlock(
            "div",
            _hoisted_12$k,
            " 次指标: " + toDisplayString(selected.value.secondaryStat) + toDisplayString(secondaryStatUnit.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          createElementVNode("button", {
            type: "button",
            onClick: _cache[3] || (_cache[3] = ($event) => selected.value = null)
          }, "关闭")
        ])) : createCommentVNode("v-if", true),
        createCommentVNode(" series empty → panel-empty; series present but not topology → noDataMsg + zoom chrome "),
        !graph.value.nodes.length && !hasSeries.value ? (openBlock(), createElementBlock("div", _hoisted_13$k, [..._cache[4] || (_cache[4] = [
          createElementVNode(
            "p",
            { class: "panel-empty__msg" },
            "回复中未找到数据",
            -1
            /* CACHED */
          )
        ])])) : !graph.value.nodes.length ? (openBlock(), createElementBlock("div", _hoisted_14$i, " 没有数据 ")) : createCommentVNode("v-if", true),
        _cache[5] || (_cache[5] = createStaticVNode('<div class="view-controls" data-testid="nodegraph-view-controls" aria-hidden="true" data-v-4ec607d6><div class="view-controls__btns" data-v-4ec607d6><button type="button" class="vc-btn" tabindex="-1" aria-label="Zoom in" data-v-4ec607d6><svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" data-v-4ec607d6><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" data-v-4ec607d6></circle><path d="M12 8v8M8 12h8" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" data-v-4ec607d6></path></svg></button><button type="button" class="vc-btn" tabindex="-1" aria-label="Zoom out" data-v-4ec607d6><svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" data-v-4ec607d6><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" data-v-4ec607d6></circle><path d="M8 12h8" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" data-v-4ec607d6></path></svg></button></div></div>', 1))
      ], 8, _hoisted_1$1M);
    };
  }
});
const NodeGraphRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2r, [["__scopeId", "data-v-4ec607d6"]]);
const _sfc_main$2q = /* @__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(NodeGraphRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "nodeGraph",
    name: "节点图",
    description: "服务拓扑 / 节点关系图",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2q
).setPanelOptions((builder) => {
  const cat = ["节点图"];
  builder.addSelect(
    {
      id: "zoomMode",
      path: "zoomMode",
      name: "缩放模式",
      category: cat,
      settings: {
        options: [
          {
            label: "协作",
            value: "cooperative",
            description: "允许页面正常滚动"
          },
          {
            label: "独占",
            value: "greedy",
            description: "响应全部缩放手势"
          }
        ]
      }
    },
    "cooperative"
  ).addSelect(
    {
      id: "layoutAlgorithm",
      path: "layoutAlgorithm",
      name: "布局算法",
      category: cat,
      settings: {
        options: [
          { label: "分层", value: "layered" },
          { label: "力导向", value: "force" },
          { label: "网格", value: "grid" },
          { label: "环形", value: "circular" }
        ]
      }
    },
    "layered"
  ).addUnit(
    {
      id: "nodes.mainStatUnit",
      path: "nodes.mainStatUnit",
      name: "节点主统计单位",
      category: ["节点"]
    },
    ""
  ).addUnit(
    {
      id: "nodes.secondaryStatUnit",
      path: "nodes.secondaryStatUnit",
      name: "节点次统计单位",
      category: ["节点"]
    },
    ""
  ).addTextArea(
    {
      id: "nodes.arcs",
      path: "nodes.arcs",
      name: "弧段",
      description: 'JSON 数组，如 [{"color":"#f00","field":"error"}]',
      category: ["节点"]
    },
    "[]"
  ).addUnit(
    {
      id: "edges.mainStatUnit",
      path: "edges.mainStatUnit",
      name: "边主统计单位",
      category: ["边"]
    },
    ""
  ).addUnit(
    {
      id: "edges.secondaryStatUnit",
      path: "edges.secondaryStatUnit",
      name: "边次统计单位",
      category: ["边"]
    },
    ""
  ).addCustom({
    id: "nodes",
    path: "nodes",
    name: "节点配置",
    category: cat,
    editor: "text"
  }).addCustom({
    id: "edges",
    path: "edges",
    name: "边配置",
    category: cat,
    editor: "text"
  }).addUnit(
    {
      id: "mainStatUnit",
      path: "mainStatUnit",
      name: "主统计单位（兼容）",
      category: cat
    },
    void 0
  ).addUnit(
    {
      id: "secondaryStatUnit",
      path: "secondaryStatUnit",
      name: "次统计单位（兼容）",
      category: cat
    },
    void 0
  ).addText(
    {
      id: "arcs",
      path: "arcs",
      name: "弧（兼容）",
      category: cat
    },
    void 0
  );
}).setRuntimeConsumedPaths([
  "zoomMode",
  "layoutAlgorithm",
  "nodes.mainStatUnit",
  "nodes.secondaryStatUnit",
  "nodes.arcs",
  "edges.mainStatUnit",
  "edges.secondaryStatUnit",
  "mainStatUnit",
  "secondaryStatUnit",
  "arcs",
  "nodes",
  "edges"
]).register();
const _hoisted_1$1L = {
  class: "panel-content-only",
  "data-testid": "panel-content-only",
  "data-panel-type": "xychart"
};
const _hoisted_2$1l = ["data-x-field", "data-dims-x", "data-dims-frame", "data-dims-y", "data-fill-opacity", "data-point-size-fixed", "data-point-size", "data-point-size-min", "data-point-size-max", "data-point-shape", "data-point-symbol", "data-exclude-series", "data-show-lines", "data-line-width", "data-show", "data-legend", "data-legend-display-mode", "data-legend-placement", "data-tooltip-mode", "data-tooltip-sort", "data-line-style", "data-point-stroke-width", "data-mapping", "data-series-count"];
const _hoisted_3$1a = { class: "chart-box" };
const _hoisted_4$$ = {
  key: 0,
  class: "legend",
  "data-testid": "xychart-legend",
  "data-shared-legend": "viz-legend"
};
const _hoisted_5$T = { class: "name" };
const _sfc_main$2p = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    useCssVars((_ctx) => ({
      "v2ffda548": chartHeightCss.value
    }));
    const props = __props;
    const el = ref(null);
    const opts = computed(() => props.options ?? {});
    const custom = computed(
      () => props.fieldConfig?.defaults?.custom ?? {}
    );
    function merged(key, fallback) {
      const o = opts.value[key];
      if (o !== void 0 && o !== null && o !== "") return o;
      const c = custom.value[key];
      if (c !== void 0 && c !== null && c !== "") return c;
      return fallback;
    }
    function resolveFieldName(spec) {
      if (spec == null) return "";
      if (typeof spec === "string") return spec;
      const s = spec;
      if (s.fixed != null) return String(s.fixed);
      if (s.matcher?.options != null) return String(s.matcher.options);
      if (s.options != null) return String(s.options);
      return "";
    }
    const prep = computed(() => {
      const frames = props.data?.series ?? [];
      if (!frames.length) {
        return {
          warn: "无数据",
          series: []
        };
      }
      const mapping = String(opts.value.mapping ?? "auto");
      const mappedSeries = Array.isArray(opts.value.series) && opts.value.series.length ? opts.value.series : [{}];
      const dims = opts.value.dims ?? {};
      const legacyX = opts.value.xField ? String(opts.value.xField) : dims.x ? String(dims.x) : "";
      const out = [];
      let seriesIndex = 0;
      const fillOpacity = Number(merged("fillOpacity", 50));
      const pointSizeRaw = merged("pointSize", 5);
      const pointSizeObj = typeof pointSizeRaw === "object" && pointSizeRaw ? pointSizeRaw : null;
      const pointSize = Number(
        pointSizeObj ? pointSizeObj.fixed ?? pointSizeObj.min ?? 5 : pointSizeRaw ?? 5
      );
      const pointSizeMin = pointSizeObj?.min != null ? Number(pointSizeObj.min) : void 0;
      const pointSizeMax = pointSizeObj?.max != null ? Number(pointSizeObj.max) : void 0;
      const pointSymbol = String(
        merged("pointSymbol", opts.value.pointSymbol ?? "circle")
      );
      const excludeSeries = new Set(
        (Array.isArray(opts.value.excludeSeries) ? opts.value.excludeSeries : String(opts.value.excludeSeries || "").split(/[,\s]+/).filter(Boolean)).map(String)
      );
      const showMode = String(merged("show", "points"));
      const showLines = showMode === "lines" || showMode === "points+lines" || opts.value.showLines === true;
      const lineWidth = showLines ? Number(merged("lineWidth", 1)) : 0;
      const dimsFrame = dims.frame != null && dims.frame !== "" ? Number(dims.frame) : null;
      for (const seriesCfg of mappedSeries) {
        if (mapping === "manual") {
          const hasX = resolveFieldName(seriesCfg?.x) || seriesCfg?.x?.matcher;
          const hasY = resolveFieldName(seriesCfg?.y) || seriesCfg?.y?.matcher;
          if (!hasX || !hasY) continue;
        }
        for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
          const frame = frames[frameIndex];
          if (dimsFrame != null && Number.isFinite(dimsFrame) && frameIndex !== dimsFrame) continue;
          const onlyNum = frame.fields.filter((f) => f.type === "number");
          if (!onlyNum.length) continue;
          const xName = resolveFieldName(seriesCfg?.x) || legacyX;
          let xField = xName ? onlyNum.find((f) => f.name === xName) : onlyNum[0];
          if (!xField) xField = onlyNum[0];
          if (!xField) continue;
          const yWanted = resolveFieldName(seriesCfg?.y);
          for (const yField of onlyNum) {
            if (yField === xField) continue;
            if (yWanted && yField.name !== yWanted) continue;
            if (mapping === "manual" && !yWanted) continue;
            const seriesLabel = getFieldDisplayName(yField, frame, frames);
            if (excludeSeries.has(yField.name) || excludeSeries.has(seriesLabel) || excludeSeries.has(String(seriesIndex))) {
              continue;
            }
            const cfg = {
              ...yField.config ?? {},
              ...props.fieldConfig?.defaults ?? {}
            };
            const color = seriesCfg?.pointColor && String(seriesCfg.pointColor) || getFieldSeriesColor(String(yField.name || "series"), seriesIndex, {
              ...cfg,
              color: cfg.color ?? { mode: "palette-classic" }
            }) || getFieldColor(
              Number(yField.values[yField.values.length - 1] ?? 0),
              cfg
            ) || classicGreen();
            const label = seriesCfg?.name && String(seriesCfg.name) ? String(seriesCfg.name) : getFieldDisplayName(yField, frame, frames);
            let size = pointSize;
            if (pointSizeMin != null && pointSizeMax != null) {
              const vals = yField.values.map((v) => Math.abs(Number(v))).filter((n) => Number.isFinite(n));
              const vmin = vals.length ? Math.min(...vals) : 0;
              const vmax = vals.length ? Math.max(...vals) : 1;
              const span = vmax - vmin || 1;
              const last = Math.abs(
                Number(yField.values[yField.values.length - 1] ?? 0)
              );
              const t2 = (last - vmin) / span;
              size = pointSizeMin + t2 * (pointSizeMax - pointSizeMin);
            }
            out.push({
              label,
              color: String(color),
              points: yField.values.map((y, row) => ({
                x: Number(xField.values[row] ?? row),
                y: y == null ? null : Number(y)
              })),
              fillOpacity: showLines ? fillOpacity : 0,
              lineWidth,
              pointSize: size,
              pointStrokeWidth: Number(merged("pointStrokeWidth", opts.value.pointStrokeWidth ?? 1)),
              lineStyle: merged("lineStyle", opts.value.lineStyle),
              pointShape: String(
                merged("pointShape", pointSymbol === "square" ? "square" : "circle")
              ),
              showPoints: "always",
              lineInterpolation: String(merged("lineInterpolation", "linear"))
            });
            seriesIndex++;
            if (mapping === "manual") break;
          }
        }
      }
      if (!out.length) {
        return {
          warn: "无数据",
          series: []
        };
      }
      return { warn: void 0, series: out };
    });
    const showError = computed(() => {
      if (props.data?.state === "Loading") return false;
      return Boolean(prep.value.warn) || !prep.value.series.length;
    });
    const series = computed(() => showError.value ? [] : prep.value.series);
    const width2 = computed(() => props.width || 400);
    const height2 = computed(() => {
      const place = String(opts.value?.legend?.placement ?? "bottom");
      const show = opts.value?.legend?.showLegend !== false && series.value.length > 0;
      const reserve = show && place === "bottom" ? 32 : 0;
      return Math.max((props.height || 200) - reserve, 40);
    });
    const chartHeightCss = computed(() => `${height2.value}px`);
    const xFieldAttr = computed(() => {
      if (opts.value.xField) return String(opts.value.xField);
      const series0 = opts.value.series?.[0];
      const n = resolveFieldName(series0?.x);
      if (n) return n;
      const frames = props.data?.series ?? [];
      const nums = frames[0]?.fields?.filter((f) => f.type === "number") ?? [];
      return nums[0]?.name ?? "";
    });
    const pointSizeAttr = computed(() => {
      const raw = merged("pointSize", 5);
      if (typeof raw === "object" && raw) return String(raw.fixed ?? 5);
      return String(raw ?? 5);
    });
    const pointShapeAttr = computed(
      () => String(
        merged(
          "pointShape",
          opts.value.pointSymbol === "square" || merged("pointSymbol") === "square" ? "square" : "circle"
        )
      )
    );
    const pointSymbolAttr = computed(
      () => String(merged("pointSymbol", opts.value.pointSymbol ?? pointShapeAttr.value))
    );
    const excludeSeriesAttr = computed(() => {
      const ex = opts.value.excludeSeries;
      if (Array.isArray(ex)) return ex.join(",");
      return String(ex ?? "");
    });
    const pointSizeMinAttr = computed(() => {
      const raw = merged("pointSize", 5);
      if (typeof raw === "object" && raw && raw.min != null)
        return String(raw.min);
      return "";
    });
    const pointSizeMaxAttr = computed(() => {
      const raw = merged("pointSize", 5);
      if (typeof raw === "object" && raw && raw.max != null)
        return String(raw.max);
      return "";
    });
    const showLinesAttr = computed(() => {
      const show = String(merged("show", "points"));
      return String(
        show === "lines" || show === "points+lines" || opts.value.showLines === true
      );
    });
    const lineWidthAttr = computed(
      () => String(merged("lineWidth", showLinesAttr.value === "true" ? 1 : 0))
    );
    const showModeAttr = computed(() => String(merged("show", "points")));
    const legendAttr = computed(
      () => String(opts.value?.legend?.showLegend !== false)
    );
    const mappingAttr = computed(() => String(opts.value.mapping ?? "auto"));
    const seriesCountAttr = computed(() => String(series.value.length));
    const pointStrokeWidthAttr = computed(
      () => String(merged("pointStrokeWidth", opts.value.pointStrokeWidth ?? 1))
    );
    const lineStyleAttr = computed(() => {
      const ls = merged("lineStyle", opts.value.lineStyle);
      if (ls == null) return "";
      if (typeof ls === "string") return ls;
      if (typeof ls === "object") {
        const o = ls;
        return String(o.fill ?? o.dash?.join?.(",") ?? JSON.stringify(ls));
      }
      return String(ls);
    });
    const legendDisplayModeAttr = computed(
      () => String(opts.value?.legend?.displayMode ?? "list")
    );
    const legendPlacementAttr = computed(
      () => String(opts.value?.legend?.placement ?? "bottom")
    );
    const tooltipModeAttr = computed(
      () => String(opts.value?.tooltip?.mode ?? "single")
    );
    const tooltipSortAttr = computed(
      () => String(opts.value?.tooltip?.sort ?? "none")
    );
    useUPlot(el, series, {
      width: width2,
      height: height2,
      mode: computed(() => {
        const show = String(merged("show", "points"));
        if (show === "lines" || show === "points+lines" || opts.value.showLines === true) {
          return Number(merged("fillOpacity", 0)) > 0 ? "area" : "line";
        }
        return "points";
      }),
      timeX: false,
      showLegend: false,
      lineInterpolation: computed(
        () => String(merged("lineInterpolation", "linear"))
      )
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1L, [
        showError.value ? (openBlock(), createBlock(PanelDataErrorView, {
          key: 0,
          data: __props.data,
          "field-config": __props.fieldConfig,
          message: prep.value.warn || "无数据"
        }, null, 8, ["data", "field-config", "message"])) : (openBlock(), createElementBlock("div", {
          key: 1,
          class: "chart-wrap",
          "data-testid": "xychart-panel",
          "data-x-field": xFieldAttr.value,
          "data-dims-x": String(opts.value.dims?.x ?? opts.value.xField ?? xFieldAttr.value),
          "data-dims-frame": String(opts.value.dims?.frame ?? ""),
          "data-dims-y": String(opts.value.dims?.y ?? ""),
          "data-fill-opacity": String(merged("fillOpacity", 50)),
          "data-point-size-fixed": pointSizeAttr.value,
          "data-point-size": pointSizeAttr.value,
          "data-point-size-min": pointSizeMinAttr.value,
          "data-point-size-max": pointSizeMaxAttr.value,
          "data-point-shape": pointShapeAttr.value,
          "data-point-symbol": pointSymbolAttr.value,
          "data-exclude-series": excludeSeriesAttr.value,
          "data-show-lines": showLinesAttr.value,
          "data-line-width": lineWidthAttr.value,
          "data-show": showModeAttr.value,
          "data-legend": legendAttr.value,
          "data-legend-display-mode": legendDisplayModeAttr.value,
          "data-legend-placement": legendPlacementAttr.value,
          "data-tooltip-mode": tooltipModeAttr.value,
          "data-tooltip-sort": tooltipSortAttr.value,
          "data-line-style": lineStyleAttr.value,
          "data-point-stroke-width": pointStrokeWidthAttr.value,
          "data-mapping": mappingAttr.value,
          "data-series-count": seriesCountAttr.value
        }, [
          createElementVNode("div", _hoisted_3$1a, [
            createElementVNode(
              "div",
              {
                ref_key: "el",
                ref: el,
                class: "chart",
                "data-testid": "panel-uplot",
                role: "img",
                "aria-label": "XY 图"
              },
              null,
              512
              /* NEED_PATCH */
            )
          ]),
          legendAttr.value === "true" && series.value.length ? (openBlock(), createElementBlock("ul", _hoisted_4$$, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(series.value, (s) => {
                return openBlock(), createElementBlock("li", {
                  key: s.label
                }, [
                  createElementVNode(
                    "i",
                    {
                      class: "legend-swatch",
                      style: normalizeStyle({ background: s.color })
                    },
                    null,
                    4
                    /* STYLE */
                  ),
                  createElementVNode(
                    "span",
                    _hoisted_5$T,
                    toDisplayString(s.label),
                    1
                    /* TEXT */
                  )
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : createCommentVNode("v-if", true)
        ], 8, _hoisted_2$1l))
      ]);
    };
  }
});
const Panel$c = /* @__PURE__ */ _export_sfc(_sfc_main$2p, [["__scopeId", "data-v-ff9e0b7a"]]);
const _hoisted_1$1K = ["data-mapping"];
const _hoisted_2$1k = ["value"];
const _hoisted_3$19 = {
  key: 0,
  value: "0"
};
const _hoisted_4$_ = ["value"];
const _hoisted_5$S = ["value"];
const _hoisted_6$M = ["value"];
const _hoisted_7$K = ["value"];
const _hoisted_8$C = ["value"];
const _hoisted_9$A = {
  class: "series-list",
  "data-testid": "xy-series-list"
};
const _hoisted_10$u = ["data-testid", "onClick"];
const _hoisted_11$p = ["onClick"];
const _hoisted_12$j = {
  key: 0,
  class: "editor",
  "data-testid": "xy-series-form"
};
const _hoisted_13$j = ["value"];
const _hoisted_14$h = ["value"];
const _hoisted_15$d = {
  key: 0,
  value: "0"
};
const _hoisted_16$c = ["value"];
const _hoisted_17$b = ["value"];
const _hoisted_18$b = ["value"];
const _hoisted_19$b = ["value"];
const _hoisted_20$a = ["value"];
const _hoisted_21$9 = ["value"];
const _hoisted_22$8 = ["value"];
const _hoisted_23$6 = ["value"];
const _hoisted_24$6 = ["value"];
const _hoisted_25$6 = ["value"];
const _sfc_main$2o = /* @__PURE__ */ defineComponent({
  __name: "XYSeriesEditor",
  props: {
    mapping: {},
    series: {},
    dims: {},
    frames: {}
  },
  emits: ["change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const selectedIdx = ref(0);
    function parseSeries(raw) {
      if (Array.isArray(raw)) return raw;
      if (typeof raw === "string" && raw.trim()) {
        try {
          const p = JSON.parse(raw);
          return Array.isArray(p) ? p : [];
        } catch {
          return [];
        }
      }
      return [];
    }
    const list = computed(() => {
      const s = parseSeries(props.series);
      if (props.mapping === "manual" && !s.length) {
        return [{ frame: { matcher: { id: "byIndex", options: 0 } } }];
      }
      return s;
    });
    watch(
      () => props.mapping,
      (m, prev) => {
        if (prev != null && m !== prev && m === "manual" && !parseSeries(props.series).length) {
          emit("change", {
            series: [{ frame: { matcher: { id: "byIndex", options: 0 } } }]
          });
          selectedIdx.value = 0;
        }
      }
    );
    const frames = computed(() => props.frames ?? []);
    const current = computed(() => list.value[selectedIdx.value] ?? null);
    function frameIndexOf(s) {
      const o = s.frame?.matcher?.options;
      const n = Number(o ?? 0);
      return Number.isFinite(n) ? n : 0;
    }
    function fieldName(spec) {
      if (spec == null) return "";
      if (typeof spec === "string") return spec;
      if (spec.fixed != null) return String(spec.fixed);
      if (spec.matcher?.options != null) return String(spec.matcher.options);
      return "";
    }
    function fieldsOf(frameIdx, types) {
      const f = frames.value[frameIdx] ?? frames.value[0];
      if (!f) return [];
      return f.fields.filter((fld) => !types || types.includes(fld.type)).map((fld) => fld.name);
    }
    function seriesLabel(s, i) {
      if (typeof s.name === "string" && s.name) return s.name;
      if (s.name && typeof s.name === "object" && s.name.fixed) return s.name.fixed;
      const y = fieldName(s.y);
      return y || `序列 ${i + 1}`;
    }
    function commit(next) {
      emit("change", { series: next });
    }
    function addSeries() {
      const next = [
        ...list.value,
        { frame: { matcher: { id: "byIndex", options: 0 } } }
      ];
      commit(next);
      selectedIdx.value = next.length - 1;
    }
    function deleteSeries(i) {
      const next = list.value.filter((_, idx) => idx !== i);
      commit(
        next.length ? next : [{ frame: { matcher: { id: "byIndex", options: 0 } } }]
      );
      selectedIdx.value = 0;
    }
    function patchCurrent(partial) {
      const next = list.value.map(
        (s, i) => i === selectedIdx.value ? { ...s, ...partial } : s
      );
      commit(next);
    }
    function setName(fixed) {
      patchCurrent({ name: fixed ? { fixed } : void 0 });
    }
    function setFrame(idx) {
      patchCurrent({ frame: { matcher: { id: "byIndex", options: idx } } });
    }
    function setField(key, name) {
      if (!name) {
        patchCurrent({ [key]: void 0 });
        return;
      }
      patchCurrent({ [key]: { matcher: { id: "byName", options: name } } });
    }
    function setColorField(name) {
      if (!name) {
        patchCurrent({ color: void 0 });
        return;
      }
      patchCurrent({ color: { matcher: { id: "byName", options: name } } });
    }
    function setPointColor(hex) {
      patchCurrent({
        pointColor: hex || void 0,
        color: hex ? { fixed: hex } : void 0
      });
    }
    function setDims(partial) {
      emit("change", { dims: { ...props.dims ?? {}, ...partial } });
    }
    const curFrameIdx = computed(
      () => current.value ? frameIndexOf(current.value) : Number(props.dims?.frame ?? 0)
    );
    const numberFields = computed(() => fieldsOf(curFrameIdx.value, ["number"]));
    const allFields = computed(() => fieldsOf(curFrameIdx.value));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "xy-series-editor",
        "data-testid": "xy-series-editor",
        "data-mapping": String(__props.mapping ?? "auto")
      }, [
        createCommentVNode(" Auto: dims "),
        __props.mapping !== "manual" ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            _cache[15] || (_cache[15] = createElementVNode(
              "header",
              { class: "head" },
              "自动映射 · 维度",
              -1
              /* CACHED */
            )),
            createElementVNode("label", null, [
              _cache[10] || (_cache[10] = createTextVNode(
                " 数据帧 ",
                -1
                /* CACHED */
              )),
              createElementVNode("select", {
                "data-testid": "xy-dims-frame",
                value: String(__props.dims?.frame ?? 0),
                onChange: _cache[0] || (_cache[0] = ($event) => setDims({
                  frame: Number($event.target.value)
                }))
              }, [
                !frames.value.length ? (openBlock(), createElementBlock("option", _hoisted_3$19, "帧 0")) : createCommentVNode("v-if", true),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(frames.value, (f, i) => {
                    return openBlock(), createElementBlock("option", {
                      key: i,
                      value: String(i)
                    }, toDisplayString(f.name || `帧 ${i}`) + " (" + toDisplayString(f.length) + " 行) ", 9, _hoisted_4$_);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ], 40, _hoisted_2$1k)
            ]),
            createElementVNode("label", null, [
              _cache[12] || (_cache[12] = createTextVNode(
                " X 字段 ",
                -1
                /* CACHED */
              )),
              createElementVNode("select", {
                "data-testid": "xy-dims-x",
                value: __props.dims?.x ?? "",
                onChange: _cache[1] || (_cache[1] = ($event) => setDims({ x: $event.target.value }))
              }, [
                _cache[11] || (_cache[11] = createElementVNode(
                  "option",
                  { value: "" },
                  "自动",
                  -1
                  /* CACHED */
                )),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(fieldsOf(Number(__props.dims?.frame ?? 0), ["number"]), (n) => {
                    return openBlock(), createElementBlock("option", {
                      key: n,
                      value: n
                    }, toDisplayString(n), 9, _hoisted_6$M);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ], 40, _hoisted_5$S)
            ]),
            createElementVNode("label", null, [
              _cache[14] || (_cache[14] = createTextVNode(
                " Y 字段 ",
                -1
                /* CACHED */
              )),
              createElementVNode("select", {
                "data-testid": "xy-dims-y",
                value: __props.dims?.y ?? "",
                onChange: _cache[2] || (_cache[2] = ($event) => setDims({ y: $event.target.value }))
              }, [
                _cache[13] || (_cache[13] = createElementVNode(
                  "option",
                  { value: "" },
                  "全部数值字段",
                  -1
                  /* CACHED */
                )),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(fieldsOf(Number(__props.dims?.frame ?? 0), ["number"]), (n) => {
                    return openBlock(), createElementBlock("option", {
                      key: n,
                      value: n
                    }, toDisplayString(n), 9, _hoisted_8$C);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ], 40, _hoisted_7$K)
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" Manual: series list + field pickers "),
            createElementVNode("header", { class: "head" }, [
              _cache[16] || (_cache[16] = createTextVNode(
                " 手动序列 ",
                -1
                /* CACHED */
              )),
              createElementVNode("button", {
                type: "button",
                "data-testid": "xy-add-series",
                class: "btn",
                onClick: addSeries
              }, " + 添加序列 ")
            ]),
            createElementVNode("ul", _hoisted_9$A, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(list.value, (s, i) => {
                  return openBlock(), createElementBlock("li", {
                    key: i,
                    class: normalizeClass(["series-row", { sel: i === selectedIdx.value }]),
                    "data-testid": `xy-series-${i}`,
                    onClick: ($event) => selectedIdx.value = i
                  }, [
                    createElementVNode(
                      "span",
                      null,
                      toDisplayString(seriesLabel(s, i)),
                      1
                      /* TEXT */
                    ),
                    createElementVNode("button", {
                      type: "button",
                      "data-testid": "xy-del-series",
                      class: "icon",
                      title: "删除",
                      onClick: withModifiers(($event) => deleteSeries(i), ["stop"])
                    }, " × ", 8, _hoisted_11$p)
                  ], 10, _hoisted_10$u);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ]),
            current.value ? (openBlock(), createElementBlock("div", _hoisted_12$j, [
              createElementVNode("label", null, [
                _cache[17] || (_cache[17] = createTextVNode(
                  " 名称 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("input", {
                  "data-testid": "xy-series-name",
                  value: seriesLabel(current.value, selectedIdx.value).startsWith("序列 ") ? "" : seriesLabel(current.value, selectedIdx.value),
                  placeholder: "序列名称",
                  onChange: _cache[3] || (_cache[3] = ($event) => setName($event.target.value))
                }, null, 40, _hoisted_13$j)
              ]),
              createElementVNode("label", null, [
                _cache[18] || (_cache[18] = createTextVNode(
                  " 数据帧 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("select", {
                  "data-testid": "xy-series-frame",
                  value: String(frameIndexOf(current.value)),
                  onChange: _cache[4] || (_cache[4] = ($event) => setFrame(Number($event.target.value)))
                }, [
                  !frames.value.length ? (openBlock(), createElementBlock("option", _hoisted_15$d, "帧 0")) : createCommentVNode("v-if", true),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(frames.value, (f, i) => {
                      return openBlock(), createElementBlock("option", {
                        key: i,
                        value: String(i)
                      }, toDisplayString(f.name || `帧 ${i}`), 9, _hoisted_16$c);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 40, _hoisted_14$h)
              ]),
              createElementVNode("label", null, [
                _cache[20] || (_cache[20] = createTextVNode(
                  " X 字段 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("select", {
                  "data-testid": "xy-series-x",
                  value: fieldName(current.value.x),
                  onChange: _cache[5] || (_cache[5] = ($event) => setField("x", $event.target.value))
                }, [
                  _cache[19] || (_cache[19] = createElementVNode(
                    "option",
                    { value: "" },
                    "选择字段",
                    -1
                    /* CACHED */
                  )),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(numberFields.value, (n) => {
                      return openBlock(), createElementBlock("option", {
                        key: "x" + n,
                        value: n
                      }, toDisplayString(n), 9, _hoisted_18$b);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 40, _hoisted_17$b)
              ]),
              createElementVNode("label", null, [
                _cache[22] || (_cache[22] = createTextVNode(
                  " Y 字段 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("select", {
                  "data-testid": "xy-series-y",
                  value: fieldName(current.value.y),
                  onChange: _cache[6] || (_cache[6] = ($event) => setField("y", $event.target.value))
                }, [
                  _cache[21] || (_cache[21] = createElementVNode(
                    "option",
                    { value: "" },
                    "选择字段",
                    -1
                    /* CACHED */
                  )),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(numberFields.value, (n) => {
                      return openBlock(), createElementBlock("option", {
                        key: "y" + n,
                        value: n
                      }, toDisplayString(n), 9, _hoisted_20$a);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 40, _hoisted_19$b)
              ]),
              createElementVNode("label", null, [
                _cache[24] || (_cache[24] = createTextVNode(
                  " 颜色字段 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("select", {
                  "data-testid": "xy-series-color-field",
                  value: fieldName(current.value.color),
                  onChange: _cache[7] || (_cache[7] = ($event) => setColorField($event.target.value))
                }, [
                  _cache[23] || (_cache[23] = createElementVNode(
                    "option",
                    { value: "" },
                    "固定色 / 无",
                    -1
                    /* CACHED */
                  )),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(allFields.value, (n) => {
                      return openBlock(), createElementBlock("option", {
                        key: "c" + n,
                        value: n
                      }, toDisplayString(n), 9, _hoisted_22$8);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 40, _hoisted_21$9)
              ]),
              createElementVNode("label", null, [
                _cache[25] || (_cache[25] = createTextVNode(
                  " 固定点颜色 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("input", {
                  "data-testid": "xy-series-point-color",
                  type: "color",
                  value: current.value.pointColor || current.value.color?.fixed || "var(--grafana-primary)",
                  onInput: _cache[8] || (_cache[8] = ($event) => setPointColor($event.target.value))
                }, null, 40, _hoisted_23$6)
              ]),
              createElementVNode("label", null, [
                _cache[27] || (_cache[27] = createTextVNode(
                  " 大小字段 ",
                  -1
                  /* CACHED */
                )),
                createElementVNode("select", {
                  "data-testid": "xy-series-size",
                  value: fieldName(current.value.size),
                  onChange: _cache[9] || (_cache[9] = ($event) => setField("size", $event.target.value))
                }, [
                  _cache[26] || (_cache[26] = createElementVNode(
                    "option",
                    { value: "" },
                    "固定大小",
                    -1
                    /* CACHED */
                  )),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(numberFields.value, (n) => {
                      return openBlock(), createElementBlock("option", {
                        key: "s" + n,
                        value: n
                      }, toDisplayString(n), 9, _hoisted_25$6);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ], 40, _hoisted_24$6)
              ])
            ])) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 8, _hoisted_1$1K);
    };
  }
});
const XYSeriesEditor = /* @__PURE__ */ _export_sfc(_sfc_main$2o, [["__scopeId", "data-v-17e3cd9c"]]);
new VuePanelPlugin(
  {
    id: "xychart",
    name: "XY 图",
    description: "XY / 散点图",
    state: "stable",
    skipDataQuery: false
  },
  Panel$c
).useFieldConfig({
  useCustomConfig: (builder) => {
    const category = ["XY 图"];
    builder.addRadio(
      {
        id: "show",
        path: "show",
        name: "显示",
        category,
        settings: {
          options: [
            { label: "点", value: "points" },
            { label: "线", value: "lines" },
            { label: "点+线", value: "points+lines" }
          ]
        }
      },
      "points"
    ).addSlider(
      {
        id: "pointSize.fixed",
        path: "pointSize.fixed",
        name: "点大小",
        category,
        settings: { min: 1, max: 100, step: 1 },
        showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
      },
      5
    ).addNumber({
      id: "pointSize.min",
      path: "pointSize.min",
      name: "最小",
      category,
      showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
    }).addNumber({
      id: "pointSize.max",
      path: "pointSize.max",
      name: "最大",
      category,
      showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
    }).addRadio(
      {
        id: "pointShape",
        path: "pointShape",
        name: "点形状",
        category,
        settings: {
          options: [
            { label: "圆形", value: "circle" },
            { label: "方形", value: "square" }
          ]
        },
        showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
      },
      "circle"
    ).addSlider(
      {
        id: "pointStrokeWidth",
        path: "pointStrokeWidth",
        name: "点描边宽度",
        category,
        settings: { min: 0, max: 10, step: 1 },
        showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
      },
      1
    ).addSlider(
      {
        id: "fillOpacity",
        path: "fillOpacity",
        name: "填充透明度",
        category,
        settings: { min: 0, max: 100, step: 1 },
        showIf: (c) => (c.show ?? c.custom?.show) !== "lines"
      },
      50
    ).addText({
      id: "lineStyle",
      path: "lineStyle",
      name: "线样式",
      category,
      showIf: (c) => (c.show ?? c.custom?.show) !== "points"
    }).addSlider(
      {
        id: "lineWidth",
        path: "lineWidth",
        name: "线宽",
        category,
        settings: { min: 0, max: 10, step: 1 },
        showIf: (c) => (c.show ?? c.custom?.show) !== "points"
      },
      1
    ).addText({
      id: "pointSymbol",
      path: "pointSymbol",
      name: "点符号（兼容）",
      category,
      showIf: () => false
    });
  }
}).setPanelOptions((builder) => {
  const category = ["XY 图"];
  builder.addRadio(
    {
      id: "mapping",
      path: "mapping",
      name: "序列映射",
      category,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "手动", value: "manual" }
        ]
      }
    },
    "auto"
  ).addNumber(
    {
      id: "dims.frame",
      path: "dims.frame",
      name: "数据帧索引",
      category,
      settings: { min: 0, step: 1 },
      showIf: () => false
      // SeriesEditor,
    },
    0
  ).addText({
    id: "dims.x",
    path: "dims.x",
    name: "X 字段",
    category,
    showIf: () => false
    // SeriesEditor,
  }).addText({
    id: "dims.y",
    path: "dims.y",
    name: "Y 字段",
    category,
    showIf: () => false
    // SeriesEditor,
  }).addCustom(
    {
      id: "series",
      path: "series",
      name: "序列（SeriesEditor）",
      description: "由下方 SeriesEditor 编辑；兼容 JSON round-trip",
      category,
      editor: "textarea",
      showIf: () => false
      // UI via XYSeriesEditor in PanelEditor
    },
    []
  ).addText({
    id: "excludeSeries",
    path: "excludeSeries",
    name: "排除序列（逗号分隔）",
    category
  }).addRadio(
    {
      id: "show",
      path: "show",
      name: "显示（options 兼容）",
      category: ["XY 图 · 兼容"],
      settings: {
        options: [
          { label: "点", value: "points" },
          { label: "线", value: "lines" },
          { label: "点+线", value: "points+lines" }
        ]
      }
    },
    "points"
  ).addSlider(
    {
      id: "pointSize.fixed",
      path: "pointSize.fixed",
      name: "点大小（兼容）",
      category: ["XY 图 · 兼容"],
      settings: { min: 1, max: 100, step: 1 }
    },
    5
  ).addNumber({
    id: "pointSize.min",
    path: "pointSize.min",
    name: "最小点（兼容）",
    category: ["XY 图 · 兼容"]
  }).addNumber({
    id: "pointSize.max",
    path: "pointSize.max",
    name: "最大点（兼容）",
    category: ["XY 图 · 兼容"]
  }).addRadio(
    {
      id: "pointShape",
      path: "pointShape",
      name: "点形状（兼容）",
      category: ["XY 图 · 兼容"],
      settings: {
        options: [
          { label: "圆形", value: "circle" },
          { label: "方形", value: "square" }
        ]
      }
    },
    "circle"
  ).addSlider(
    {
      id: "pointStrokeWidth",
      path: "pointStrokeWidth",
      name: "点描边（兼容）",
      category: ["XY 图 · 兼容"],
      settings: { min: 0, max: 10 }
    },
    1
  ).addSlider(
    {
      id: "fillOpacity",
      path: "fillOpacity",
      name: "填充（兼容）",
      category: ["XY 图 · 兼容"],
      settings: { min: 0, max: 100 }
    },
    50
  ).addText({
    id: "lineStyle",
    path: "lineStyle",
    name: "线样式（兼容）",
    category: ["XY 图 · 兼容"]
  }).addSlider(
    {
      id: "lineWidth",
      path: "lineWidth",
      name: "线宽（兼容）",
      category: ["XY 图 · 兼容"],
      settings: { min: 0, max: 10 }
    },
    1
  ).addText({
    id: "pointSymbol",
    path: "pointSymbol",
    name: "点符号（兼容）",
    category: ["XY 图 · 兼容"]
  });
  addTooltipOptions(builder, true);
  addLegendOptions(builder, true, true);
}).setRuntimeConsumedPaths([
  "mapping",
  "series",
  "dims.frame",
  "dims.x",
  "dims.y",
  "excludeSeries",
  "show",
  "pointSize.fixed",
  "pointSize.min",
  "pointSize.max",
  "pointShape",
  "pointStrokeWidth",
  "fillOpacity",
  "lineStyle",
  "lineWidth",
  "pointSymbol",
  "legend.showLegend",
  "legend.displayMode",
  "legend.placement",
  "tooltip.mode",
  "tooltip.sort"
]).setOptionsEditor(XYSeriesEditor).register();
function resolveLineDash(lineStyle) {
  if (lineStyle == null) return void 0;
  const s = typeof lineStyle === "string" ? lineStyle : String(lineStyle?.fill ?? lineStyle?.style ?? "");
  const v = s.toLowerCase();
  if (v === "dashed" || v === "dash") return "6 4";
  if (v === "dotted" || v === "dot") return "2 3";
  return void 0;
}
function pickElementChrome(el) {
  const links = Array.isArray(el.links) ? el.links : el.links != null ? [el.links] : void 0;
  const actions = Array.isArray(el.actions) ? el.actions : el.actions != null && String(el.actions).trim() !== "" ? [el.actions] : void 0;
  const lineStyle = el.lineStyle ?? el.config?.lineStyle ?? void 0;
  return { links, actions, lineStyle };
}
function normalizeCanvasOptions(options = {}) {
  const root = options.root && typeof options.root === "object" ? options.root : void 0;
  const rawElements = (Array.isArray(options.elements) && options.elements.length ? options.elements : void 0) ?? (Array.isArray(root?.elements) ? root.elements : void 0);
  const elements = rawElements?.map((el, i) => {
    const n = normalizeElement(el, i);
    if (!n || !el || typeof el !== "object") return n;
    const chrome = pickElementChrome(el);
    return { ...n, ...chrome };
  }).filter((el) => el != null);
  const connections = collectConnections(options, elements ?? []);
  const selectedIds = Array.isArray(options.selectedIds) ? options.selectedIds.map(String) : typeof options.selectedId === "string" ? [options.selectedId] : void 0;
  const bgNested = options.background && typeof options.background === "object" ? options.background : null;
  const backgroundColor = typeof options.background === "string" ? options.background : typeof bgNested?.color === "string" ? bgNested.color : typeof options["background.color"] === "string" ? String(options["background.color"]) : "transparent";
  const backgroundImage = typeof bgNested?.image === "string" ? bgNested.image : typeof options["background.image"] === "string" ? String(options["background.image"]) : void 0;
  const backgroundSize = typeof bgNested?.size === "string" ? bgNested.size : typeof options["background.size"] === "string" ? String(options["background.size"]) : "cover";
  const borderNested = options.border && typeof options.border === "object" ? options.border : null;
  const borderColor = typeof borderNested?.color === "string" ? borderNested.color : typeof options["border.color"] === "string" ? String(options["border.color"]) : "";
  const borderWidth = borderNested?.width != null ? Number(borderNested.width) : options["border.width"] != null ? Number(options["border.width"]) : void 0;
  const panelColor = typeof options.color === "string" ? options.color : typeof options.color === "object" && options.color?.fixed ? String(options.color.fixed) : "";
  const normalizedElements = applyConstraints(elements ?? [], 100, 100);
  return {
    elements: normalizedElements,
    connections,
    background: backgroundColor,
    backgroundColor,
    backgroundImage,
    backgroundSize,
    borderColor,
    borderWidth,
    color: panelColor,
    inlineEditing: options.inlineEditing !== false,
    panZoom: Boolean(
      options.panZoom === true || String(options.panZoom) === "true" || Number(options.panZoom) === 1
    ),
    panZoomHelp: options.panZoomHelp !== false,
    zoomToContent: Boolean(options.zoomToContent),
    showAdvancedTypes: Boolean(options.showAdvancedTypes),
    tooltipMode: String(
      options.tooltip?.mode ?? options["tooltip.mode"] ?? "auto"
    ),
    tooltipDisableForOneClick: Boolean(
      options.tooltip?.disableForOneClick ?? options["tooltip.disableForOneClick"]
    ),
    root: root ?? { elements: normalizedElements },
    selectedId: selectedIds?.[selectedIds.length - 1],
    selectedIds
  };
}
function readPlacement(el) {
  const placement = el.placement && typeof el.placement === "object" ? el.placement : null;
  const x = num(el.x ?? placement?.left ?? placement?.x, 0);
  const y = num(el.y ?? placement?.top ?? placement?.y, 0);
  const w = num(el.w ?? el.width ?? placement?.width, NaN);
  const h2 = num(el.h ?? el.height ?? placement?.height, NaN);
  return { x, y, w, h: h2, placement };
}
function readElementText(el) {
  if (typeof el.text === "string") return el.text;
  const config2 = el.config && typeof el.config === "object" ? el.config : null;
  const textCfg = config2?.text;
  if (typeof textCfg === "string") return textCfg;
  if (textCfg && typeof textCfg === "object") {
    const fixed = textCfg.fixed;
    if (typeof fixed === "string") return fixed;
  }
  return void 0;
}
function normalizeElement(raw, index2) {
  if (!raw || typeof raw !== "object") return null;
  const el = raw;
  const typeRaw = String(el.type ?? "");
  const type = typeRaw === "metric-value" ? "metricValue" : typeRaw;
  const id = typeof el.id === "string" ? el.id : `el-${index2}`;
  const { x, y, w: placeW, h: placeH } = readPlacement(el);
  const fill = typeof el.fill === "string" ? el.fill : void 0;
  const name = typeof el.name === "string" ? el.name : void 0;
  const constraint = normalizeConstraint(el.constraint);
  const connections = Array.isArray(el.connections) ? el.connections.map((c, ci) => normalizeConnection(c, id, ci)).filter((c) => !!c) : void 0;
  const text = readElementText(el);
  switch (type) {
    case "rect":
      return {
        type: "rect",
        id,
        name,
        x,
        y,
        w: Number.isFinite(placeW) ? placeW : num(el.w ?? el.width, 10),
        h: Number.isFinite(placeH) ? placeH : num(el.h ?? el.height, 10),
        fill,
        text,
        constraint,
        connections
      };
    case "circle":
      return {
        type: "circle",
        id,
        name,
        x,
        y,
        r: num(el.r ?? el.radius, 5),
        fill,
        constraint,
        connections
      };
    case "text":
      return {
        type: "text",
        id,
        name,
        x,
        y,
        text: text ?? "",
        fill,
        fontSize: num(el.fontSize, 14),
        constraint,
        connections
      };
    case "metricValue":
    case "metric":
      return {
        type: "metric",
        id,
        name,
        x,
        y,
        w: Number.isFinite(placeW) ? placeW : num(el.w ?? el.width, 120),
        h: Number.isFinite(placeH) ? placeH : num(el.h ?? el.height, 40),
        field: typeof el.field === "string" ? el.field : void 0,
        fill,
        text,
        fontSize: num(el.fontSize, 20),
        constraint,
        connections
      };
    case "line":
      return {
        type: "line",
        id,
        name,
        x,
        y,
        x2: num(el.x2, x + 10),
        y2: num(el.y2, y + 10),
        stroke: typeof el.stroke === "string" ? el.stroke : classicColor(14),
        strokeWidth: num(el.strokeWidth, 0.8),
        constraint,
        connections
      };
    case "ellipse":
      return {
        type: "ellipse",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 14),
        h: num(el.h ?? el.height, 10),
        fill,
        constraint,
        connections
      };
    case "icon":
      return {
        type: "icon",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 8),
        h: num(el.h ?? el.height, 8),
        fill: fill ?? classicColor(14),
        icon: typeof el.icon === "string" ? el.icon : "cube",
        constraint,
        connections
      };
    case "server":
      return {
        type: "server",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 12),
        h: num(el.h ?? el.height, 16),
        fill: fill ?? classicBlue(),
        text: typeof el.text === "string" ? el.text : "Server",
        constraint,
        connections
      };
    case "button":
      return {
        type: "button",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 16),
        h: num(el.h ?? el.height, 8),
        fill: fill ?? classicBlue(),
        text: typeof el.text === "string" ? el.text : "Button",
        constraint,
        connections
      };
    case "drone":
      return {
        type: "drone",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 14),
        h: num(el.h ?? el.height, 10),
        fill: fill ?? classicBlue(),
        text: typeof el.text === "string" ? el.text : "Drone",
        constraint,
        connections
      };
    case "droneTop":
    case "droneFront":
    case "droneSide": {
      const view = type;
      return {
        type: view,
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 14),
        h: num(el.h ?? el.height, 10),
        fill: fill ?? classicBlue(),
        text: typeof el.text === "string" ? el.text : view,
        constraint,
        connections
      };
    }
    case "windTurbine":
    case "wind-turbine":
      return {
        type: "windTurbine",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 12),
        h: num(el.h ?? el.height, 18),
        fill: fill ?? classicColor(14),
        text: typeof el.text === "string" ? el.text : "Turbine",
        constraint,
        connections
      };
    case "cloud":
    case "triangle":
    case "parallelogram":
      return {
        type,
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 16),
        h: num(el.h ?? el.height, 12),
        fill: fill ?? (type === "cloud" ? classicColor(14) : type === "triangle" ? classicYellow() : classicPurple()),
        text: typeof el.text === "string" ? el.text : type,
        constraint,
        connections
      };
    // Grafana aliases
    case "rectangle":
      return {
        type: "rect",
        id,
        name,
        x,
        y,
        w: num(el.w ?? el.width, 10),
        h: num(el.h ?? el.height, 10),
        fill,
        text: typeof el.text === "string" ? el.text : void 0,
        constraint,
        connections
      };
    default:
      return null;
  }
}
function normalizeConstraint(raw) {
  if (!raw || typeof raw !== "object") return void 0;
  const c = raw;
  return {
    horizontal: c.horizontal != null ? String(c.horizontal) : void 0,
    vertical: c.vertical != null ? String(c.vertical) : void 0
  };
}
function normalizeConnection(raw, fallbackSource, index2) {
  if (!raw || typeof raw !== "object") return null;
  const c = raw;
  const source = String(c.source ?? c.sourceName ?? fallbackSource ?? "");
  const target = String(c.target ?? c.targetName ?? "");
  if (!source || !target) return null;
  return {
    id: typeof c.id === "string" ? c.id : `conn-${source}-${target}-${index2}`,
    source,
    target,
    color: typeof c.color === "string" ? c.color : classicColor(14),
    pathType: typeof c.pathType === "string" ? c.pathType : "straight",
    strokeWidth: c.strokeWidth != null ? Number(c.strokeWidth) : 0.8,
    sourceOriginal: c.sourceOriginal && typeof c.sourceOriginal === "object" ? {
      x: num(c.sourceOriginal.x, 0.5),
      y: num(c.sourceOriginal.y, 0.5)
    } : { x: 0.5, y: 0.5 },
    targetOriginal: c.targetOriginal && typeof c.targetOriginal === "object" ? {
      x: num(c.targetOriginal.x, 0.5),
      y: num(c.targetOriginal.y, 0.5)
    } : { x: 0.5, y: 0.5 },
    vertices: Array.isArray(c.vertices) ? c.vertices.map((v) => ({ x: num(v?.x, 0), y: num(v?.y, 0) })) : void 0
  };
}
function collectConnections(options, elements) {
  const out = [];
  const seen = /* @__PURE__ */ new Set();
  const push = (c) => {
    if (!c) return;
    const key = c.id || `${c.source}->${c.target}`;
    if (seen.has(key)) return;
    seen.add(key);
    out.push(c);
  };
  if (Array.isArray(options.connections)) {
    options.connections.forEach((c, i) => push(normalizeConnection(c, "", i)));
  }
  for (const el of elements) {
    if (Array.isArray(el.connections)) {
      el.connections.forEach(
        (c, i) => push(normalizeConnection(c, el.id ?? "", i))
      );
    }
  }
  return out;
}
function applyConstraints(elements, canvasW = 100, canvasH = 100) {
  return elements.map((el) => {
    const c = el.constraint;
    if (!c) return el;
    const b = elementBounds(el);
    let x = el.x;
    let y = el.y;
    const h2 = String(c.horizontal ?? "");
    const v = String(c.vertical ?? "");
    if (h2 === "left") x = el.type === "circle" ? b.w / 2 : 0;
    else if (h2 === "right")
      x = el.type === "circle" ? canvasW - b.w / 2 : canvasW - b.w;
    else if (h2 === "center")
      x = el.type === "circle" ? canvasW / 2 : (canvasW - b.w) / 2;
    else if (h2 === "scale") {
      const ratio = el.x / 100;
      x = el.type === "circle" ? ratio * canvasW : ratio * canvasW;
    }
    if (v === "top") y = el.type === "circle" ? b.h / 2 : 0;
    else if (v === "bottom")
      y = el.type === "circle" ? canvasH - b.h / 2 : canvasH - b.h;
    else if (v === "center")
      y = el.type === "circle" ? canvasH / 2 : (canvasH - b.h) / 2;
    else if (v === "scale") {
      const ratio = el.y / 100;
      y = el.type === "circle" ? ratio * canvasH : ratio * canvasH;
    }
    if ((h2 === "scale" || v === "scale") && el.type !== "line" && el.type !== "circle" && el.type !== "text" && el.type !== "metric") {
      const scaleX = canvasW / 100;
      const scaleY = canvasH / 100;
      const w = Math.max(
        1,
        Number(el.w ?? 10) * (h2 === "scale" ? scaleX : 1)
      );
      const hh = Math.max(
        1,
        Number(el.h ?? 10) * (v === "scale" ? scaleY : 1)
      );
      return { ...el, x, y, w, h: hh };
    }
    if (el.type === "line") {
      const dx = x - el.x;
      const dy = y - el.y;
      return {
        ...el,
        x: el.x + dx,
        y: el.y + dy,
        x2: el.x2 + dx,
        y2: el.y2 + dy
      };
    }
    return { ...el, x, y };
  });
}
function anchorPoint(el, anchor = { x: 0.5, y: 0.5 }) {
  const b = elementBounds(el);
  return { x: b.x + b.w * anchor.x, y: b.y + b.h * anchor.y };
}
function connectionPath(elements, conn) {
  const src = elements.find((e) => e.id === conn.source);
  const tgt = elements.find((e) => e.id === conn.target);
  if (!src || !tgt) return null;
  const a = anchorPoint(src, conn.sourceOriginal ?? { x: 0.5, y: 0.5 });
  const b = anchorPoint(tgt, conn.targetOriginal ?? { x: 0.5, y: 0.5 });
  if (conn.pathType === "bezier") {
    const mx = (a.x + b.x) / 2;
    const d = `M ${a.x} ${a.y} C ${mx} ${a.y}, ${mx} ${b.y}, ${b.x} ${b.y}`;
    return { d, x1: a.x, y1: a.y, x2: b.x, y2: b.y };
  }
  if (conn.vertices?.length) {
    const parts = [
      `M ${a.x} ${a.y}`,
      ...conn.vertices.map((v) => `L ${v.x} ${v.y}`),
      `L ${b.x} ${b.y}`
    ];
    return { d: parts.join(" "), x1: a.x, y1: a.y, x2: b.x, y2: b.y };
  }
  return {
    d: `M ${a.x} ${a.y} L ${b.x} ${b.y}`,
    x1: a.x,
    y1: a.y,
    x2: b.x,
    y2: b.y
  };
}
function setConnectionVertices(options, connectionId, vertices) {
  const connections = (options.connections ?? []).map(
    (c) => c.id === connectionId ? {
      ...c,
      vertices: vertices.map((v) => ({
        x: Number(v.x) || 0,
        y: Number(v.y) || 0
      }))
    } : c
  );
  return { ...options, connections };
}
function addConnectionVertex(options, connectionId, vertex) {
  const connections = (options.connections ?? []).map((c) => {
    if (c.id !== connectionId) return c;
    return {
      ...c,
      vertices: [
        ...c.vertices ?? [],
        { x: Number(vertex.x) || 0, y: Number(vertex.y) || 0 }
      ]
    };
  });
  return { ...options, connections };
}
function addConnection(options, sourceId, targetId, patch = {}) {
  if (!sourceId || !targetId || sourceId === targetId) return options;
  const connections = [...options.connections ?? []];
  const id = `conn-${sourceId}-${targetId}-${connections.length}`;
  connections.push({
    id,
    source: sourceId,
    target: targetId,
    color: patch.color ?? classicColor(14),
    pathType: patch.pathType ?? "straight",
    strokeWidth: patch.strokeWidth ?? 0.8,
    sourceOriginal: patch.sourceOriginal ?? { x: 0.5, y: 0.5 },
    targetOriginal: patch.targetOriginal ?? { x: 0.5, y: 0.5 }
  });
  return { ...options, elements: options.elements ?? [], connections };
}
function removeConnection(options, id) {
  return {
    ...options,
    elements: options.elements ?? [],
    connections: (options.connections ?? []).filter((c) => c.id !== id)
  };
}
function setConnectionPathType(options, connectionId, pathType) {
  const connections = (options.connections ?? []).map(
    (c) => c.id === connectionId ? { ...c, pathType } : c
  );
  return { ...options, connections };
}
function toggleConnectionPathType(options, connectionId) {
  const conn = (options.connections ?? []).find((c) => c.id === connectionId);
  if (!conn) return options;
  const next = conn.pathType === "bezier" ? "straight" : "bezier";
  return setConnectionPathType(options, connectionId, next);
}
function updateCanvasElement(elements, id, patch) {
  return elements.map((el) => {
    if (el.id !== id) return el;
    return { ...el, ...patch };
  });
}
function setElementConstraint(elements, id, constraint) {
  return elements.map((el) => el.id === id ? { ...el, constraint } : el);
}
function num(v, fallback) {
  const n = Number(v);
  return Number.isFinite(n) ? n : fallback;
}
function defaultCanvasElements(_value) {
  return [
    {
      type: "metric",
      id: "element-1",
      name: "Element 1",
      x: 100,
      y: 100,
      w: 260,
      h: 50,
      fill: "#c8cacc",
      text: "双击设置字段",
      fontSize: 20,
      textColor: resolveThemeModeHint() === "light" ? "rgb(36, 41, 46)" : "rgb(204, 204, 220)"
    }
  ];
}
function ensureElementIds(elements) {
  return elements.map((el, i) => ({ ...el, id: el.id ?? `el-${i}` }));
}
function addCanvasElement(elements, type) {
  const id = `el-${Date.now().toString(36)}-${elements.length}`;
  const base = { id, x: 40, y: 40 };
  let next;
  switch (type) {
    case "rect":
      next = { type: "rect", ...base, w: 20, h: 14, fill: classicBlue() };
      break;
    case "circle":
      next = { type: "circle", ...base, r: 8, fill: classicGreen() };
      break;
    case "text":
      next = {
        type: "text",
        ...base,
        text: "Text",
        fill: "#c8cacc",
        fontSize: 5
      };
      break;
    case "metric":
      next = {
        type: "metric",
        ...base,
        field: "Value",
        fill: classicYellow(),
        text: "—"
      };
      break;
    case "line":
      next = {
        type: "line",
        ...base,
        x2: 60,
        y2: 60,
        stroke: classicColor(14),
        strokeWidth: 1
      };
      break;
    case "ellipse":
      next = { type: "ellipse", ...base, w: 18, h: 12, fill: classicPurple() };
      break;
    case "icon":
      next = {
        type: "icon",
        ...base,
        w: 10,
        h: 10,
        fill: classicColor(14),
        icon: "cube"
      };
      break;
    case "server":
      next = {
        type: "server",
        ...base,
        w: 14,
        h: 18,
        fill: classicBlue(),
        text: "Server"
      };
      break;
    case "button":
      next = {
        type: "button",
        ...base,
        w: 18,
        h: 8,
        fill: classicBlue(),
        text: "Button"
      };
      break;
    case "drone":
      next = {
        type: "drone",
        ...base,
        w: 14,
        h: 10,
        fill: classicBlue(),
        text: "Drone"
      };
      break;
    case "droneTop":
      next = {
        type: "droneTop",
        ...base,
        w: 14,
        h: 10,
        fill: classicBlue(),
        text: "DroneTop"
      };
      break;
    case "droneFront":
      next = {
        type: "droneFront",
        ...base,
        w: 14,
        h: 10,
        fill: classicBlue(),
        text: "DroneFront"
      };
      break;
    case "droneSide":
      next = {
        type: "droneSide",
        ...base,
        w: 14,
        h: 10,
        fill: classicBlue(),
        text: "DroneSide"
      };
      break;
    case "windTurbine":
      next = {
        type: "windTurbine",
        ...base,
        w: 12,
        h: 18,
        fill: classicColor(14),
        text: "Turbine"
      };
      break;
    case "cloud":
      next = {
        type: "cloud",
        ...base,
        w: 18,
        h: 12,
        fill: classicColor(14),
        text: "Cloud"
      };
      break;
    case "triangle":
      next = {
        type: "triangle",
        ...base,
        w: 16,
        h: 14,
        fill: classicYellow(),
        text: "△"
      };
      break;
    case "parallelogram":
      next = {
        type: "parallelogram",
        ...base,
        w: 20,
        h: 12,
        fill: classicPurple(),
        text: "◇"
      };
      break;
    case "metricValue":
      next = {
        type: "metric",
        ...base,
        field: "Value",
        fill: classicYellow(),
        text: "—"
      };
      break;
    case "rectangle":
      next = { type: "rect", ...base, w: 20, h: 14, fill: classicBlue() };
      break;
    default:
      next = { type: "rect", ...base, w: 16, h: 12, fill: classicBlue() };
      break;
  }
  return [...ensureElementIds(elements), next];
}
function removeCanvasElements(elements, ids) {
  const set = new Set(ids);
  return elements.filter((el) => !el.id || !set.has(el.id));
}
function moveCanvasElement(elements, id, dx, dy) {
  return elements.map((el) => {
    if (el.id !== id) return el;
    if (el.type === "line") {
      return {
        ...el,
        x: el.x + dx,
        y: el.y + dy,
        x2: el.x2 + dx,
        y2: el.y2 + dy
      };
    }
    return { ...el, x: el.x + dx, y: el.y + dy };
  });
}
function moveCanvasElements(elements, ids, dx, dy) {
  let next = elements;
  for (const id of ids) next = moveCanvasElement(next, id, dx, dy);
  return next;
}
function resizeCanvasElement(elements, id, patch) {
  return elements.map((el) => {
    if (el.id !== id) return el;
    if (el.type === "rect" || el.type === "ellipse" || el.type === "icon" || el.type === "server" || el.type === "button" || el.type === "drone" || el.type === "windTurbine") {
      return {
        ...el,
        x: patch.x != null ? patch.x : el.x,
        y: patch.y != null ? patch.y : el.y,
        w: patch.w != null ? Math.max(1, patch.w) : el.w,
        h: patch.h != null ? Math.max(1, patch.h) : el.h
      };
    }
    if (el.type === "circle") {
      return {
        ...el,
        x: patch.x != null ? patch.x : el.x,
        y: patch.y != null ? patch.y : el.y,
        r: patch.r != null ? Math.max(1, patch.r) : el.r
      };
    }
    if (el.type === "line") {
      return {
        ...el,
        x2: patch.x2 != null ? patch.x2 : el.x2,
        y2: patch.y2 != null ? patch.y2 : el.y2
      };
    }
    if (el.type === "text" || el.type === "metric") {
      return {
        ...el,
        x: patch.x != null ? patch.x : el.x,
        y: patch.y != null ? patch.y : el.y
      };
    }
    return el;
  });
}
function selectCanvasElement(options, id, additive = false) {
  if (!id) return { ...options, selectedId: void 0, selectedIds: [] };
  let selectedIds = options.selectedIds ?? (options.selectedId ? [options.selectedId] : []);
  if (additive) {
    selectedIds = selectedIds.includes(id) ? selectedIds.filter((x) => x !== id) : [...selectedIds, id];
  } else {
    selectedIds = [id];
  }
  return {
    ...options,
    selectedId: selectedIds[selectedIds.length - 1],
    selectedIds
  };
}
function bindMetricText(elements, metricValue) {
  return elements.map((el) => {
    if (el.type !== "metric") return el;
    if (!el.field) return el;
    return { ...el, text: metricValue != null ? String(metricValue) : "—" };
  });
}
function serializeCanvasOptions(options) {
  const bgColor = options.backgroundColor ?? options.background ?? (resolveThemeModeHint() === "light" ? "rgb(251, 251, 251)" : "rgb(17, 18, 23)");
  const elements = ensureElementIds(options.elements ?? []);
  const connections = options.connections ?? collectConnections({}, elements);
  return {
    background: {
      color: bgColor,
      ...options.backgroundImage ? { image: options.backgroundImage } : {},
      size: options.backgroundSize ?? "cover"
    },
    // flat alias for simpler consumers
    "background.color": bgColor,
    ...options.backgroundImage ? { "background.image": options.backgroundImage } : {},
    "background.size": options.backgroundSize ?? "cover",
    elements,
    connections,
    root: {
      elements,
      ...typeof options.root === "object" && options.root ? options.root : {}
    },
    inlineEditing: options.inlineEditing !== false,
    panZoom: Boolean(
      options.panZoom === true || String(options.panZoom) === "true" || Number(options.panZoom) === 1
    ),
    panZoomHelp: options.panZoomHelp !== false,
    zoomToContent: Boolean(options.zoomToContent),
    showAdvancedTypes: Boolean(options.showAdvancedTypes),
    tooltip: {
      mode: options.tooltipMode ?? "auto",
      disableForOneClick: Boolean(options.tooltipDisableForOneClick)
    },
    "tooltip.mode": options.tooltipMode ?? "auto",
    "tooltip.disableForOneClick": Boolean(options.tooltipDisableForOneClick),
    ...options.selectedId ? { selectedId: options.selectedId } : {},
    ...options.selectedIds?.length ? { selectedIds: options.selectedIds } : {}
  };
}
function elementBounds(el) {
  if (el.type === "rect" || el.type === "ellipse")
    return { x: el.x, y: el.y, w: el.w, h: el.h };
  if (el.type === "circle")
    return { x: el.x - el.r, y: el.y - el.r, w: el.r * 2, h: el.r * 2 };
  if (el.type === "icon" || el.type === "server" || el.type === "button" || el.type === "drone" || el.type === "droneTop" || el.type === "droneFront" || el.type === "droneSide" || el.type === "windTurbine" || el.type === "cloud" || el.type === "triangle" || el.type === "parallelogram") {
    return { x: el.x, y: el.y, w: el.w ?? 10, h: el.h ?? 10 };
  }
  if (el.type === "line") {
    const x = Math.min(el.x, el.x2);
    const y = Math.min(el.y, el.y2);
    return {
      x,
      y,
      w: Math.max(1, Math.abs(el.x2 - el.x)),
      h: Math.max(1, Math.abs(el.y2 - el.y))
    };
  }
  return { x: el.x, y: el.y - 4, w: 20, h: 8 };
}
function cloneOptions(snapshot) {
  return JSON.parse(JSON.stringify(snapshot));
}
class CanvasHistory {
  past = [];
  future = [];
  limit;
  constructor(limit = 50) {
    this.limit = limit;
  }
  push(snapshot) {
    this.past.push(cloneOptions(snapshot));
    if (this.past.length > this.limit) this.past.shift();
    this.future = [];
  }
  undo(current) {
    const prev = this.past.pop();
    if (!prev) return null;
    this.future.push(cloneOptions(current));
    return prev;
  }
  redo(current) {
    const next = this.future.pop();
    if (!next) return null;
    this.past.push(cloneOptions(current));
    return next;
  }
  get canUndo() {
    return this.past.length > 0;
  }
  get canRedo() {
    return this.future.length > 0;
  }
}
const _hoisted_1$1J = ["data-inline-editing", "data-pan-zoom", "data-zoom-to-content", "data-show-advanced", "data-tooltip-mode", "data-bg-color", "data-bg-image", "data-bg-size", "data-border-color", "data-border-width", "data-color", "data-element-count", "data-connection-count", "data-has-root", "data-has-drone", "data-has-wind-turbine", "data-vertex-total", "data-view-scale", "data-pan-zoom-help"];
const _hoisted_2$1j = {
  key: 0,
  class: "pan-zoom-help",
  "data-testid": "canvas-pan-zoom-help",
  role: "note"
};
const _hoisted_3$18 = {
  key: 1,
  class: "toolbar",
  "data-testid": "canvas-toolbar"
};
const _hoisted_4$Z = ["disabled"];
const _hoisted_5$R = ["disabled"];
const _hoisted_6$L = ["disabled"];
const _hoisted_7$J = ["disabled"];
const _hoisted_8$B = ["disabled"];
const _hoisted_9$z = ["disabled"];
const _hoisted_10$t = ["disabled"];
const _hoisted_11$o = {
  key: 5,
  class: "constraint"
};
const _hoisted_12$i = ["value"];
const _hoisted_13$i = {
  key: 6,
  class: "constraint"
};
const _hoisted_14$g = ["value"];
const _hoisted_15$c = {
  key: 2,
  class: "element-props",
  "data-testid": "canvas-element-props"
};
const _hoisted_16$b = ["value"];
const _hoisted_17$a = ["value"];
const _hoisted_18$a = { key: 0 };
const _hoisted_19$a = ["value"];
const _hoisted_20$9 = { key: 1 };
const _hoisted_21$8 = ["value"];
const _hoisted_22$7 = { key: 2 };
const _hoisted_23$5 = ["value"];
const _hoisted_24$5 = { key: 3 };
const _hoisted_25$5 = ["value"];
const _hoisted_26$5 = { key: 4 };
const _hoisted_27$4 = ["value"];
const _hoisted_28$4 = { key: 5 };
const _hoisted_29$4 = ["value"];
const _hoisted_30$4 = { key: 6 };
const _hoisted_31$4 = ["value"];
const _hoisted_32$4 = ["value"];
const _hoisted_33$4 = ["value"];
const _hoisted_34$4 = ["data-inline-editing", "data-pan-zoom", "data-bg-color"];
const _hoisted_35$3 = ["data-el-type", "data-el-id", "onPointerdown"];
const _hoisted_36$2 = {
  key: 0,
  class: "metric-text"
};
const _hoisted_37$2 = {
  key: 2,
  class: "fallback-label"
};
const _hoisted_38$2 = ["viewBox", "data-inline-editing", "data-pan-zoom", "data-bg-color"];
const _hoisted_39$1 = { key: 0 };
const _hoisted_40$1 = ["width", "height"];
const _hoisted_41$1 = ["href", "width", "height", "preserveAspectRatio"];
const _hoisted_42$1 = ["width", "height", "fill"];
const _hoisted_43$1 = ["data-source", "data-target", "data-vertex-count", "data-path-type"];
const _hoisted_44$1 = ["d", "stroke", "stroke-width"];
const _hoisted_45$1 = ["cx", "cy", "fill", "onPointerdown"];
const _hoisted_46$1 = ["data-el-type", "data-el-animation", "transform", "onPointerdown"];
const _hoisted_47$1 = ["x", "y", "width", "height", "rx", "fill", "stroke", "data-el-id"];
const _hoisted_48$1 = ["x", "y"];
const _hoisted_49$1 = ["x1", "y1", "x2", "y2"];
const _hoisted_50$1 = ["cx", "cy", "r", "fill", "stroke"];
const _hoisted_51$1 = ["cx", "cy", "rx", "ry", "fill", "stroke"];
const _hoisted_52$1 = ["d", "fill", "stroke"];
const _hoisted_53$1 = ["points", "fill", "stroke"];
const _hoisted_54$1 = ["points", "fill", "stroke"];
const _hoisted_55$1 = ["x", "y"];
const _hoisted_56$1 = ["x", "y", "width", "height", "fill", "stroke"];
const _hoisted_57$1 = ["x", "y"];
const _hoisted_58$1 = ["x1", "y1", "x2", "y2", "stroke", "stroke-width", "stroke-dasharray", "data-line-style", "data-has-links", "data-has-actions", "title", "onClick"];
const _hoisted_59$1 = ["x", "y", "width", "height", "fill", "stroke", "data-el-id"];
const _hoisted_60$1 = ["x", "y", "fill", "font-size"];
const _hoisted_61$1 = ["x", "y", "fill", "font-size"];
const _hoisted_62$1 = ["x", "y", "onPointerdown"];
const _sfc_main$2n = /* @__PURE__ */ defineComponent({
  __name: "CanvasEditor",
  props: {
    options: {},
    metricValue: {},
    editable: { type: Boolean },
    width: {},
    height: {}
  },
  emits: ["change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const viewBox = computed(() => {
      const w = Number(props.width);
      const h2 = Number(props.height);
      if (Number.isFinite(w) && w > 0 && Number.isFinite(h2) && h2 > 0) {
        return `0 0 ${Math.round(w)} ${Math.round(h2)}`;
      }
      return "0 0 100 100";
    });
    const viewBoxW = computed(() => {
      const w = Number(props.width);
      return Number.isFinite(w) && w > 0 ? Math.round(w) : 100;
    });
    const viewBoxH = computed(() => {
      const h2 = Number(props.height);
      return Number.isFinite(h2) && h2 > 0 ? Math.round(h2) : 100;
    });
    const usePixelLayout = computed(() => {
      const w = Number(props.width);
      const h2 = Number(props.height);
      return Number.isFinite(w) && w > 40 && Number.isFinite(h2) && h2 > 40;
    });
    const emit = __emit;
    const local = ref(normalizeCanvasOptions(props.options ?? {}));
    const viewScale = ref(1);
    const viewPan = ref({ x: 0, y: 0 });
    const history2 = new CanvasHistory();
    const canUndo = ref(false);
    const canRedo = ref(false);
    function refreshHistoryFlags() {
      canUndo.value = history2.canUndo;
      canRedo.value = history2.canRedo;
    }
    watch(
      () => props.options,
      (o) => {
        if (o) local.value = normalizeCanvasOptions(o);
      }
    );
    const elements = computed(() => {
      const base = local.value.elements?.length ? local.value.elements : defaultCanvasElements(props.metricValue);
      return bindMetricText(base, props.metricValue);
    });
    const selectedIds = computed(
      () => local.value.selectedIds ?? (local.value.selectedId ? [local.value.selectedId] : [])
    );
    const connections = computed(() => local.value.connections ?? []);
    const connectionPaths = computed(
      () => connections.value.map((c) => {
        const path = connectionPath(elements.value, c);
        return path ? { conn: c, ...path } : null;
      }).filter(Boolean)
    );
    function htmlElStyle(el) {
      const any = el;
      const w = Number(any.w ?? (el.type === "circle" ? (any.r ?? 8) * 2 : 100));
      const h2 = Number(any.h ?? (el.type === "circle" ? (any.r ?? 8) * 2 : 100));
      const base = {
        position: "absolute",
        left: `${el.x}px`,
        top: `${el.y}px`,
        width: `${w}px`,
        height: `${h2}px`,
        boxSizing: "border-box"
      };
      if (el.type === "metric") {
        base.background = String(any.fill ?? "var(--grafana-border)");
        base.display = "table";
        base.color = String(any.textColor ?? "var(--grafana-text)");
        base.fontSize = `${Number(any.fontSize ?? 20)}px`;
        base.fontFamily = "Inter, Helvetica, Arial, sans-serif";
        base.fontWeight = "400";
        base.lineHeight = "normal";
      } else if (el.type === "rect" || el.type === "button" || el.type === "server") {
        base.background = String(any.fill ?? "var(--grafana-primary)");
      } else if (el.type === "circle" || el.type === "ellipse") {
        base.background = String(any.fill ?? classicGreen());
        base.borderRadius = el.type === "circle" ? "50%" : "50%";
      }
      if (isSelected(el.id)) {
        base.outline = "1px solid var(--grafana-input-bg)";
      }
      return base;
    }
    function isSelected(id) {
      return !!id && selectedIds.value.includes(id);
    }
    function connectSelected() {
      if (selectedIds.value.length < 2) return;
      const [source, target] = selectedIds.value.slice(-2);
      const base = {
        ...local.value,
        elements: elements.value,
        connections: local.value.connections ?? []
      };
      commit(addConnection(base, source, target));
    }
    function removeSelectedConnections() {
      let next = {
        ...local.value,
        elements: elements.value,
        connections: [...local.value.connections ?? []]
      };
      for (const c of connections.value) {
        if (selectedIds.value.includes(c.source) || selectedIds.value.includes(c.target)) {
          next = removeConnection(next, c.id ?? "");
        }
      }
      commit(next);
    }
    function toggleLastPathType() {
      const last = connections.value[connections.value.length - 1];
      if (!last?.id) return;
      commit(
        toggleConnectionPathType(
          {
            ...local.value,
            elements: elements.value,
            connections: local.value.connections ?? []
          },
          last.id
        )
      );
    }
    function setConstraint(axis, value) {
      const id = selectedIds.value[selectedIds.value.length - 1];
      if (!id) return;
      const el = elements.value.find((e) => e.id === id);
      const constraint = { ...el?.constraint ?? {}, [axis]: value };
      let els = setElementConstraint(elements.value, id, constraint);
      els = applyConstraints(els, 100, 100);
      commit({ ...local.value, elements: els });
    }
    function hasTextProp(el) {
      if (!el) return false;
      return "text" in el || [
        "text",
        "metric",
        "button",
        "server",
        "drone",
        "droneTop",
        "droneFront",
        "droneSide",
        "windTurbine",
        "cloud",
        "triangle",
        "parallelogram",
        "rect"
      ].includes(el.type);
    }
    function patchSelectedElement(partial) {
      const id = selectedIds.value[selectedIds.value.length - 1];
      if (!id) return;
      const els = updateCanvasElement(elements.value, id, partial);
      commit({ ...local.value, elements: els });
    }
    const selectedElement = computed(() => {
      const id = selectedIds.value[selectedIds.value.length - 1];
      return elements.value.find((e) => e.id === id);
    });
    function commit(next, record = true) {
      if (record) history2.push(local.value);
      local.value = next;
      emit("change", serializeCanvasOptions(next));
      refreshHistoryFlags();
    }
    function add(type) {
      const els = addCanvasElement(elements.value, type);
      const selectedId = els[els.length - 1]?.id;
      commit({
        ...local.value,
        elements: els,
        selectedId,
        selectedIds: selectedId ? [selectedId] : []
      });
    }
    function removeSelected() {
      if (!selectedIds.value.length) return;
      commit({
        ...local.value,
        elements: removeCanvasElements(elements.value, selectedIds.value),
        selectedId: void 0,
        selectedIds: []
      });
    }
    function select(id, additive = false) {
      commit(
        selectCanvasElement(
          { ...local.value, elements: elements.value },
          id,
          additive
        ),
        false
      );
    }
    function undo() {
      const prev = history2.undo(local.value);
      if (!prev) return;
      local.value = prev;
      emit("change", serializeCanvasOptions(prev));
      refreshHistoryFlags();
    }
    function redo() {
      const next = history2.redo(local.value);
      if (!next) return;
      local.value = next;
      emit("change", serializeCanvasOptions(next));
      refreshHistoryFlags();
    }
    const dragging = ref(null);
    function svgPoint(evt, svg) {
      const pt = svg.createSVGPoint();
      pt.x = evt.clientX;
      pt.y = evt.clientY;
      const ctm = svg.getScreenCTM();
      if (!ctm) return { x: 0, y: 0 };
      const p = pt.matrixTransform(ctm.inverse());
      return { x: p.x, y: p.y };
    }
    function ownerSvg(evt) {
      const el = evt.currentTarget;
      if (el instanceof SVGSVGElement) return el;
      return el.ownerSVGElement;
    }
    function onPointerDown(evt, id) {
      if (!props.editable) return;
      const svg = ownerSvg(evt);
      if (!svg) return;
      evt.currentTarget.setPointerCapture?.(evt.pointerId);
      const p = svgPoint(evt, svg);
      const additive = evt.shiftKey || evt.metaKey || evt.ctrlKey;
      const nextSel = selectCanvasElement(
        { ...local.value, elements: elements.value },
        id,
        additive
      );
      local.value = nextSel;
      const ids = nextSel.selectedIds?.length ? nextSel.selectedIds : [id];
      dragging.value = { kind: "move", ids, lastX: p.x, lastY: p.y };
    }
    function onResizeDown(evt, id) {
      if (!props.editable) return;
      evt.stopPropagation();
      const svg = ownerSvg(evt);
      if (!svg) return;
      evt.currentTarget.setPointerCapture?.(evt.pointerId);
      const p = svgPoint(evt, svg);
      const origin = elements.value.find((e) => e.id === id);
      if (!origin) return;
      history2.push(local.value);
      dragging.value = {
        kind: "resize",
        id,
        startX: p.x,
        startY: p.y,
        origin: JSON.parse(JSON.stringify(origin))
      };
      local.value = { ...local.value, selectedId: id, selectedIds: [id] };
    }
    function onPointerMove(evt) {
      if (!dragging.value || !props.editable) return;
      if (dragging.value.kind === "vertex") {
        const svg2 = ownerSvg(evt);
        if (!svg2) return;
        const p2 = svgPoint(evt, svg2);
        const d = dragging.value;
        const conn = (local.value.connections ?? []).find((c) => c.id === d.connId);
        if (!conn) return;
        const verts = [...conn.vertices ?? []];
        verts[d.vertexIndex] = { x: p2.x, y: p2.y };
        local.value = setConnectionVertices(local.value, d.connId, verts);
        return;
      }
      const svg = ownerSvg(evt);
      if (!svg) return;
      const p = svgPoint(evt, svg);
      if (dragging.value.kind === "move") {
        const dx = p.x - dragging.value.lastX;
        const dy = p.y - dragging.value.lastY;
        if (Math.abs(dx) < 0.01 && Math.abs(dy) < 0.01) return;
        const els = moveCanvasElements(elements.value, dragging.value.ids, dx, dy);
        dragging.value = {
          kind: "move",
          ids: dragging.value.ids,
          lastX: p.x,
          lastY: p.y
        };
        local.value = { ...local.value, elements: els };
        return;
      }
      const { id, origin } = dragging.value;
      if (origin.type === "rect" || origin.type === "ellipse" || origin.type === "icon" || origin.type === "server" || origin.type === "button" || origin.type === "drone" || origin.type === "droneTop" || origin.type === "droneFront" || origin.type === "droneSide" || origin.type === "windTurbine" || origin.type === "cloud" || origin.type === "triangle" || origin.type === "parallelogram") {
        const w = Math.max(
          1,
          Number(origin.w ?? 12) + (p.x - dragging.value.startX)
        );
        const h2 = Math.max(
          1,
          Number(origin.h ?? 10) + (p.y - dragging.value.startY)
        );
        local.value = {
          ...local.value,
          elements: resizeCanvasElement(elements.value, id, { w, h: h2 })
        };
      } else if (origin.type === "circle") {
        const r = Math.max(
          1,
          origin.r + (p.x - dragging.value.startX + p.y - dragging.value.startY) / 2
        );
        local.value = {
          ...local.value,
          elements: resizeCanvasElement(elements.value, id, { r })
        };
      } else if (origin.type === "line") {
        local.value = {
          ...local.value,
          elements: resizeCanvasElement(elements.value, id, { x2: p.x, y2: p.y })
        };
      }
    }
    function onPointerUp() {
      if (!dragging.value) return;
      const wasResize = dragging.value.kind === "resize";
      dragging.value = null;
      commit({ ...local.value, elements: elements.value }, !wasResize);
    }
    function onVertexDown(evt, connId, vertexIndex) {
      if (!props.editable) return;
      evt.stopPropagation();
      const svg = ownerSvg(evt);
      if (!svg) return;
      evt.currentTarget.setPointerCapture?.(evt.pointerId);
      history2.push(local.value);
      dragging.value = { kind: "vertex", connId, vertexIndex };
    }
    function addVertexToLast() {
      const last = connections.value[connections.value.length - 1];
      if (!last?.id) return;
      history2.push(local.value);
      const mid = { x: 50, y: 50 };
      if (last.source && last.target) {
        const path = connectionPath(elements.value, last);
        if (path) {
          mid.x = (path.x1 + path.x2) / 2;
          mid.y = (path.y1 + path.y2) / 2;
        }
      }
      const next = addConnectionVertex(local.value, last.id, mid);
      commit(next, false);
    }
    function onWheel(evt) {
      if (!local.value.panZoom) return;
      evt.preventDefault();
      const dir = evt.deltaY > 0 ? 0.9 : 1.1;
      viewScale.value = Math.max(0.4, Math.min(3, viewScale.value * dir));
    }
    function onBgClick(evt) {
      if (!props.editable) return;
      if (evt.target === evt.currentTarget) select(void 0);
    }
    function hit(el) {
      return el.id ?? "";
    }
    function cloudPath(el) {
      const x = Number(el.x), y = Number(el.y), w = Number(el.w ?? 16), h2 = Number(el.h ?? 12);
      const cy = y + h2 / 2;
      return `M ${x + w * 0.2} ${cy + h2 * 0.15}
    a ${w * 0.18} ${h2 * 0.22} 0 1 1 ${w * 0.15} ${-h2 * 0.2}
    a ${w * 0.22} ${h2 * 0.25} 0 1 1 ${w * 0.35} 0
    a ${w * 0.16} ${h2 * 0.2} 0 1 1 ${w * 0.12} ${h2 * 0.18}
    z`;
    }
    function trianglePoints(el) {
      const x = Number(el.x), y = Number(el.y), w = Number(el.w ?? 16), h2 = Number(el.h ?? 14);
      return `${x + w / 2},${y} ${x + w},${y + h2} ${x},${y + h2}`;
    }
    function parallelogramPoints(el) {
      const x = Number(el.x), y = Number(el.y), w = Number(el.w ?? 20), h2 = Number(el.h ?? 12);
      const skew = w * 0.25;
      return `${x + skew},${y} ${x + w},${y} ${x + w - skew},${y + h2} ${x},${y + h2}`;
    }
    function handlePos(el) {
      const b = elementBounds(el);
      return { x: b.x + b.w, y: b.y + b.h };
    }
    function linkTitle(el) {
      const links = el?.links;
      if (!Array.isArray(links) || !links.length) return String(el?.name || el?.id || "");
      return links.map((l) => l?.title || l?.url || String(l)).filter(Boolean).join(" · ");
    }
    function onElementActivate(el) {
      const links = el?.links;
      if (Array.isArray(links) && links[0]) {
        const url = links[0].url || links[0].href || (typeof links[0] === "string" ? links[0] : "");
        if (url && typeof window !== "undefined") {
          try {
            window.open(String(url), "_blank", "noopener,noreferrer");
          } catch {
          }
        }
      }
      if (el?.actions?.length) {
        el.__lastAction = el.actions[0];
      }
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "canvas-editor",
        "data-testid": "canvas-editor",
        "data-inline-editing": String(local.value.inlineEditing !== false),
        "data-pan-zoom": String(!!local.value.panZoom),
        "data-zoom-to-content": String(!!local.value.zoomToContent),
        "data-show-advanced": String(!!local.value.showAdvancedTypes),
        "data-tooltip-mode": String(local.value.tooltipMode ?? "auto"),
        "data-bg-color": String(local.value.backgroundColor || local.value.background || "var(--grafana-bg-canvas)"),
        "data-bg-image": String(local.value.backgroundImage || ""),
        "data-bg-size": String(local.value.backgroundSize || "cover"),
        "data-border-color": String(local.value.borderColor || ""),
        "data-border-width": String(local.value.borderWidth ?? ""),
        "data-color": String(local.value.color || ""),
        "data-element-count": String(elements.value.length),
        "data-connection-count": String(connections.value.length),
        "data-has-root": String(!!local.value.root),
        "data-has-drone": String(elements.value.some((e) => String(e.type).startsWith("drone"))),
        "data-has-wind-turbine": String(elements.value.some((e) => e.type === "windTurbine")),
        "data-vertex-total": String(connections.value.reduce((n, c) => n + (c.vertices?.length ?? 0), 0)),
        "data-view-scale": String(viewScale.value),
        "data-pan-zoom-help": String(!!local.value.panZoom && local.value.panZoomHelp !== false)
      }, [
        createCommentVNode(" Grafana PanZoomHelp: options-pane info; surface when panZoom enabled "),
        local.value.panZoom ? (openBlock(), createElementBlock("div", _hoisted_2$1j, [..._cache[30] || (_cache[30] = [
          createElementVNode(
            "div",
            { class: "pan-zoom-help__title" },
            "平移与缩放控制",
            -1
            /* CACHED */
          ),
          createElementVNode(
            "ul",
            { class: "pan-zoom-help__list" },
            [
              createElementVNode("li", null, "平移：中键 或 Ctrl + 右键拖动"),
              createElementVNode("li", null, "缩放：滚轮"),
              createElementVNode("li", null, "重置：双击")
            ],
            -1
            /* CACHED */
          )
        ])])) : createCommentVNode("v-if", true),
        __props.editable && local.value.inlineEditing !== false ? (openBlock(), createElementBlock("div", _hoisted_3$18, [
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-rect",
            onClick: _cache[0] || (_cache[0] = ($event) => add("rect"))
          }, " 矩形 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-circle",
            onClick: _cache[1] || (_cache[1] = ($event) => add("circle"))
          }, " 圆形 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-text",
            onClick: _cache[2] || (_cache[2] = ($event) => add("text"))
          }, " 文本 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-metric",
            onClick: _cache[3] || (_cache[3] = ($event) => add("metric"))
          }, " 指标 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-line",
            onClick: _cache[4] || (_cache[4] = ($event) => add("line"))
          }, " 直线 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-ellipse",
            onClick: _cache[5] || (_cache[5] = ($event) => add("ellipse"))
          }, " 椭圆 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-cloud",
            onClick: _cache[6] || (_cache[6] = ($event) => add("cloud"))
          }, " 云 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-triangle",
            onClick: _cache[7] || (_cache[7] = ($event) => add("triangle"))
          }, " 三角 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-parallelogram",
            onClick: _cache[8] || (_cache[8] = ($event) => add("parallelogram"))
          }, " 平行四边形 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-icon",
            onClick: _cache[9] || (_cache[9] = ($event) => add("icon"))
          }, " 图标 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-server",
            onClick: _cache[10] || (_cache[10] = ($event) => add("server"))
          }, " 服务器 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-button",
            onClick: _cache[11] || (_cache[11] = ($event) => add("button"))
          }, " 按钮 "),
          local.value.showAdvancedTypes ? (openBlock(), createElementBlock("button", {
            key: 0,
            type: "button",
            "data-testid": "canvas-add-drone",
            onClick: _cache[12] || (_cache[12] = ($event) => add("drone"))
          }, " 无人机 ")) : createCommentVNode("v-if", true),
          local.value.showAdvancedTypes ? (openBlock(), createElementBlock("button", {
            key: 1,
            type: "button",
            "data-testid": "canvas-add-drone-top",
            onClick: _cache[13] || (_cache[13] = ($event) => add("droneTop"))
          }, " 无人机顶视 ")) : createCommentVNode("v-if", true),
          local.value.showAdvancedTypes ? (openBlock(), createElementBlock("button", {
            key: 2,
            type: "button",
            "data-testid": "canvas-add-drone-front",
            onClick: _cache[14] || (_cache[14] = ($event) => add("droneFront"))
          }, " 无人机前视 ")) : createCommentVNode("v-if", true),
          local.value.showAdvancedTypes ? (openBlock(), createElementBlock("button", {
            key: 3,
            type: "button",
            "data-testid": "canvas-add-drone-side",
            onClick: _cache[15] || (_cache[15] = ($event) => add("droneSide"))
          }, " 无人机侧视 ")) : createCommentVNode("v-if", true),
          local.value.showAdvancedTypes ? (openBlock(), createElementBlock("button", {
            key: 4,
            type: "button",
            "data-testid": "canvas-add-wind-turbine",
            onClick: _cache[16] || (_cache[16] = ($event) => add("windTurbine"))
          }, " 风机 ")) : createCommentVNode("v-if", true),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-connect",
            disabled: selectedIds.value.length < 2,
            onClick: connectSelected
          }, " 连接 ", 8, _hoisted_4$Z),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-add-vertex",
            disabled: !connections.value.length,
            onClick: addVertexToLast
          }, " 加顶点 ", 8, _hoisted_5$R),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-path-type",
            disabled: !connections.value.length,
            onClick: toggleLastPathType
          }, " 路径类型 ", 8, _hoisted_6$L),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-disconnect",
            disabled: !connections.value.length,
            onClick: removeSelectedConnections
          }, " 断连 ", 8, _hoisted_7$J),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-remove",
            disabled: !selectedIds.value.length,
            onClick: removeSelected
          }, " 删除 ", 8, _hoisted_8$B),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-undo",
            disabled: !canUndo.value,
            onClick: undo
          }, " 撤销 ", 8, _hoisted_9$z),
          createElementVNode("button", {
            type: "button",
            "data-testid": "canvas-redo",
            disabled: !canRedo.value,
            onClick: redo
          }, " 重做 ", 8, _hoisted_10$t),
          selectedElement.value ? (openBlock(), createElementBlock("label", _hoisted_11$o, [
            _cache[32] || (_cache[32] = createTextVNode(
              " 水平 ",
              -1
              /* CACHED */
            )),
            createElementVNode("select", {
              "data-testid": "canvas-constraint-h",
              value: selectedElement.value.constraint?.horizontal ?? "",
              onChange: _cache[17] || (_cache[17] = ($event) => setConstraint(
                "horizontal",
                $event.target.value
              ))
            }, [..._cache[31] || (_cache[31] = [
              createElementVNode(
                "option",
                { value: "" },
                "自由",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "left" },
                "左",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "center" },
                "中",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "right" },
                "右",
                -1
                /* CACHED */
              )
            ])], 40, _hoisted_12$i)
          ])) : createCommentVNode("v-if", true),
          selectedElement.value ? (openBlock(), createElementBlock("label", _hoisted_13$i, [
            _cache[34] || (_cache[34] = createTextVNode(
              " 垂直 ",
              -1
              /* CACHED */
            )),
            createElementVNode("select", {
              "data-testid": "canvas-constraint-v",
              value: selectedElement.value.constraint?.vertical ?? "",
              onChange: _cache[18] || (_cache[18] = ($event) => setConstraint(
                "vertical",
                $event.target.value
              ))
            }, [..._cache[33] || (_cache[33] = [
              createElementVNode(
                "option",
                { value: "" },
                "自由",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "top" },
                "上",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "center" },
                "中",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "bottom" },
                "下",
                -1
                /* CACHED */
              )
            ])], 40, _hoisted_14$g)
          ])) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        __props.editable && selectedElement.value ? (openBlock(), createElementBlock("div", _hoisted_15$c, [
          _cache[47] || (_cache[47] = createElementVNode(
            "strong",
            null,
            "元素属性",
            -1
            /* CACHED */
          )),
          createElementVNode("label", null, [
            _cache[35] || (_cache[35] = createTextVNode(
              "名称 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-name",
              value: String(selectedElement.value.name ?? selectedElement.value.id ?? ""),
              onChange: _cache[19] || (_cache[19] = ($event) => patchSelectedElement({
                name: $event.target.value
              }))
            }, null, 40, _hoisted_16$b)
          ]),
          createElementVNode("label", null, [
            _cache[36] || (_cache[36] = createTextVNode(
              "填充色 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-fill",
              type: "color",
              value: String(selectedElement.value.fill ?? "var(--grafana-primary)"),
              onInput: _cache[20] || (_cache[20] = ($event) => patchSelectedElement({
                fill: $event.target.value
              }))
            }, null, 40, _hoisted_17$a)
          ]),
          hasTextProp(selectedElement.value) ? (openBlock(), createElementBlock("label", _hoisted_18$a, [
            _cache[37] || (_cache[37] = createTextVNode(
              "文本 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-text",
              value: String(selectedElement.value.text ?? ""),
              onChange: _cache[21] || (_cache[21] = ($event) => patchSelectedElement({
                text: $event.target.value
              }))
            }, null, 40, _hoisted_19$a)
          ])) : createCommentVNode("v-if", true),
          selectedElement.value.type === "metric" ? (openBlock(), createElementBlock("label", _hoisted_20$9, [
            _cache[38] || (_cache[38] = createTextVNode(
              "字段 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-field",
              value: String(selectedElement.value.field ?? ""),
              onChange: _cache[22] || (_cache[22] = ($event) => patchSelectedElement({
                field: $event.target.value
              }))
            }, null, 40, _hoisted_21$8)
          ])) : createCommentVNode("v-if", true),
          selectedElement.value.type === "line" ? (openBlock(), createElementBlock("label", _hoisted_22$7, [
            _cache[39] || (_cache[39] = createTextVNode(
              "描边色 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-stroke",
              type: "color",
              value: String(selectedElement.value.stroke ?? "var(--grafana-primary)"),
              onInput: _cache[23] || (_cache[23] = ($event) => patchSelectedElement({
                stroke: $event.target.value
              }))
            }, null, 40, _hoisted_23$5)
          ])) : createCommentVNode("v-if", true),
          selectedElement.value.type === "line" ? (openBlock(), createElementBlock("label", _hoisted_24$5, [
            _cache[40] || (_cache[40] = createTextVNode(
              "线宽 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-stroke-width",
              type: "number",
              min: "0.2",
              step: "0.2",
              value: Number(selectedElement.value.strokeWidth ?? 1),
              onChange: _cache[24] || (_cache[24] = ($event) => patchSelectedElement({
                strokeWidth: Number($event.target.value)
              }))
            }, null, 40, _hoisted_25$5)
          ])) : createCommentVNode("v-if", true),
          "w" in selectedElement.value ? (openBlock(), createElementBlock("label", _hoisted_26$5, [
            _cache[41] || (_cache[41] = createTextVNode(
              "宽 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-w",
              type: "number",
              value: Number(selectedElement.value.w ?? 12),
              onChange: _cache[25] || (_cache[25] = ($event) => patchSelectedElement({
                w: Number($event.target.value)
              }))
            }, null, 40, _hoisted_27$4)
          ])) : createCommentVNode("v-if", true),
          "h" in selectedElement.value ? (openBlock(), createElementBlock("label", _hoisted_28$4, [
            _cache[42] || (_cache[42] = createTextVNode(
              "高 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-h",
              type: "number",
              value: Number(selectedElement.value.h ?? 10),
              onChange: _cache[26] || (_cache[26] = ($event) => patchSelectedElement({
                h: Number($event.target.value)
              }))
            }, null, 40, _hoisted_29$4)
          ])) : createCommentVNode("v-if", true),
          selectedElement.value.type === "circle" ? (openBlock(), createElementBlock("label", _hoisted_30$4, [
            _cache[43] || (_cache[43] = createTextVNode(
              "半径 ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-r",
              type: "number",
              value: Number(selectedElement.value.r ?? 8),
              onChange: _cache[27] || (_cache[27] = ($event) => patchSelectedElement({
                r: Number($event.target.value)
              }))
            }, null, 40, _hoisted_31$4)
          ])) : createCommentVNode("v-if", true),
          createElementVNode("label", null, [
            _cache[44] || (_cache[44] = createTextVNode(
              "旋转° ",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              "data-testid": "canvas-el-rotation",
              type: "number",
              value: Number(selectedElement.value.rotation ?? 0),
              onChange: _cache[28] || (_cache[28] = ($event) => patchSelectedElement({
                rotation: Number($event.target.value)
              }))
            }, null, 40, _hoisted_32$4)
          ]),
          createElementVNode("label", null, [
            _cache[46] || (_cache[46] = createTextVNode(
              "动画 ",
              -1
              /* CACHED */
            )),
            createElementVNode("select", {
              "data-testid": "canvas-el-animation",
              value: String(selectedElement.value.animation ?? "none"),
              onChange: _cache[29] || (_cache[29] = ($event) => patchSelectedElement({
                animation: $event.target.value
              }))
            }, [..._cache[45] || (_cache[45] = [
              createElementVNode(
                "option",
                { value: "none" },
                "无",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "pulse" },
                "脉冲",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "spin" },
                "旋转",
                -1
                /* CACHED */
              ),
              createElementVNode(
                "option",
                { value: "blink" },
                "闪烁",
                -1
                /* CACHED */
              )
            ])], 40, _hoisted_33$4)
          ])
        ])) : createCommentVNode("v-if", true),
        createCommentVNode(" Grafana Scene uses absolute HTML elements (not SVG text) — dual-run path "),
        usePixelLayout.value ? (openBlock(), createElementBlock("div", {
          key: 3,
          class: "canvas-html",
          "data-testid": "panel-canvas",
          "data-inline-editing": String(local.value.inlineEditing !== false),
          "data-pan-zoom": String(!!local.value.panZoom),
          "data-bg-color": String(local.value.backgroundColor || local.value.background || "transparent"),
          "data-pixel-layout": true,
          role: "img",
          "aria-label": "画布面板",
          style: normalizeStyle({
            width: viewBoxW.value + "px",
            height: viewBoxH.value + "px",
            background: local.value.backgroundImage ? `url(${local.value.backgroundImage}) ${local.value.backgroundSize || "cover"} center/cover no-repeat` : local.value.backgroundColor || local.value.background || "transparent",
            transform: `translate(${viewPan.value.x}px,${viewPan.value.y}px) scale(${viewScale.value})`,
            transformOrigin: "center center"
          }),
          onClick: onBgClick
        }, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(elements.value, (el, i) => {
              return openBlock(), createElementBlock("div", {
                key: el.id ?? i,
                class: normalizeClass(["canvas-el", ["type-" + el.type, { selected: isSelected(el.id) }]]),
                "data-el-type": el.type,
                "data-el-id": hit(el),
                style: normalizeStyle(htmlElStyle(el)),
                onPointerdown: withModifiers(($event) => props.editable ? onPointerDown($event, hit(el)) : void 0, ["stop"])
              }, [
                el.type === "metric" ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_36$2,
                  toDisplayString(el.text || "双击设置字段"),
                  1
                  /* TEXT */
                )) : el.type === "text" ? (openBlock(), createElementBlock(
                  "span",
                  {
                    key: 1,
                    class: "plain-text",
                    style: normalizeStyle({
                      color: el.fill || "var(--grafana-text)",
                      fontSize: (el.fontSize || 12) + "px"
                    })
                  },
                  toDisplayString(el.text),
                  5
                  /* TEXT, STYLE */
                )) : (openBlock(), createElementBlock(
                  "span",
                  _hoisted_37$2,
                  toDisplayString(el.type),
                  1
                  /* TEXT */
                ))
              ], 46, _hoisted_35$3);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 12, _hoisted_34$4)) : (openBlock(), createElementBlock("svg", {
          key: 4,
          class: "canvas",
          viewBox: viewBox.value,
          preserveAspectRatio: "none",
          onWheel: withModifiers(onWheel, ["prevent"]),
          style: normalizeStyle({
            transform: `translate(${viewPan.value.x}px,${viewPan.value.y}px) scale(${viewScale.value})`,
            transformOrigin: "center center"
          }),
          "data-testid": "panel-canvas",
          "data-inline-editing": String(local.value.inlineEditing !== false),
          "data-pan-zoom": String(!!local.value.panZoom),
          "data-bg-color": String(local.value.backgroundColor || local.value.background || "var(--grafana-bg-canvas)"),
          role: "img",
          "aria-label": "画布面板",
          onPointermove: onPointerMove,
          onPointerup: onPointerUp,
          onPointerleave: onPointerUp,
          onClick: onBgClick
        }, [
          local.value.backgroundImage ? (openBlock(), createElementBlock("defs", _hoisted_39$1, [
            createElementVNode("pattern", {
              id: "canvas-bg-img",
              patternUnits: "userSpaceOnUse",
              width: viewBoxW.value,
              height: viewBoxH.value
            }, [
              createElementVNode("image", {
                href: local.value.backgroundImage,
                x: "0",
                y: "0",
                width: viewBoxW.value,
                height: viewBoxH.value,
                preserveAspectRatio: local.value.backgroundSize === "contain" ? "xMidYMid meet" : "xMidYMid slice"
              }, null, 8, _hoisted_41$1)
            ], 8, _hoisted_40$1)
          ])) : createCommentVNode("v-if", true),
          createElementVNode("rect", {
            x: "0",
            y: "0",
            width: viewBoxW.value,
            height: viewBoxH.value,
            fill: local.value.backgroundImage ? "url(#canvas-bg-img)" : local.value.backgroundColor || local.value.background || "transparent"
          }, null, 8, _hoisted_42$1),
          _cache[48] || (_cache[48] = createElementVNode(
            "defs",
            null,
            [
              createElementVNode("marker", {
                id: "canvas-arrow",
                markerWidth: "4",
                markerHeight: "4",
                refX: "3",
                refY: "2",
                orient: "auto"
              }, [
                createElementVNode("path", {
                  d: "M0,0 L4,2 L0,4 Z",
                  fill: "var(--grafana-primary)"
                })
              ])
            ],
            -1
            /* CACHED */
          )),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(connectionPaths.value, (cp, ci) => {
              return openBlock(), createElementBlock("g", {
                key: cp.conn.id ?? ci,
                "data-testid": "canvas-connection",
                "data-source": cp.conn.source,
                "data-target": cp.conn.target,
                "data-vertex-count": String(cp.conn.vertices?.length ?? 0),
                "data-path-type": String(cp.conn.pathType ?? "straight")
              }, [
                createElementVNode("path", {
                  d: cp.d,
                  fill: "none",
                  stroke: cp.conn.color ?? "var(--grafana-primary)",
                  "stroke-width": cp.conn.strokeWidth ?? 0.8,
                  "marker-end": "url(#canvas-arrow)"
                }, null, 8, _hoisted_44$1),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(cp.conn.vertices ?? [], (v, vi) => {
                    return openBlock(), createElementBlock("circle", {
                      key: vi,
                      cx: v.x,
                      cy: v.y,
                      r: "1.6",
                      fill: unref(classicYellow)(),
                      stroke: "var(--grafana-bg-canvas)",
                      "stroke-width": "0.3",
                      "data-testid": "canvas-connection-vertex",
                      style: { "cursor": "move" },
                      onPointerdown: withModifiers(($event) => onVertexDown($event, String(cp.conn.id ?? ""), vi), ["stop"])
                    }, null, 40, _hoisted_45$1);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ], 8, _hoisted_43$1);
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(elements.value, (el, i) => {
              return openBlock(), createElementBlock("g", {
                key: el.id ?? i,
                "data-el-type": el.type,
                "data-el-animation": String(el.animation ?? "none"),
                transform: el.rotation ? `rotate(${el.rotation} ${el.x + (el.w ?? el.r ?? 0) / 2} ${el.y + (el.h ?? el.r ?? 0) / 2})` : void 0,
                style: { "cursor": "move" },
                onPointerdown: withModifiers(($event) => onPointerDown($event, hit(el)), ["stop"])
              }, [
                el.type === "rect" || el.type === "button" || el.type === "server" || el.type === "drone" || el.type === "droneTop" || el.type === "droneFront" || el.type === "droneSide" || el.type === "windTurbine" ? (openBlock(), createElementBlock("rect", {
                  key: 0,
                  x: el.x,
                  y: el.y,
                  width: el.w ?? 12,
                  height: el.h ?? 10,
                  rx: el.type === "button" ? 1.5 : el.type === "drone" ? 3 : el.type === "windTurbine" ? 1 : el.type === "server" ? 0.5 : 0,
                  fill: el.fill ?? (el.type === "server" ? "var(--grafana-primary)" : el.type === "button" ? unref(classicBlue)() : el.type === "drone" ? unref(classicBlue)() : el.type === "windTurbine" ? "var(--grafana-primary)" : "var(--grafana-primary)"),
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8",
                  "data-el-id": hit(el)
                }, null, 8, _hoisted_47$1)) : createCommentVNode("v-if", true),
                el.type === "button" || el.type === "server" || el.type === "drone" || el.type === "droneTop" || el.type === "droneFront" || el.type === "droneSide" || el.type === "windTurbine" ? (openBlock(), createElementBlock("text", {
                  key: 1,
                  x: el.x + (el.w ?? 12) / 2,
                  y: el.y + (el.h ?? 10) / 2 + 1.2,
                  "text-anchor": "middle",
                  fill: "var(--grafana-bg-canvas)",
                  "font-size": "3.2",
                  style: { "pointer-events": "none" }
                }, toDisplayString(el.text || (el.type === "server" ? "Server" : el.type === "drone" ? "Drone" : el.type === "windTurbine" ? "Turbine" : "Button")), 9, _hoisted_48$1)) : createCommentVNode("v-if", true),
                createCommentVNode(" windTurbine pole visual "),
                el.type === "windTurbine" ? (openBlock(), createElementBlock("line", {
                  key: 2,
                  x1: el.x + (el.w ?? 12) / 2,
                  y1: el.y + (el.h ?? 18),
                  x2: el.x + (el.w ?? 12) / 2,
                  y2: el.y + (el.h ?? 18) + 6,
                  stroke: "var(--grafana-primary)",
                  "stroke-width": "0.8",
                  style: { "pointer-events": "none" }
                }, null, 8, _hoisted_49$1)) : createCommentVNode("v-if", true),
                el.type === "circle" ? (openBlock(), createElementBlock("circle", {
                  key: 3,
                  cx: el.x,
                  cy: el.y,
                  r: el.r,
                  fill: el.fill ?? unref(classicGreen)(),
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_50$1)) : createCommentVNode("v-if", true),
                el.type === "ellipse" ? (openBlock(), createElementBlock("ellipse", {
                  key: 4,
                  cx: el.x + el.w / 2,
                  cy: el.y + el.h / 2,
                  rx: el.w / 2,
                  ry: el.h / 2,
                  fill: el.fill ?? unref(classicPurple)(),
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_51$1)) : createCommentVNode("v-if", true),
                el.type === "cloud" ? (openBlock(), createElementBlock("path", {
                  key: 5,
                  d: cloudPath(el),
                  fill: el.fill ?? "var(--grafana-primary)",
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_52$1)) : createCommentVNode("v-if", true),
                el.type === "triangle" ? (openBlock(), createElementBlock("polygon", {
                  key: 6,
                  points: trianglePoints(el),
                  fill: el.fill ?? unref(classicYellow)(),
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_53$1)) : createCommentVNode("v-if", true),
                el.type === "parallelogram" ? (openBlock(), createElementBlock("polygon", {
                  key: 7,
                  points: parallelogramPoints(el),
                  fill: el.fill ?? unref(classicPurple)(),
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_54$1)) : createCommentVNode("v-if", true),
                el.type === "cloud" || el.type === "triangle" || el.type === "parallelogram" ? (openBlock(), createElementBlock("text", {
                  key: 8,
                  x: el.x + (el.w ?? 16) / 2,
                  y: el.y + (el.h ?? 12) / 2 + 1.2,
                  "text-anchor": "middle",
                  fill: "var(--grafana-bg-canvas)",
                  "font-size": "3",
                  style: { "pointer-events": "none" }
                }, toDisplayString(el.text || el.type), 9, _hoisted_55$1)) : createCommentVNode("v-if", true),
                el.type === "icon" ? (openBlock(), createElementBlock(
                  Fragment,
                  { key: 9 },
                  [
                    createElementVNode("rect", {
                      x: el.x,
                      y: el.y,
                      width: el.w ?? 8,
                      height: el.h ?? 8,
                      fill: el.fill ?? "var(--grafana-primary)",
                      stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                      "stroke-width": "0.6",
                      rx: "1"
                    }, null, 8, _hoisted_56$1),
                    createElementVNode("text", {
                      x: el.x + (el.w ?? 8) / 2,
                      y: el.y + (el.h ?? 8) / 2 + 1.5,
                      "text-anchor": "middle",
                      fill: "var(--grafana-bg-canvas)",
                      "font-size": "4",
                      style: { "pointer-events": "none" }
                    }, " ◆ ", 8, _hoisted_57$1)
                  ],
                  64
                  /* STABLE_FRAGMENT */
                )) : createCommentVNode("v-if", true),
                el.type === "line" ? (openBlock(), createElementBlock("line", {
                  key: 10,
                  x1: el.x,
                  y1: el.y,
                  x2: el.x2,
                  y2: el.y2,
                  stroke: el.stroke ?? "var(--grafana-primary)",
                  "stroke-width": el.strokeWidth ?? 0.8,
                  "stroke-dasharray": unref(resolveLineDash)(el.lineStyle),
                  "data-line-style": String(el.lineStyle ?? "solid"),
                  "data-has-links": String(!!(el.links && el.links.length)),
                  "data-has-actions": String(!!(el.actions && el.actions.length)),
                  title: linkTitle(el),
                  onClick: withModifiers(($event) => onElementActivate(el), ["stop"])
                }, null, 8, _hoisted_58$1)) : createCommentVNode("v-if", true),
                createCommentVNode(" metric-value: Grafana defaultBgColor box + centered text "),
                el.type === "metric" ? (openBlock(), createElementBlock("rect", {
                  key: 11,
                  x: el.x,
                  y: el.y,
                  width: el.w ?? 260,
                  height: el.h ?? 50,
                  fill: el.fill ?? "var(--grafana-border)",
                  stroke: isSelected(el.id) ? "var(--grafana-input-bg)" : "transparent",
                  "stroke-width": "1",
                  "data-el-id": hit(el)
                }, null, 8, _hoisted_59$1)) : createCommentVNode("v-if", true),
                el.type === "metric" ? (openBlock(), createElementBlock("text", {
                  key: 12,
                  x: el.x + (el.w ?? 260) / 2,
                  y: el.y + (el.h ?? 50) / 2,
                  "text-anchor": "middle",
                  "dominant-baseline": "middle",
                  fill: el.textColor ?? "var(--grafana-text)",
                  "font-size": el.fontSize ?? 20,
                  "font-family": "Inter, Helvetica, Arial, sans-serif",
                  style: { "pointer-events": "none" }
                }, toDisplayString(el.text || "双击设置字段"), 9, _hoisted_60$1)) : createCommentVNode("v-if", true),
                el.type === "text" ? (openBlock(), createElementBlock("text", {
                  key: 13,
                  x: el.x,
                  y: el.y,
                  fill: el.fill ?? "var(--grafana-text)",
                  "font-size": el.fontSize ?? 5
                }, toDisplayString(el.text), 9, _hoisted_61$1)) : createCommentVNode("v-if", true),
                __props.editable && isSelected(el.id) && el.type !== "text" && el.type !== "metric" ? (openBlock(), createElementBlock("rect", {
                  key: 14,
                  x: handlePos(el).x - 1.5,
                  y: handlePos(el).y - 1.5,
                  width: "3",
                  height: "3",
                  fill: "var(--grafana-input-bg)",
                  stroke: "var(--grafana-primary)",
                  "stroke-width": "0.4",
                  "data-testid": "canvas-resize-handle",
                  style: { "cursor": "nwse-resize" },
                  onPointerdown: withModifiers(($event) => onResizeDown($event, hit(el)), ["stop"])
                }, null, 40, _hoisted_62$1)) : createCommentVNode("v-if", true)
              ], 40, _hoisted_46$1);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 44, _hoisted_38$2))
      ], 8, _hoisted_1$1J);
    };
  }
});
const CanvasEditor = /* @__PURE__ */ _export_sfc(_sfc_main$2n, [["__scopeId", "data-v-8a4b95ef"]]);
const _hoisted_1$1I = ["data-show-advanced-types", "data-tooltip-disable-one-click", "data-direction", "data-radius", "data-border-radius"];
const _sfc_main$2m = /* @__PURE__ */ defineComponent({
  __name: "CanvasRenderer",
  props: {
    data: {},
    options: {},
    width: {},
    height: {},
    editable: { type: Boolean }
  },
  emits: ["options-change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const metricValue = computed(() => {
      const frame = props.data?.series?.[0];
      const field = frame?.fields.find((f) => f.type === "number");
      return field?.values?.slice(-1)[0];
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-canvas",
        "data-testid": "panel-canvas",
        "data-show-advanced-types": String(!!__props.options?.showAdvancedTypes),
        "data-tooltip-disable-one-click": String(!!(__props.options?.tooltip?.disableForOneClick ?? __props.options?.["tooltip.disableForOneClick"])),
        "data-direction": String(__props.options?.direction ?? ""),
        "data-radius": String(__props.options?.radius ?? __props.options?.border?.radius ?? ""),
        "data-border-radius": String(__props.options?.border?.radius ?? "")
      }, [
        createVNode(CanvasEditor, {
          options: __props.options,
          "metric-value": metricValue.value,
          editable: __props.editable,
          width: __props.width,
          height: __props.height,
          onChange: _cache[0] || (_cache[0] = ($event) => emit("options-change", $event))
        }, null, 8, ["options", "metric-value", "editable", "width", "height"])
      ], 8, _hoisted_1$1I);
    };
  }
});
const CanvasRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2m, [["__scopeId", "data-v-1895d590"]]);
const _sfc_main$2l = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  emits: ["options-change"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    const props = __props;
    const editable = computed(
      () => props.editable !== false && props.options?.inlineEditing !== false
    );
    return (_ctx, _cache) => {
      return openBlock(), createBlock(CanvasRenderer, {
        data: __props.data,
        options: __props.options,
        width: __props.width,
        height: __props.height,
        editable: editable.value,
        onOptionsChange: _cache[0] || (_cache[0] = ($event) => emit("options-change", $event))
      }, null, 8, ["data", "options", "width", "height", "editable"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "canvas",
    name: "画布",
    description: "自由布局可视化画布",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2l
).useFieldConfig().setNoPadding().setPanelOptions((builder) => {
  const cat = ["画布"];
  const tip = ["提示"];
  const el = ["元素"];
  builder.addBoolean(
    {
      id: "inlineEditing",
      path: "inlineEditing",
      name: "内联编辑",
      description: "直接在面板中编辑",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showAdvancedTypes",
      path: "showAdvancedTypes",
      name: "实验性元素类型",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "panZoom",
      path: "panZoom",
      name: "平移与缩放",
      category: cat
    },
    false
  ).addCustom({
    id: "panZoomHelp",
    path: "panZoomHelp",
    name: "平移缩放帮助",
    category: cat,
    editor: "text",
    showIf: (c) => !!c.panZoom
  }).addBoolean(
    {
      id: "zoomToContent",
      path: "zoomToContent",
      name: "缩放至内容",
      category: cat,
      showIf: (c) => !!c.panZoom
    },
    false
  ).addRadio(
    {
      id: "tooltip.mode",
      path: "tooltip.mode",
      name: "提示模式",
      category: tip,
      settings: {
        options: [
          { label: "启用", value: "single" },
          { label: "禁用", value: "none" }
        ]
      }
    },
    "single"
  ).addBoolean(
    {
      id: "tooltip.disableForOneClick",
      path: "tooltip.disableForOneClick",
      name: "单击元素禁用提示",
      category: tip,
      showIf: (c) => c.tooltip?.mode !== "none"
    },
    false
  ).addCustom({
    id: "root",
    path: "root",
    name: "根场景",
    category: el,
    editor: "text"
  }).addCustom({
    id: "type",
    path: "type",
    name: "元素类型",
    category: el,
    editor: "select",
    settings: {
      options: [
        { label: "矩形", value: "rectangle" },
        { label: "文本", value: "text" },
        { label: "指标", value: "metric-value" },
        { label: "图标", value: "icon" },
        { label: "椭圆", value: "ellipse" },
        { label: "服务器", value: "server" }
      ]
    }
  }).addText(
    { id: "color", path: "color", name: "颜色", category: el },
    void 0
  ).addNumber(
    { id: "size", path: "size", name: "尺寸", category: el },
    void 0
  ).addNumber(
    { id: "radius", path: "radius", name: "半径", category: el },
    void 0
  ).addSelect(
    {
      id: "direction",
      path: "direction",
      name: "方向",
      category: el,
      settings: {
        options: [
          { label: "水平", value: "horizontal" },
          { label: "垂直", value: "vertical" }
        ]
      }
    },
    void 0
  ).addSelect(
    {
      id: "lineStyle",
      path: "lineStyle",
      name: "线型",
      category: el,
      settings: {
        options: [
          { label: "实线", value: "solid" },
          { label: "虚线", value: "dashed" },
          { label: "点线", value: "dotted" }
        ]
      }
    },
    void 0
  ).addCustom({
    id: "links",
    path: "links",
    name: "链接",
    category: el,
    editor: "links"
  }).addCustom({
    id: "actions",
    path: "actions",
    name: "动作",
    category: el,
    editor: "text"
  }).addColor(
    {
      id: "background.color",
      path: "background.color",
      name: "背景色",
      category: el
    },
    void 0
  ).addText(
    {
      id: "background.image",
      path: "background.image",
      name: "背景图",
      category: el
    },
    void 0
  ).addSelect(
    {
      id: "background.size",
      path: "background.size",
      name: "背景尺寸",
      category: el,
      settings: {
        options: [
          { label: "覆盖", value: "cover" },
          { label: "包含", value: "contain" },
          { label: "原始", value: "original" },
          { label: "平铺", value: "tile" }
        ]
      }
    },
    void 0
  ).addColor(
    {
      id: "border.color",
      path: "border.color",
      name: "边框色",
      category: el
    },
    void 0
  ).addNumber(
    {
      id: "border.width",
      path: "border.width",
      name: "边框宽",
      category: el
    },
    void 0
  ).addNumber(
    {
      id: "border.radius",
      path: "border.radius",
      name: "边框圆角",
      category: el
    },
    void 0
  );
}).setRuntimeConsumedPaths([
  "inlineEditing",
  "showAdvancedTypes",
  "panZoom",
  "panZoomHelp",
  "zoomToContent",
  "tooltip.mode",
  "tooltip.disableForOneClick",
  "root",
  "type",
  "color",
  "size",
  "radius",
  "direction",
  "lineStyle",
  "links",
  "actions",
  "background.color",
  "background.image",
  "background.size",
  "border.color",
  "border.width",
  "border.radius"
]).setOptionsEditor(CanvasEditor).register();
function validateTraceFields(fields) {
  const names = fields.map((f) => f.name);
  const has = (re) => names.some((n) => re.test(n));
  const missing = [];
  if (!has(/spanID|spanId|span_id/i)) missing.push("spanId");
  if (!has(/startTime|startTimeUnixNano|start_time|start/i) && !fields.some((f) => f.type === "time")) {
    missing.push("startTime");
  }
  if (!has(/duration|durationNano|duration_ms|dur/i)) missing.push("duration");
  if (missing.length) {
    return {
      code: "INVALID_TRACE_SCHEMA",
      message: `链路数据缺少必要字段: ${missing.join(", ")}`,
      missing
    };
  }
  return null;
}
function framesToTraceSpans(fields) {
  if (!fields.length) return [];
  const n = fields[0]?.values.length ?? 0;
  if (!n) return [];
  const by = (re) => fields.find((f) => re.test(f.name));
  const spanIdF = by(/spanID|spanId|span_id/i);
  if (!spanIdF) return [];
  const schemaErr = validateTraceFields(fields);
  if (schemaErr) return [];
  const nameF = by(/operation|name|spanName/i) ?? fields.find((f) => f.type === "string");
  const serviceF = by(/service/i);
  const startF = by(/startTimeUnixNano|startTime|start/i) ?? fields.find((f) => f.type === "time" || f.type === "number");
  const durF = by(/duration|dur/i) ?? fields.find((f) => f.type === "number" && f !== startF);
  const parentF = by(/parentSpanID|parentSpanId|parent/i);
  const statusF = by(/status|statusCode/i);
  const tagsF = by(/tags|attributes|process\.tags/i);
  const processF = by(/^process$|process\./i);
  const logsF = by(/logs|events/i);
  const spans = [];
  for (let i = 0; i < n; i++) {
    let start = Number(startF?.values[i] ?? i * 10);
    if (start > 1e15) start = start / 1e6;
    else if (start > 1e14) start = start / 1e3;
    let duration = Number(durF?.values[i] ?? 20);
    if (duration > 1e9) duration = duration / 1e6;
    let tags;
    const rawTags = tagsF?.values[i];
    if (rawTags && typeof rawTags === "object" && !Array.isArray(rawTags)) {
      tags = Object.fromEntries(
        Object.entries(rawTags).map(([k, v]) => [k, String(v)])
      );
    } else if (typeof rawTags === "string" && rawTags.trim().startsWith("{")) {
      try {
        tags = Object.fromEntries(
          Object.entries(JSON.parse(rawTags)).map(([k, v]) => [k, String(v)])
        );
      } catch {
        tags = { raw: rawTags };
      }
    }
    let process2;
    const rawProc = processF?.values[i];
    if (rawProc && typeof rawProc === "object" && !Array.isArray(rawProc)) {
      process2 = Object.fromEntries(
        Object.entries(rawProc).map(([k, v]) => [k, String(v)])
      );
    }
    let logs;
    const rawLogs = logsF?.values[i];
    if (Array.isArray(rawLogs)) {
      logs = rawLogs.map((l, li) => ({
        timestamp: Number(l?.timestamp ?? l?.ts ?? li),
        fields: l?.fields && typeof l.fields === "object" ? Object.fromEntries(
          Object.entries(l.fields).map(([k, v]) => [k, String(v)])
        ) : { event: String(l?.event ?? l ?? "") }
      }));
    }
    spans.push({
      spanId: String(spanIdF?.values[i] ?? i),
      parentSpanId: parentF?.values[i] != null ? String(parentF.values[i]) : void 0,
      name: String(nameF?.values[i] ?? `span-${i}`),
      service: String(serviceF?.values[i] ?? "service"),
      start,
      duration,
      depth: 0,
      status: statusF ? String(statusF.values[i]) : void 0,
      tags,
      process: process2,
      logs,
      logsCount: logs?.length
    });
  }
  const hasParentField = !!parentF;
  const indexed = indexTraceHierarchy(spans, { allowDepthHeuristic: !hasParentField });
  return indexed.ordered;
}
function indexTraceHierarchy(spans, opts = {}) {
  const diagnostics = [];
  const byId2 = /* @__PURE__ */ new Map();
  for (const s of spans) {
    if (byId2.has(s.spanId)) {
      diagnostics.push({
        code: "DUPLICATE_SPAN",
        message: `duplicate spanId ${s.spanId}`,
        spanId: s.spanId
      });
      continue;
    }
    byId2.set(s.spanId, s);
  }
  const children = /* @__PURE__ */ new Map();
  const pushChild = (parent, s) => {
    const list = children.get(parent);
    if (list) list.push(s);
    else children.set(parent, [s]);
  };
  for (const s of byId2.values()) {
    const rawParent = s.parentSpanId != null && String(s.parentSpanId) !== "" ? String(s.parentSpanId) : null;
    if (rawParent && !byId2.has(rawParent)) {
      diagnostics.push({
        code: "ORPHAN_SPAN",
        message: `orphan span ${s.spanId}: missing parent ${rawParent}`,
        spanId: s.spanId
      });
      pushChild(null, s);
      continue;
    }
    if (rawParent === s.spanId) {
      diagnostics.push({
        code: "CYCLE",
        message: `self-parent cycle on ${s.spanId}`,
        spanId: s.spanId
      });
      pushChild(null, s);
      continue;
    }
    pushChild(rawParent, s);
  }
  for (const list of children.values()) {
    list.sort(
      (a, b) => a.start - b.start || a.spanId.localeCompare(b.spanId)
    );
  }
  const ordered = [];
  const visiting = /* @__PURE__ */ new Set();
  const visited = /* @__PURE__ */ new Set();
  function dfs(parent, depth) {
    const kids = children.get(parent) ?? [];
    for (const s of kids) {
      if (visiting.has(s.spanId)) {
        diagnostics.push({
          code: "CYCLE",
          message: `cycle detected at ${s.spanId}`,
          spanId: s.spanId
        });
        continue;
      }
      if (visited.has(s.spanId)) continue;
      visiting.add(s.spanId);
      s.depth = depth;
      ordered.push(s);
      visited.add(s.spanId);
      dfs(s.spanId, depth + 1);
      visiting.delete(s.spanId);
    }
  }
  dfs(null, 0);
  for (const s of byId2.values()) {
    if (!visited.has(s.spanId)) {
      diagnostics.push({
        code: "UNREACHABLE_SPAN",
        message: `unreachable span ${s.spanId}`,
        spanId: s.spanId
      });
      s.depth = 0;
      ordered.push(s);
      visited.add(s.spanId);
    }
  }
  if (opts.allowDepthHeuristic && ordered.length > 1 && ordered.every((s) => s.depth === 0)) {
    ordered.forEach((s, i) => {
      s.depth = i === 0 ? 0 : 1 + i % 3;
    });
  }
  return { byId: byId2, children, ordered, diagnostics };
}
function spanTimeBounds(spans) {
  if (!spans.length) return { rootStart: 0, end: 0, duration: 0 };
  let rootStart = spans[0].start;
  let end = spans[0].start + spans[0].duration;
  for (let i = 1; i < spans.length; i++) {
    const s = spans[i];
    if (s.start < rootStart) rootStart = s.start;
    const e = s.start + s.duration;
    if (e > end) end = e;
  }
  return { rootStart, end, duration: Math.max(0, end - rootStart) };
}
function normalizeTracePanelFrames(frames) {
  const diagnostics = [];
  const allSpans = [];
  for (const frame of frames || []) {
    const fields = (frame.fields || []).map((f) => ({
      name: f.name,
      type: f.type,
      values: f.values
    }));
    const err = validateTraceFields(fields);
    if (err) {
      diagnostics.push({ code: err.code, message: err.message });
      continue;
    }
    const spans2 = framesToTraceSpans(fields);
    if (!spans2.length && fields.length) {
      diagnostics.push({
        code: "INVALID_RESPONSE",
        message: "trace frame produced zero spans after strict parse"
      });
      continue;
    }
    for (const s of spans2) {
      if (!s.spanId) {
        throw new Error("INVALID_RESPONSE: span missing spanId");
      }
      if (!Number.isFinite(s.start) || !Number.isFinite(s.duration)) {
        throw new Error("INVALID_RESPONSE: span missing start or duration");
      }
      allSpans.push(s);
    }
  }
  if (!allSpans.length) {
    if (diagnostics.length) {
      const e = new Error(
        `INVALID_RESPONSE: ${diagnostics.map((d) => d.message).join("; ")}`
      );
      e.code = "INVALID_RESPONSE";
      throw e;
    }
    return { spans: [], rootStart: 0, duration: 0, diagnostics };
  }
  const bounds = spanTimeBounds(allSpans);
  const rootStart = bounds.rootStart;
  const spans = allSpans.map((s) => ({
    ...s,
    // trace-relative offset
    offsetMs: Math.round(s.start - rootStart)
  }));
  return {
    spans,
    rootStart,
    duration: bounds.duration,
    diagnostics
  };
}
function useVirtualTraceRows(total, scrollTop, viewportHeight, rowHeight = 28, overscan = 12) {
  const win = computeVirtualWindow(total, scrollTop, viewportHeight, rowHeight, overscan);
  return {
    ...win,
    slice: (rows) => sliceVirtualRows(rows, win)
  };
}
const _hoisted_1$1H = {
  key: 0,
  class: "panel-empty",
  "data-testid": "traces-panel-empty"
};
const _hoisted_2$1i = ["data-filters", "data-critical-path", "data-matches-only", "data-span-count", "data-show-service", "data-detail-open", "data-selected-span", "data-view-mode", "data-has-service-graph", "data-service-graph-nodes", "data-virtualized", "data-row-height", "data-window-count"];
const _hoisted_3$17 = {
  key: 0,
  class: "view-tabs",
  "data-testid": "traces-view-tabs"
};
const _hoisted_4$Y = {
  key: 1,
  class: "svc-graph",
  "data-testid": "traces-service-graph"
};
const _hoisted_5$Q = {
  viewBox: "0 0 100 90",
  class: "svc-svg",
  role: "img",
  "aria-label": "服务拓扑图"
};
const _hoisted_6$K = ["x1", "y1", "x2", "y2"];
const _hoisted_7$I = ["onClick"];
const _hoisted_8$A = ["cx", "cy", "fill"];
const _hoisted_9$y = ["x", "y"];
const _hoisted_10$s = {
  key: 0,
  class: "svc-detail",
  "data-testid": "traces-service-detail"
};
const _hoisted_11$n = { key: 0 };
const _hoisted_12$h = {
  key: 0,
  class: "legend",
  "data-testid": "traces-legend"
};
const _hoisted_13$h = { class: "TimelineHeaderRow" };
const _hoisted_14$f = { class: "header-view" };
const _hoisted_15$b = { class: "Ticks" };
const _hoisted_16$a = ["data-row-index", "data-selected", "aria-rowindex", "onClick"];
const _hoisted_17$9 = { class: "nameColumn" };
const _hoisted_18$9 = { class: "SpanTreeOffset" };
const _hoisted_19$9 = { class: "endpointName" };
const _hoisted_20$8 = { class: "view" };
const _hoisted_21$7 = { class: "Ticks ticks-abs" };
const _hoisted_22$6 = { class: "spanBarWrapper" };
const _hoisted_23$4 = {
  key: 3,
  class: "empty",
  "data-testid": "traces-empty"
};
const _hoisted_24$4 = {
  key: 4,
  class: "empty",
  "data-testid": "traces-empty-fallback"
};
const _hoisted_25$4 = {
  key: 0,
  class: "detail",
  "data-testid": "traces-detail"
};
const _hoisted_26$4 = { class: "detail-head" };
const _hoisted_27$3 = { class: "endpointName" };
const _hoisted_28$3 = { class: "detail-meta" };
const _hoisted_29$3 = { key: 0 };
const _hoisted_30$3 = {
  class: "tabs",
  "data-testid": "traces-detail-tabs"
};
const _hoisted_31$3 = {
  key: 0,
  class: "kv",
  "data-testid": "traces-tags"
};
const _hoisted_32$3 = {
  key: 0,
  class: "empty-cell"
};
const _hoisted_33$3 = {
  key: 1,
  class: "proc",
  "data-testid": "traces-process"
};
const _hoisted_34$3 = { key: 0 };
const _hoisted_35$2 = {
  key: 2,
  class: "logs-tl",
  "data-testid": "traces-logs"
};
const _hoisted_36$1 = { class: "log-ts" };
const _hoisted_37$1 = { class: "log-fields" };
const _hoisted_38$1 = {
  key: 0,
  class: "empty-cell"
};
const TRACE_ROW_H = 28;
const _sfc_main$2k = /* @__PURE__ */ defineComponent({
  __name: "TracesRenderer",
  props: {
    data: {},
    options: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const filtersOpt = computed(() => opts.value.filters ?? opts.value.spanFilters ?? null);
    const selected = ref(null);
    function isNodeGraphFrame(f) {
      const name = String(f?.name ?? "");
      if (/^(nodes?|edges?)$/i.test(name)) return true;
      if (f?.meta?.preferredVisualisationType === "nodeGraph") return true;
      const names = (Array.isArray(f?.fields) ? f.fields : []).map(
        (fld) => String(fld?.name ?? "").toLowerCase()
      );
      const hasFromTo = names.some((n) => n === "source" || n === "from") && names.some((n) => n === "target" || n === "to");
      const hasIdTitle = names.includes("id") && names.some((n) => n === "title" || n === "mainstat");
      return hasFromTo || hasIdTitle;
    }
    function isTraceFrame(f) {
      if (!f || isNodeGraphFrame(f)) return false;
      const names = (Array.isArray(f?.fields) ? f.fields : []).map(
        (fld) => String(fld?.name ?? "").toLowerCase()
      );
      return names.some(
        (n) => /spanid|span_id|duration|starttime|operationname|servicename/.test(n)
      );
    }
    const allSpans = computed(() => {
      const series = props.data?.series ?? [];
      if (series.length && series.every(isNodeGraphFrame)) {
        return [];
      }
      const frames = series.filter((f) => isTraceFrame(f) || !isNodeGraphFrame(f));
      if (!frames.length) return [];
      try {
        const norm = normalizeTracePanelFrames(frames);
        return norm.spans.map((s) => ({
          ...s,
          start: Number.isFinite(s.offsetMs) ? s.offsetMs : s.start - norm.rootStart
        }));
      } catch {
        return [];
      }
    });
    const spans = computed(() => {
      let list = allSpans.value;
      const f = opts.value.spanFilters ?? {};
      if (f.criticalPathOnly) {
        let walk = function(parent) {
          const kids = byParent.get(parent) ?? [];
          if (!kids.length) return;
          const best = [...kids].sort((a, b) => b.duration - a.duration)[0];
          keep.add(best.spanId);
          walk(best.spanId);
        };
        const byParent = /* @__PURE__ */ new Map();
        for (const s of list) {
          const k = s.parentSpanId;
          if (!byParent.has(k)) byParent.set(k, []);
          byParent.get(k).push(s);
        }
        const keep = /* @__PURE__ */ new Set();
        walk(void 0);
        for (const s of list) {
          if (!s.parentSpanId) keep.add(s.spanId);
        }
        list = list.filter((s) => keep.has(s.spanId));
      }
      if (f.matchesOnly && f.serviceName) {
        const svc = String(f.serviceName).toLowerCase();
        list = list.filter((s) => s.service.toLowerCase().includes(svc));
      }
      if (f.matchesOnly && f.spanName) {
        const n = String(f.spanName).toLowerCase();
        list = list.filter((s) => s.name.toLowerCase().includes(n));
      }
      if (f.minDuration != null && f.minDuration !== "") {
        const min = Number(f.minDuration);
        if (Number.isFinite(min)) list = list.filter((s) => s.duration >= min);
      }
      return list;
    });
    const maxEnd = computed(() => {
      const b = spanTimeBounds(spans.value);
      return Math.max(1, b.end || 1);
    });
    const services = computed(() => {
      const set = /* @__PURE__ */ new Set();
      for (const s of spans.value) set.add(s.service);
      return Array.from(set);
    });
    const scrollTop = ref(0);
    const viewportH = ref(360);
    const scrollEl = ref(null);
    const virt = computed(
      () => useVirtualTraceRows(
        spans.value.length,
        scrollTop.value,
        viewportH.value,
        TRACE_ROW_H,
        12
      )
    );
    const visibleSpans = computed(() => virt.value.slice(spans.value));
    function onTraceScroll(e) {
      const el = e.target;
      scrollTop.value = el.scrollTop;
      viewportH.value = el.clientHeight || viewportH.value;
    }
    function measureTraceViewport() {
      const el = scrollEl.value;
      if (!el) return;
      viewportH.value = el.clientHeight || viewportH.value;
    }
    function scrollSelectedIntoView(id) {
      if (!id) return;
      const idx = spans.value.findIndex((s) => s.spanId === id);
      if (idx < 0) return;
      const el = scrollEl.value;
      if (!el) {
        scrollTop.value = Math.max(0, idx * TRACE_ROW_H - viewportH.value / 3);
        return;
      }
      const top = idx * TRACE_ROW_H;
      const bottom = top + TRACE_ROW_H;
      if (top < el.scrollTop) {
        el.scrollTop = top;
      } else if (bottom > el.scrollTop + el.clientHeight) {
        el.scrollTop = bottom - el.clientHeight;
      }
      scrollTop.value = el.scrollTop;
      viewportH.value = el.clientHeight || viewportH.value;
    }
    watch(selected, (id) => {
      void nextTick(() => scrollSelectedIntoView(id));
    });
    watch(
      () => spans.value.length,
      () => {
        void nextTick(measureTraceViewport);
      }
    );
    let _ro = null;
    onMounted(() => {
      void nextTick(() => {
        measureTraceViewport();
        if (typeof ResizeObserver !== "undefined" && scrollEl.value) {
          _ro = new ResizeObserver(() => measureTraceViewport());
          _ro.observe(scrollEl.value);
        }
      });
    });
    onBeforeUnmount(() => {
      _ro?.disconnect();
      _ro = null;
    });
    function hasNodeGraphFrames(series) {
      if (!series?.length) return false;
      return series.some((f) => {
        const name = String(f?.name ?? "");
        if (/node|edge/i.test(name)) return true;
        if (f?.meta?.preferredVisualisationType === "nodeGraph") return true;
        const fields = Array.isArray(f?.fields) ? f.fields : [];
        const names = fields.map(
          (fld) => String(fld?.name ?? "").toLowerCase()
        );
        const hasId = names.some((n) => n === "id" || n.endsWith(" id"));
        const hasFromTo = names.some(
          (n) => n === "source" || n === "from" || n.endsWith("source")
        ) && names.some(
          (n) => n === "target" || n === "to" || n.endsWith("target")
        );
        return hasId || hasFromTo;
      });
    }
    const hasServiceGraph = computed(
      () => hasNodeGraphFrames(props.data?.series)
    );
    const serviceGraph = computed(() => {
      if (!hasServiceGraph.value)
        return { nodes: [], edges: [] };
      return layoutGraph(framesToGraph(props.data?.series), "force");
    });
    const graphById = computed(
      () => new Map(serviceGraph.value.nodes.map((n) => [n.id, n]))
    );
    const selectedNode = ref(null);
    const viewMode = ref("waterfall");
    watch(
      () => ({ spans: allSpans.value.length, graph: hasServiceGraph.value }),
      ({ spans: spans2, graph }) => {
        if (!spans2 && graph) viewMode.value = "serviceGraph";
        if (spans2 && !graph) viewMode.value = "waterfall";
      },
      { immediate: true }
    );
    function selectNode(n) {
      selectedNode.value = selectedNode.value?.id === n.id ? null : n;
    }
    const noTraceData = computed(
      () => !allSpans.value.length && !hasServiceGraph.value
    );
    const showServiceName = computed(() => opts.value.showServiceName !== false);
    const showDuration = computed(() => opts.value.showDuration !== false);
    const selectedSpan = computed(() => {
      if (!selected.value) return null;
      return allSpans.value.find((s) => s.spanId === selected.value) ?? spans.value.find((s) => s.spanId === selected.value) ?? null;
    });
    const selectedTags = computed(() => {
      const s = selectedSpan.value;
      if (!s) return [];
      const base = {
        spanID: s.spanId,
        ...s.parentSpanId ? { parentSpanID: s.parentSpanId } : {},
        service: s.service,
        operation: s.name,
        duration: `${Math.round(s.duration)}ms`,
        start: `${Math.round(s.start)}ms`,
        ...s.status ? { status: s.status } : {},
        ...s.tags ?? {}
      };
      return Object.entries(base);
    });
    const processEntries = computed(() => {
      const s = selectedSpan.value;
      if (!s?.process) return [];
      return Object.entries(s.process);
    });
    const logEntries = computed(() => {
      const s = selectedSpan.value;
      return s?.logs ?? [];
    });
    const detailTab = ref("tags");
    watch(selected, () => {
      detailTab.value = "tags";
    });
    function serviceColor(name) {
      return classicColorForKey(name);
    }
    const timeTicks = computed(() => {
      const end = maxEnd.value || 1;
      const steps = 5;
      return Array.from({ length: steps + 1 }, (_, i) => {
        const t2 = end * i / steps;
        return {
          pct: i / steps * 100,
          label: t2 >= 1e3 ? `${(t2 / 1e3).toFixed(t2 >= 1e4 ? 0 : 1)}s` : `${Math.round(t2)}ms`
        };
      });
    });
    function formatDur(ms) {
      if (!Number.isFinite(ms)) return "—";
      if (ms >= 1e3) return `${(ms / 1e3).toFixed(ms >= 1e4 ? 1 : 2)}s`;
      if (ms < 1) return `${ms.toFixed(2)}ms`;
      return `${Math.round(ms)}ms`;
    }
    function onTraceKeydown(e) {
      if (!spans.value.length) return;
      const list = spans.value;
      const idx = selected.value ? list.findIndex((s) => s.spanId === selected.value) : -1;
      if (e.key === "Escape") {
        selected.value = null;
        e.preventDefault();
        return;
      }
      if (e.key === "ArrowDown") {
        const next = idx < 0 ? 0 : Math.min(list.length - 1, idx + 1);
        selected.value = list[next]?.spanId ?? null;
        e.preventDefault();
      } else if (e.key === "ArrowUp") {
        const next = idx < 0 ? 0 : Math.max(0, idx - 1);
        selected.value = list[next]?.spanId ?? null;
        e.preventDefault();
      } else if (e.key === "Enter" && idx >= 0) {
        e.preventDefault();
      }
    }
    function selectSpan(id) {
      selected.value = selected.value === id ? null : id;
    }
    return (_ctx, _cache) => {
      return noTraceData.value ? (openBlock(), createElementBlock("div", _hoisted_1$1H, [..._cache[6] || (_cache[6] = [
        createElementVNode(
          "p",
          { class: "panel-empty__msg" },
          "回复中未找到数据",
          -1
          /* CACHED */
        )
      ])])) : (openBlock(), createElementBlock("div", {
        key: 1,
        class: "traces",
        "data-testid": "panel-traces",
        "data-filters": String(
          filtersOpt.value == null || filtersOpt.value === "" ? "" : typeof filtersOpt.value === "string" ? filtersOpt.value : JSON.stringify(filtersOpt.value)
        ),
        tabindex: "0",
        role: "region",
        "data-critical-path": String(!!opts.value.spanFilters?.criticalPathOnly),
        "data-matches-only": String(!!opts.value.spanFilters?.matchesOnly),
        "data-span-count": String(spans.value.length),
        "data-show-service": String(showServiceName.value),
        "data-detail-open": String(!!selectedSpan.value),
        "data-selected-span": selected.value ?? "",
        "data-view-mode": viewMode.value,
        "data-has-service-graph": String(hasServiceGraph.value),
        "data-service-graph-nodes": String(serviceGraph.value.nodes.length),
        "data-virtualized": String(spans.value.length > 0),
        "data-row-height": String(TRACE_ROW_H),
        "data-window-count": String(virt.value.visibleCount),
        onKeydown: onTraceKeydown
      }, [
        createElementVNode(
          "div",
          {
            class: normalizeClass(["wrapper", { "is-empty": !spans.value.length && viewMode.value === "waterfall" }])
          },
          [
            hasServiceGraph.value && spans.value.length ? (openBlock(), createElementBlock("div", _hoisted_3$17, [
              createElementVNode(
                "button",
                {
                  type: "button",
                  class: normalizeClass({ on: viewMode.value === "waterfall" }),
                  "data-testid": "traces-view-waterfall",
                  onClick: _cache[0] || (_cache[0] = ($event) => viewMode.value = "waterfall")
                },
                " 瀑布图 ",
                2
                /* CLASS */
              ),
              createElementVNode(
                "button",
                {
                  type: "button",
                  class: normalizeClass({ on: viewMode.value === "serviceGraph" }),
                  "data-testid": "traces-view-service-graph",
                  onClick: _cache[1] || (_cache[1] = ($event) => viewMode.value = "serviceGraph")
                },
                " 服务图 ",
                2
                /* CLASS */
              )
            ])) : createCommentVNode("v-if", true),
            viewMode.value === "serviceGraph" && hasServiceGraph.value ? (openBlock(), createElementBlock("div", _hoisted_4$Y, [
              (openBlock(), createElementBlock("svg", _hoisted_5$Q, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(serviceGraph.value.edges, (e, i) => {
                    return openBlock(), createElementBlock("line", {
                      key: "e" + i,
                      x1: graphById.value.get(e.from)?.x ?? 0,
                      y1: graphById.value.get(e.from)?.y ?? 0,
                      x2: graphById.value.get(e.to)?.x ?? 0,
                      y2: graphById.value.get(e.to)?.y ?? 0,
                      class: "svc-edge"
                    }, null, 8, _hoisted_6$K);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                )),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(serviceGraph.value.nodes, (n) => {
                    return openBlock(), createElementBlock("g", {
                      key: n.id,
                      class: normalizeClass(["svc-node", { on: selectedNode.value?.id === n.id }]),
                      "data-testid": "traces-service-node",
                      onClick: ($event) => selectNode(n)
                    }, [
                      createElementVNode("circle", {
                        cx: n.x,
                        cy: n.y,
                        r: "5",
                        fill: serviceColor(n.label || n.id)
                      }, null, 8, _hoisted_8$A),
                      createElementVNode("text", {
                        x: n.x,
                        y: (n.y ?? 0) + 9,
                        "text-anchor": "middle",
                        class: "svc-label"
                      }, toDisplayString(n.label || n.id), 9, _hoisted_9$y)
                    ], 10, _hoisted_7$I);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])),
              selectedNode.value ? (openBlock(), createElementBlock("div", _hoisted_10$s, [
                createElementVNode(
                  "strong",
                  null,
                  toDisplayString(selectedNode.value.label || selectedNode.value.id),
                  1
                  /* TEXT */
                ),
                selectedNode.value.mainStat != null ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_11$n,
                  " · " + toDisplayString(selectedNode.value.mainStat),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ])) : createCommentVNode("v-if", true)
            ])) : spans.value.length ? (openBlock(), createElementBlock(
              Fragment,
              { key: 2 },
              [
                showServiceName.value ? (openBlock(), createElementBlock("div", _hoisted_12$h, [
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(services.value, (s) => {
                      return openBlock(), createElementBlock("span", {
                        key: s,
                        class: "chip"
                      }, [
                        createElementVNode(
                          "i",
                          {
                            class: "dot",
                            style: normalizeStyle({ background: serviceColor(s) })
                          },
                          null,
                          4
                          /* STYLE */
                        ),
                        createTextVNode(
                          toDisplayString(s),
                          1
                          /* TEXT */
                        )
                      ]);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ])) : createCommentVNode("v-if", true),
                createCommentVNode(" TimelineHeaderRow "),
                createElementVNode("div", _hoisted_13$h, [
                  _cache[7] || (_cache[7] = createElementVNode(
                    "div",
                    { class: "header-name" },
                    "Service & Operation",
                    -1
                    /* CACHED */
                  )),
                  createElementVNode("div", _hoisted_14$f, [
                    createElementVNode("div", _hoisted_15$b, [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(timeTicks.value, (tk, i) => {
                          return openBlock(), createElementBlock(
                            "div",
                            {
                              key: i,
                              class: "TicksTick",
                              style: normalizeStyle({ left: tk.pct + "%" })
                            },
                            [
                              createElementVNode(
                                "span",
                                {
                                  class: normalizeClass(["TicksTickLabel", { end: i === timeTicks.value.length - 1 }])
                                },
                                toDisplayString(tk.label),
                                3
                                /* TEXT, CLASS */
                              )
                            ],
                            4
                            /* STYLE */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])
                  ])
                ]),
                createCommentVNode(" SpanBarRows (windowed) "),
                createElementVNode(
                  "div",
                  {
                    ref_key: "scrollEl",
                    ref: scrollEl,
                    class: "VirtualizedTraceView",
                    "data-testid": "traces-virtual-scroll",
                    onScrollPassive: onTraceScroll
                  },
                  [
                    createElementVNode(
                      "div",
                      {
                        class: "trace-virt-spacer",
                        style: normalizeStyle({ height: virt.value.totalHeight + "px", position: "relative" })
                      },
                      [
                        createElementVNode(
                          "div",
                          {
                            class: "trace-virt-window",
                            style: normalizeStyle({ transform: "translateY(" + virt.value.offsetY + "px)" })
                          },
                          [
                            (openBlock(true), createElementBlock(
                              Fragment,
                              null,
                              renderList(visibleSpans.value, (s, i) => {
                                return openBlock(), createElementBlock("div", {
                                  key: s.spanId + "-" + (virt.value.start + i),
                                  class: normalizeClass(["span-row", {
                                    selected: selected.value === s.spanId,
                                    isDetailExpanded: selected.value === s.spanId,
                                    error: s.status === "ERROR" || s.status === "2"
                                  }]),
                                  "data-testid": "trace-span",
                                  "data-row-index": String(virt.value.start + i),
                                  "data-selected": selected.value === s.spanId ? "true" : "false",
                                  "aria-rowindex": virt.value.start + i + 1,
                                  onClick: ($event) => selectSpan(s.spanId)
                                }, [
                                  createElementVNode(
                                    "div",
                                    {
                                      class: "nameWrapper",
                                      style: normalizeStyle({ borderBottomColor: serviceColor(s.service || "unknown") })
                                    },
                                    [
                                      createElementVNode("div", _hoisted_17$9, [
                                        createElementVNode("span", _hoisted_18$9, [
                                          (openBlock(true), createElementBlock(
                                            Fragment,
                                            null,
                                            renderList(s.depth, (d) => {
                                              return openBlock(), createElementBlock("span", {
                                                key: d,
                                                class: "SpanTreeOffset--indentGuide"
                                              });
                                            }),
                                            128
                                            /* KEYED_FRAGMENT */
                                          ))
                                        ]),
                                        createElementVNode(
                                          "button",
                                          {
                                            type: "button",
                                            class: "name",
                                            style: normalizeStyle({ borderBottomColor: serviceColor(s.service || "unknown") + "CF" })
                                          },
                                          [
                                            showServiceName.value ? (openBlock(), createElementBlock(
                                              "span",
                                              {
                                                key: 0,
                                                class: "svcName",
                                                style: normalizeStyle({ color: serviceColor(s.service || "unknown") })
                                              },
                                              toDisplayString(s.service),
                                              5
                                              /* TEXT, STYLE */
                                            )) : createCommentVNode("v-if", true),
                                            createElementVNode(
                                              "span",
                                              _hoisted_19$9,
                                              toDisplayString(s.name),
                                              1
                                              /* TEXT */
                                            )
                                          ],
                                          4
                                          /* STYLE */
                                        )
                                      ])
                                    ],
                                    4
                                    /* STYLE */
                                  ),
                                  createElementVNode("div", _hoisted_20$8, [
                                    createElementVNode("div", _hoisted_21$7, [
                                      (openBlock(true), createElementBlock(
                                        Fragment,
                                        null,
                                        renderList(timeTicks.value, (tk, ti) => {
                                          return openBlock(), createElementBlock(
                                            "div",
                                            {
                                              key: "t" + ti,
                                              class: "TicksTick",
                                              style: normalizeStyle({ left: tk.pct + "%" })
                                            },
                                            null,
                                            4
                                            /* STYLE */
                                          );
                                        }),
                                        128
                                        /* KEYED_FRAGMENT */
                                      ))
                                    ]),
                                    createCommentVNode(" SpanBar: height 40%, top 30% "),
                                    createElementVNode("div", _hoisted_22$6, [
                                      createElementVNode(
                                        "div",
                                        {
                                          class: normalizeClass(["spanBar", { error: s.status === "ERROR" || s.status === "2" }]),
                                          style: normalizeStyle({
                                            left: s.start / maxEnd.value * 100 + "%",
                                            width: Math.max(0.25, s.duration / maxEnd.value * 100) + "%",
                                            background: s.status === "ERROR" || s.status === "2" ? "var(--grafana-error)" : serviceColor(s.service || "unknown")
                                          })
                                        },
                                        null,
                                        6
                                        /* CLASS, STYLE */
                                      ),
                                      showDuration.value ? (openBlock(), createElementBlock(
                                        "div",
                                        {
                                          key: 0,
                                          class: normalizeClass(["spanBarLabel", s.start / maxEnd.value > 0.5 ? "labelLeft" : "labelRight"]),
                                          style: normalizeStyle({
                                            left: s.start / maxEnd.value > 0.5 ? s.start / maxEnd.value * 100 + "%" : s.start / maxEnd.value * 100 + Math.max(0.25, s.duration / maxEnd.value * 100) + "%"
                                          })
                                        },
                                        toDisplayString(formatDur(s.duration)),
                                        7
                                        /* TEXT, CLASS, STYLE */
                                      )) : createCommentVNode("v-if", true)
                                    ])
                                  ])
                                ], 10, _hoisted_16$a);
                              }),
                              128
                              /* KEYED_FRAGMENT */
                            ))
                          ],
                          4
                          /* STYLE */
                        )
                      ],
                      4
                      /* STYLE */
                    )
                  ],
                  544
                  /* NEED_HYDRATION, NEED_PATCH */
                )
              ],
              64
              /* STABLE_FRAGMENT */
            )) : !hasServiceGraph.value ? (openBlock(), createElementBlock("div", _hoisted_23$4, " 暂无链路数据 ")) : (openBlock(), createElementBlock("div", _hoisted_24$4, " 无瀑布图 span，已切换服务图 "))
          ],
          2
          /* CLASS */
        ),
        createCommentVNode(" Span detail (simplified SpanDetailRow) "),
        selectedSpan.value ? (openBlock(), createElementBlock("aside", _hoisted_25$4, [
          createElementVNode("header", _hoisted_26$4, [
            createElementVNode("div", null, [
              createElementVNode(
                "div",
                {
                  class: "svcName",
                  style: normalizeStyle({ color: serviceColor(selectedSpan.value.service || "unknown") })
                },
                toDisplayString(selectedSpan.value.service),
                5
                /* TEXT, STYLE */
              ),
              createElementVNode(
                "div",
                _hoisted_27$3,
                toDisplayString(selectedSpan.value.name),
                1
                /* TEXT */
              )
            ]),
            createElementVNode("button", {
              type: "button",
              "data-testid": "traces-detail-close",
              class: "close",
              onClick: _cache[2] || (_cache[2] = ($event) => selected.value = null)
            }, " × ")
          ]),
          createElementVNode("div", _hoisted_28$3, [
            createElementVNode(
              "span",
              null,
              toDisplayString(formatDur(selectedSpan.value.duration)),
              1
              /* TEXT */
            ),
            selectedSpan.value.status ? (openBlock(), createElementBlock(
              "span",
              _hoisted_29$3,
              toDisplayString(selectedSpan.value.status),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true)
          ]),
          createElementVNode("div", _hoisted_30$3, [
            createElementVNode(
              "button",
              {
                type: "button",
                class: normalizeClass({ on: detailTab.value === "tags" }),
                "data-testid": "traces-tab-tags",
                onClick: _cache[3] || (_cache[3] = ($event) => detailTab.value = "tags")
              },
              " Tags ",
              2
              /* CLASS */
            ),
            createElementVNode(
              "button",
              {
                type: "button",
                class: normalizeClass({ on: detailTab.value === "process" }),
                "data-testid": "traces-tab-process",
                onClick: _cache[4] || (_cache[4] = ($event) => detailTab.value = "process")
              },
              " Process ",
              2
              /* CLASS */
            ),
            createElementVNode(
              "button",
              {
                type: "button",
                class: normalizeClass({ on: detailTab.value === "logs" }),
                "data-testid": "traces-tab-logs",
                onClick: _cache[5] || (_cache[5] = ($event) => detailTab.value = "logs")
              },
              " Logs" + toDisplayString(logEntries.value.length ? ` (${logEntries.value.length})` : ""),
              3
              /* TEXT, CLASS */
            )
          ]),
          detailTab.value === "tags" ? (openBlock(), createElementBlock("dl", _hoisted_31$3, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(selectedTags.value, ([k, v]) => {
                return openBlock(), createElementBlock(
                  Fragment,
                  { key: k },
                  [
                    createElementVNode(
                      "dt",
                      null,
                      toDisplayString(k),
                      1
                      /* TEXT */
                    ),
                    createElementVNode(
                      "dd",
                      null,
                      toDisplayString(v),
                      1
                      /* TEXT */
                    )
                  ],
                  64
                  /* STABLE_FRAGMENT */
                );
              }),
              128
              /* KEYED_FRAGMENT */
            )),
            !selectedTags.value.length ? (openBlock(), createElementBlock("div", _hoisted_32$3, "无标签")) : createCommentVNode("v-if", true)
          ])) : detailTab.value === "process" ? (openBlock(), createElementBlock("table", _hoisted_33$3, [
            createElementVNode("tbody", null, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(processEntries.value, ([k, v]) => {
                  return openBlock(), createElementBlock("tr", { key: k }, [
                    createElementVNode(
                      "th",
                      null,
                      toDisplayString(k),
                      1
                      /* TEXT */
                    ),
                    createElementVNode(
                      "td",
                      null,
                      toDisplayString(v),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              !processEntries.value.length ? (openBlock(), createElementBlock("tr", _hoisted_34$3, [..._cache[8] || (_cache[8] = [
                createElementVNode(
                  "td",
                  {
                    colspan: "2",
                    class: "empty-cell"
                  },
                  "无进程标签",
                  -1
                  /* CACHED */
                )
              ])])) : createCommentVNode("v-if", true)
            ])
          ])) : (openBlock(), createElementBlock("div", _hoisted_35$2, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(logEntries.value, (lg, i) => {
                return openBlock(), createElementBlock("div", {
                  key: i,
                  class: "log-item",
                  "data-testid": "traces-log-item"
                }, [
                  createElementVNode(
                    "div",
                    _hoisted_36$1,
                    "+" + toDisplayString(formatDur(lg.timestamp)),
                    1
                    /* TEXT */
                  ),
                  createElementVNode("div", _hoisted_37$1, [
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(lg.fields, (v, k) => {
                        return openBlock(), createElementBlock(
                          "span",
                          {
                            key: k,
                            class: "lf"
                          },
                          toDisplayString(k) + "=" + toDisplayString(v),
                          1
                          /* TEXT */
                        );
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ])
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            )),
            !logEntries.value.length ? (openBlock(), createElementBlock("div", _hoisted_38$1, "无 Span 日志")) : createCommentVNode("v-if", true)
          ]))
        ])) : createCommentVNode("v-if", true)
      ], 40, _hoisted_2$1i));
    };
  }
});
const TracesRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2k, [["__scopeId", "data-v-5ede5faa"]]);
const _sfc_main$2j = /* @__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(TracesRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "traces",
    name: "链路追踪",
    description: "分布式追踪瀑布图",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2j
).setPanelOptions((builder) => {
  const cat = ["链路"];
  builder.addCustom({
    id: "filters",
    path: "filters",
    name: "过滤器",
    category: cat,
    editor: "text",
    description: "Span filters（Grafana 兼容 id）"
  }).addCustom({
    id: "spanFilters",
    path: "spanFilters",
    name: "过滤器对象",
    category: cat,
    editor: "text",
    description: "Span 过滤配置对象"
  }).addBoolean(
    {
      id: "spanFilters.matchesOnly",
      path: "spanFilters.matchesOnly",
      name: "仅显示匹配项",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "spanFilters.criticalPathOnly",
      path: "spanFilters.criticalPathOnly",
      name: "仅关键路径",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "showServiceName",
      path: "showServiceName",
      name: "显示服务名",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showDuration",
      path: "showDuration",
      name: "显示耗时",
      category: cat
    },
    true
  );
}).setRuntimeConsumedPaths([
  "filters",
  "spanFilters",
  "spanFilters.criticalPathOnly",
  "spanFilters.matchesOnly",
  "showServiceName",
  "showDuration"
]).register();
function normalizeFlameTree(node) {
  const kids = (node.children ?? []).map(normalizeFlameTree);
  const childSum = kids.reduce((a, b) => a + b.value, 0);
  const self = node.self ?? Math.max(0, node.value - childSum);
  const value = Math.max(node.value, childSum + self, 1);
  return {
    name: node.name,
    value,
    self,
    children: kids.length ? kids : void 0
  };
}
function checkFields(fields) {
  const list = fields ?? [];
  const required = [
    ["label", ["string", "enum"]],
    ["level", ["number"]],
    ["value", ["number"]],
    ["self", ["number"]]
  ];
  const missingFields = [];
  const wrongTypeFields = [];
  for (const [name, types] of required) {
    const frameField = list.find((f) => f.name === name);
    if (!frameField) {
      missingFields.push(name);
      continue;
    }
    const t2 = String(frameField.type || "other");
    if (!types.includes(t2)) {
      wrongTypeFields.push({ name, expectedTypes: types, type: t2 });
    }
  }
  if (missingFields.length || wrongTypeFields.length) {
    return { missingFields, wrongTypeFields };
  }
  return void 0;
}
function getMessageCheckFieldsResult(wrongFields) {
  if (wrongFields.missingFields.length) {
    return `数据缺少字段：${wrongFields.missingFields.join(", ")}`;
  }
  if (wrongFields.wrongTypeFields.length) {
    return `数据字段类型不正确：${wrongFields.wrongTypeFields.map(
      (f) => `${f.name} 类型为 ${f.type}，应为 ${f.expectedTypes.join(" 或 ")}`
    ).join("；")}`;
  }
  return "";
}
function framesToFlameRoot(fields) {
  if (!fields.length || !(fields[0]?.values?.length ?? 0)) {
    return null;
  }
  const by = (re) => fields.find((f) => re.test(f.name));
  const n = fields[0].values.length;
  const stackF = by(/stack|stacktrace|callstack/i);
  if (stackF) {
    return normalizeFlameTree(
      stacksToTree(stackF.values.map(String), valueColumn(fields, n))
    );
  }
  const nameF = by(/name|label|function|symbol|location/i) ?? fields.find((f) => f.type === "string") ?? fields[0];
  const valueF = valueField(fields, nameF);
  const parentF = by(/parent|caller|parentName|parentId/i);
  const levelF = by(/level|depth/i);
  const selfF = by(/self|exclusive/i);
  if (parentF || levelF) {
    return normalizeFlameTree(
      hierarchyToTree(
        Array.from({ length: n }, (_, i) => ({
          name: String(nameF.values[i] ?? `fn-${i}`),
          value: Math.abs(Number(valueF?.values[i] ?? 1)),
          self: selfF ? Math.abs(Number(selfF.values[i] ?? 0)) : void 0,
          parent: parentF?.values[i] != null ? String(parentF.values[i]) : void 0,
          level: levelF ? Number(levelF.values[i] ?? 0) : void 0
        }))
      )
    );
  }
  const children = [];
  for (let i = 0; i < Math.min(n, 64); i++) {
    children.push({
      name: String(nameF.values[i] ?? `fn-${i}`),
      value: Math.abs(Number(valueF?.values[i] ?? 1)),
      self: selfF ? Math.abs(Number(selfF.values[i] ?? 0)) : void 0
    });
  }
  const total = children.reduce((a, b) => a + b.value, 0) || 1;
  return normalizeFlameTree({ name: "total", value: total, self: 0, children });
}
function valueField(fields, exclude) {
  return fields.find(
    (f) => /value|total|samples|count|weight/i.test(f.name) && f !== exclude
  ) ?? fields.find((f) => f.type === "number" && f !== exclude);
}
function valueColumn(fields, n) {
  const vf = valueField(fields);
  return Array.from(
    { length: n },
    (_, i) => Math.abs(Number(vf?.values[i] ?? 1))
  );
}
function stacksToTree(stacks, values) {
  const root = { name: "total", value: 0, self: 0, children: [] };
  for (let i = 0; i < stacks.length; i++) {
    const parts = String(stacks[i]).split(/[;\n]+/).map((s) => s.trim()).filter(Boolean);
    const v = values[i] ?? 1;
    root.value += v;
    let cur = root;
    for (let d = 0; d < parts.length; d++) {
      const name = parts[d];
      if (!cur.children) cur.children = [];
      let next = cur.children.find((c) => c.name === name);
      if (!next) {
        next = { name, value: 0, self: 0, children: [] };
        cur.children.push(next);
      }
      next.value += v;
      if (d === parts.length - 1) {
        next.self = (next.self ?? 0) + v;
      }
      cur = next;
    }
  }
  if (!root.value) root.value = 1;
  return root;
}
function hierarchyToTree(rows) {
  if (rows.some((r) => r.parent != null && r.parent !== "")) {
    const byName = /* @__PURE__ */ new Map();
    for (const r of rows) {
      byName.set(r.name, {
        name: r.name,
        value: r.value,
        self: r.self,
        children: []
      });
    }
    const roots = [];
    for (const r of rows) {
      const node = byName.get(r.name);
      if (r.parent && byName.has(r.parent) && r.parent !== r.name) {
        const p = byName.get(r.parent);
        if (!p.children) p.children = [];
        p.children.push(node);
      } else {
        roots.push(node);
      }
    }
    if (roots.length === 1) return roots[0];
    const total = roots.reduce((a, b) => a + b.value, 0) || 1;
    return { name: "total", value: total, self: 0, children: roots };
  }
  const sorted = [...rows].sort((a, b) => (a.level ?? 0) - (b.level ?? 0));
  const root = { name: "total", value: 0, self: 0, children: [] };
  const stack = [root];
  for (const r of sorted) {
    const level = Math.max(0, Math.floor(r.level ?? 0));
    while (stack.length > level + 1) stack.pop();
    const parent = stack[stack.length - 1] ?? root;
    const node = {
      name: r.name,
      value: r.value,
      self: r.self ?? r.value,
      children: []
    };
    if (!parent.children) parent.children = [];
    parent.children.push(node);
    parent.value += r.value;
    stack.push(node);
  }
  if (!root.value) root.value = rows.reduce((a, r) => a + r.value, 0) || 1;
  return root;
}
function layoutFlame(root) {
  const out = [];
  function walk(node, depth, x, width2) {
    if (!out[depth]) out[depth] = [];
    const kids = node.children ?? [];
    const childSum = kids.reduce((a, b) => a + b.value, 0);
    const self = node.self ?? Math.max(0, node.value - childSum);
    out[depth].push({
      name: node.name,
      value: node.value,
      self,
      x,
      w: width2,
      depth,
      color: classicPalette()[depth % classicPalette().length]
    });
    if (!kids.length) return;
    const sum = kids.reduce((a, b) => a + b.value, 0) || 1;
    let cx = x;
    for (const k of kids) {
      const w = width2 * (k.value / sum);
      walk(k, depth + 1, cx, w);
      cx += w;
    }
  }
  walk(normalizeFlameTree(root), 0, 0, 100);
  return out;
}
function focusFlameNode(root, name) {
  function find(n) {
    if (n.name === name) return n;
    for (const c of n.children ?? []) {
      const hit = find(c);
      if (hit) return hit;
    }
    return null;
  }
  return normalizeFlameTree(find(root) ?? root);
}
const FULL_VIEWPORT = { start: 0, end: 100 };
const MIN_VISIBLE_PCT = 0.5;
const SCROLL_ZOOM_INTENSITY = 15e-4;
function clamp(value, min, max) {
  return Math.max(min, Math.min(max, value));
}
function clampViewport(view) {
  const span = clamp(view.end - view.start, MIN_VISIBLE_PCT, 100);
  let start = clamp(view.start, 0, 100 - span);
  return { start, end: start + span };
}
function zoomViewport(view, factor, anchorRatio) {
  const oldSpan = Math.max(view.end - view.start, MIN_VISIBLE_PCT);
  const nextSpan = clamp(oldSpan * factor, MIN_VISIBLE_PCT, 100);
  const anchorPct = view.start + clamp(anchorRatio, 0, 1) * oldSpan;
  const start = clamp(anchorPct - clamp(anchorRatio, 0, 1) * nextSpan, 0, 100 - nextSpan);
  return clampViewport({ start, end: start + nextSpan });
}
function panViewport(view, deltaPct) {
  const span = Math.max(view.end - view.start, MIN_VISIBLE_PCT);
  const start = clamp(view.start - deltaPct, 0, 100 - span);
  return { start, end: start + span };
}
function blockScreenRect(xPct, wPct, view, cssWidth) {
  const span = Math.max(view.end - view.start, MIN_VISIBLE_PCT);
  const start = xPct;
  const end = xPct + wPct;
  if (end < view.start || start > view.end) {
    return { x: 0, width: 0, visible: false };
  }
  const visibleStart = clamp(start, view.start, view.end);
  const visibleEnd = clamp(end, view.start, view.end);
  const x = (visibleStart - view.start) / span * cssWidth;
  const width2 = Math.max(1, (visibleEnd - visibleStart) / span * cssWidth);
  return { x, width: width2, visible: true };
}
const DEFAULT_ROW_HEIGHT = 22;
const MIN_SPAN_BAR_HEIGHT = 8;
const LABEL_FONT = "500 11px Inter, sans-serif";
const LABEL_PADDING_X = 6;
const MIN_WIDTH_FOR_NAME = 28;
const MIN_WIDTH_FOR_VALUE = 72;
const OVERSCAN_ROWS = 2;
function getRowMetrics(rowHeight) {
  const bar = Math.max(
    MIN_SPAN_BAR_HEIGHT,
    Math.min(DEFAULT_ROW_HEIGHT - 2, Math.round(rowHeight * 0.85))
  );
  return {
    ROW_HEIGHT: rowHeight,
    BAR_HEIGHT: bar,
    BAR_Y_OFFSET: Math.floor((rowHeight - bar) / 2)
  };
}
function darkenHex(hex, amount = 0.18) {
  if (!/^#[0-9a-fA-F]{6}$/.test(hex)) return hex;
  const r = Number.parseInt(hex.slice(1, 3), 16);
  const g = Number.parseInt(hex.slice(3, 5), 16);
  const b = Number.parseInt(hex.slice(5, 7), 16);
  const f = 1 - amount;
  const to = (n) => Math.max(0, Math.min(255, Math.round(n * f))).toString(16).padStart(2, "0");
  return `#${to(r)}${to(g)}${to(b)}`;
}
function roundedRectPath(ctx, x, y, width2, height2, radius) {
  const r = Math.min(radius, width2 / 2, height2 / 2);
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x + width2, y, x + width2, y + height2, r);
  ctx.arcTo(x + width2, y + height2, x, y + height2, r);
  ctx.arcTo(x, y + height2, x, y, r);
  ctx.arcTo(x, y, x + width2, y, r);
  ctx.closePath();
}
function truncateText(ctx, text, maxWidth) {
  const ellipsis = "…";
  if (ctx.measureText(text).width <= maxWidth) return text;
  const ellipsisWidth = ctx.measureText(ellipsis).width;
  let lo = 0;
  let hi = text.length;
  while (lo < hi) {
    const mid = Math.ceil((lo + hi) / 2);
    if (ctx.measureText(text.slice(0, mid)).width + ellipsisWidth <= maxWidth) {
      lo = mid;
    } else {
      hi = mid - 1;
    }
  }
  return lo > 0 ? `${text.slice(0, lo)}${ellipsis}` : ellipsis;
}
function updateCanvasSize(canvas, width2, height2) {
  if (!canvas) return;
  const safeW = Math.max(width2, 1);
  const safeH = Math.max(height2, 1);
  const dpr = Math.min(typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1, 2);
  const nextW = Math.round(safeW * dpr);
  const nextH = Math.round(safeH * dpr);
  if (canvas.width !== nextW) canvas.width = nextW;
  if (canvas.height !== nextH) canvas.height = nextH;
  canvas.style.width = `${safeW}px`;
  canvas.style.height = `${safeH}px`;
}
function getCanvasCssSize(canvas) {
  const dpr = Math.min(typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1, 2);
  return {
    dpr,
    cssWidth: Math.max(canvas.width / dpr, 1),
    cssHeight: Math.max(canvas.height / dpr, 1)
  };
}
function drawFlamegraph(args) {
  const {
    ctx,
    levels,
    view,
    scrollTop,
    cssWidth,
    cssHeight,
    rowHeight,
    search,
    focusName,
    hoveredName,
    sandwich,
    showDiffLabels,
    hitRects
  } = args;
  hitRects.length = 0;
  const metrics = getRowMetrics(rowHeight);
  const totalRows = levels.length;
  const first = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN_ROWS);
  const last = Math.min(
    totalRows,
    Math.ceil((scrollTop + cssHeight) / rowHeight) + OVERSCAN_ROWS
  );
  const q = search.trim().toLowerCase();
  let drawn = 0;
  for (let depth = first; depth < last; depth++) {
    const rowY = depth * rowHeight - scrollTop;
    for (const block of levels[depth] ?? []) {
      const rect = blockScreenRect(block.x, block.w, view, cssWidth);
      if (!rect.visible) continue;
      const barY = rowY + metrics.BAR_Y_OFFSET;
      const isFocus = focusName === block.name;
      const isHover = hoveredName === block.name;
      const match = !q || block.name.toLowerCase().includes(q);
      const dim = q && !match && !isFocus && !isHover;
      const color = block.color || classicBlue();
      const colorDark = darkenHex(color, 0.16);
      if (dim) ctx.globalAlpha = 0.15;
      roundedRectPath(ctx, rect.x, barY, rect.width, metrics.BAR_HEIGHT, 2);
      if (isFocus || isHover) {
        ctx.fillStyle = resolveThemeModeHint() === "light" ? "rgba(255, 255, 255, 0.92)" : "rgba(34, 37, 43, 0.92)";
        ctx.fill();
        if (isFocus) ctx.setLineDash([4, 2]);
        ctx.strokeStyle = colorDark;
        ctx.lineWidth = isFocus ? 2 : 1;
        ctx.stroke();
        if (isFocus) ctx.setLineDash([]);
      } else {
        ctx.fillStyle = color;
        ctx.fill();
        ctx.strokeStyle = sandwich ? colorDark : "rgba(0, 0, 0, 0.28)";
        ctx.lineWidth = 1;
        if (sandwich) ctx.setLineDash([3, 2]);
        ctx.stroke();
        if (sandwich) ctx.setLineDash([]);
      }
      hitRects.push({
        block,
        x: rect.x,
        y: barY,
        width: rect.width,
        height: metrics.BAR_HEIGHT
      });
      drawn++;
      if (rect.width >= MIN_WIDTH_FOR_NAME) {
        ctx.save();
        ctx.beginPath();
        ctx.rect(rect.x, barY, rect.width, metrics.BAR_HEIGHT);
        ctx.clip();
        ctx.font = LABEL_FONT;
        ctx.textBaseline = "middle";
        ctx.fillStyle = isFocus || isHover ? colorDark : resolveThemeModeHint() === "light" ? "rgba(36, 41, 46, 0.95)" : "rgba(255, 255, 255, 0.95)";
        const textY = barY + metrics.BAR_HEIGHT / 2;
        const leftX = rect.x + LABEL_PADDING_X;
        const available = rect.width - LABEL_PADDING_X * 2;
        const label = showDiffLabels ? `${block.name} Δ` : block.name;
        if (rect.width >= MIN_WIDTH_FOR_VALUE) {
          const valueText = String(block.value);
          const vw = ctx.measureText(valueText).width;
          const nameSpace = available - vw - 6;
          ctx.textAlign = "right";
          ctx.fillText(valueText, rect.x + rect.width - LABEL_PADDING_X, textY);
          if (nameSpace > 16) {
            ctx.textAlign = "left";
            ctx.fillText(truncateText(ctx, label, nameSpace), leftX, textY);
          }
        } else {
          ctx.textAlign = "left";
          ctx.fillText(truncateText(ctx, label, available), leftX, textY);
        }
        ctx.restore();
      }
      if (dim) ctx.globalAlpha = 1;
    }
  }
  return drawn;
}
function hitFlameBlock(hitRects, x, y) {
  for (let i = hitRects.length - 1; i >= 0; i--) {
    const r = hitRects[i];
    if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) {
      return r;
    }
  }
  return null;
}
const _hoisted_1$1G = ["data-show-table", "data-collapsing", "data-sticky-header", "data-show-diff", "data-focus", "data-level-count", "data-block-count", "data-sandwich", "data-show-extra", "data-search"];
const _hoisted_2$1h = {
  key: 0,
  class: "empty",
  "data-testid": "flame-empty"
};
const _hoisted_3$16 = {
  class: "sr-blocks",
  "aria-hidden": "true"
};
const _hoisted_4$X = ["data-match", "aria-label", "onClick"];
const _hoisted_5$P = { class: "tooltip__title" };
const _hoisted_6$J = { class: "tooltip__row" };
const _hoisted_7$H = { class: "tooltip__row" };
const _hoisted_8$z = { class: "tooltip__row" };
const _hoisted_9$x = { class: "is-accent" };
const _hoisted_10$r = {
  key: 2,
  class: "table",
  "data-testid": "flame-table"
};
const _hoisted_11$m = ["onClick"];
const _sfc_main$2i = /* @__PURE__ */ defineComponent({
  __name: "FlamegraphRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const focusName = ref(null);
    const search = ref("");
    const hoveredName = ref(null);
    const view = ref({ ...FULL_VIEWPORT });
    const scrollTop = ref(0);
    const rowHeight = ref(DEFAULT_ROW_HEIGHT);
    const cursorXPercent = ref(null);
    const tip = ref(null);
    const blockCount = ref(0);
    const wrapRef = ref(null);
    const canvasRef = ref(null);
    const overlayRef = ref(null);
    const hitRects = [];
    let ro = null;
    let dragging = false;
    let dragMoved = false;
    let suppressClick = false;
    let dragStartX = 0;
    let dragStartY = 0;
    let dragStartView = { ...FULL_VIEWPORT };
    let dragStartScroll = 0;
    const flameFrame = computed(() => {
      const series = props.data?.series ?? [];
      for (const frame of series) {
        if (!checkFields(frame?.fields)) return frame;
      }
      for (const frame of series) {
        if (framesToFlameRoot(frame?.fields ?? [])) return frame;
      }
      return series[0];
    });
    const fieldError = computed(() => {
      const frame = flameFrame.value;
      if (!frame) return "";
      if (framesToFlameRoot(frame?.fields ?? [])) return "";
      const wrong = checkFields(frame?.fields);
      return wrong ? getMessageCheckFieldsResult(wrong) : "";
    });
    const root = computed(() => {
      if (fieldError.value) return null;
      const frame = flameFrame.value;
      const tree = framesToFlameRoot(frame?.fields ?? []);
      if (!tree) return null;
      return focusName.value ? focusFlameNode(tree, focusName.value) : tree;
    });
    const sandwich = computed(
      () => Boolean(opts.value.sandwich ?? opts.value.view === "sandwich")
    );
    const showExtra = computed(() => Boolean(opts.value.showExtra));
    const levels = computed(() => root.value ? layoutFlame(root.value) : []);
    const flatBlocks = computed(() => levels.value.flat());
    const showTable = computed(
      () => opts.value.showTable !== false && opts.value.getTable !== false
    );
    const collapsible = computed(() => opts.value.collapsing !== false);
    const stickyHeader = computed(() => opts.value.stickyHeader !== false);
    const showDiffLabels = computed(() => Boolean(opts.value.showDiffLabels));
    const totalHeight = computed(() => levels.value.length * rowHeight.value);
    const tableRows = computed(() => {
      if (!showTable.value || !root.value)
        return [];
      const rows = [];
      function walk(n) {
        rows.push({ name: n.name, total: n.value, self: n.self ?? 0 });
        for (const c of n.children ?? []) walk(c);
      }
      walk(root.value);
      return rows.sort((a, b) => b.total - a.total);
    });
    function onBlockClick(name) {
      if (!collapsible.value) return;
      focusName.value = focusName.value === name ? null : name;
      view.value = { ...FULL_VIEWPORT };
      scrollTop.value = 0;
    }
    function resetFocus() {
      focusName.value = null;
      view.value = { ...FULL_VIEWPORT };
      scrollTop.value = 0;
    }
    function sizeCanvases() {
      const el = wrapRef.value;
      if (!el) return;
      updateCanvasSize(canvasRef.value, el.clientWidth, el.clientHeight);
      updateCanvasSize(overlayRef.value, el.clientWidth, el.clientHeight);
    }
    function clearCanvas(canvas) {
      const ctx = canvas?.getContext("2d");
      if (!ctx || !canvas) return;
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    }
    function drawMain() {
      const canvas = canvasRef.value;
      const wrap = wrapRef.value;
      if (!canvas || !wrap || !levels.value.length) {
        clearCanvas(canvas);
        blockCount.value = 0;
        return;
      }
      const ctx = canvas.getContext("2d");
      if (!ctx) return;
      sizeCanvases();
      const { dpr, cssWidth, cssHeight } = getCanvasCssSize(canvas);
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const maxScroll = Math.max(0, totalHeight.value - cssHeight);
      if (scrollTop.value > maxScroll) scrollTop.value = maxScroll;
      blockCount.value = drawFlamegraph({
        ctx,
        levels: levels.value,
        view: view.value,
        scrollTop: scrollTop.value,
        cssWidth,
        cssHeight,
        rowHeight: rowHeight.value,
        search: search.value,
        focusName: focusName.value,
        hoveredName: hoveredName.value,
        sandwich: sandwich.value,
        showDiffLabels: showDiffLabels.value,
        hitRects
      });
    }
    function drawOverlay() {
      const canvas = overlayRef.value;
      if (!canvas) return;
      const ctx = canvas.getContext("2d");
      if (!ctx) return;
      const { dpr, cssWidth, cssHeight } = getCanvasCssSize(canvas);
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      if (cursorXPercent.value == null) return;
      const x = clamp(cursorXPercent.value, 0, 1) * cssWidth;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      ctx.beginPath();
      ctx.strokeStyle = "rgba(22, 100, 255, 0.22)";
      ctx.lineWidth = 1;
      ctx.moveTo(x, 0);
      ctx.lineTo(x, cssHeight);
      ctx.stroke();
    }
    let redrawRaf = null;
    let resizeRaf = null;
    function redrawNow() {
      drawMain();
      drawOverlay();
    }
    function redraw() {
      if (redrawRaf != null) return;
      if (typeof requestAnimationFrame === "function") {
        redrawRaf = requestAnimationFrame(() => {
          redrawRaf = null;
          redrawNow();
        });
      } else {
        redrawNow();
      }
    }
    function setupRO() {
      ro?.disconnect();
      if (typeof ResizeObserver === "undefined") return;
      ro = new ResizeObserver(() => {
        if (resizeRaf != null) return;
        const run = () => {
          resizeRaf = null;
          sizeCanvases();
          redrawNow();
        };
        if (typeof requestAnimationFrame === "function") {
          resizeRaf = requestAnimationFrame(run);
        } else {
          run();
        }
      });
      if (wrapRef.value) ro.observe(wrapRef.value);
    }
    function pointer(event) {
      const canvas = canvasRef.value;
      if (!canvas) return null;
      const rect = canvas.getBoundingClientRect();
      if (!rect.width || !rect.height) return null;
      const { cssWidth, cssHeight } = getCanvasCssSize(canvas);
      return {
        x: (event.clientX - rect.left) * (cssWidth / rect.width),
        y: (event.clientY - rect.top) * (cssHeight / rect.height),
        cssWidth
      };
    }
    function makeTip(block, x, y) {
      const total = root.value?.value || 1;
      const pct = (block.value / total * 100).toFixed(1);
      const wrap = wrapRef.value;
      const w = wrap?.clientWidth ?? 320;
      const h2 = wrap?.clientHeight ?? 200;
      return {
        cx: clamp(x + 12, 8, Math.max(8, w - 200)),
        cy: clamp(y + 12, 8, Math.max(8, h2 - 100)),
        name: block.name,
        total: block.value,
        self: block.self,
        pct: `${pct}%`
      };
    }
    function onMouseMove(event) {
      if (dragging) return;
      const p = pointer(event);
      if (!p) return;
      cursorXPercent.value = clamp(p.x / Math.max(p.cssWidth, 1), 0, 1);
      const hit = hitFlameBlock(hitRects, p.x, p.y);
      if (hit) {
        hoveredName.value = hit.block.name;
        tip.value = makeTip(hit.block, p.x, p.y);
        if (canvasRef.value) canvasRef.value.style.cursor = "pointer";
      } else {
        hoveredName.value = null;
        tip.value = null;
        if (canvasRef.value) canvasRef.value.style.cursor = "grab";
      }
      redraw();
    }
    function onLeave() {
      cursorXPercent.value = null;
      hoveredName.value = null;
      tip.value = null;
      if (canvasRef.value && !dragging) canvasRef.value.style.cursor = "grab";
      redraw();
    }
    function detachDrag() {
      document.removeEventListener("mousemove", onDocMove);
      document.removeEventListener("mouseup", onDocUp);
    }
    function onMouseDown(event) {
      if (event.button !== 0 || !canvasRef.value || !wrapRef.value) return;
      dragging = true;
      dragMoved = false;
      suppressClick = false;
      dragStartX = event.clientX;
      dragStartY = event.clientY;
      dragStartView = { ...view.value };
      dragStartScroll = scrollTop.value;
      canvasRef.value.style.cursor = "grabbing";
      document.addEventListener("mousemove", onDocMove);
      document.addEventListener("mouseup", onDocUp);
    }
    function onDocMove(event) {
      if (!dragging || !canvasRef.value || !wrapRef.value) return;
      const dx = event.clientX - dragStartX;
      const dy = event.clientY - dragStartY;
      dragMoved = Math.hypot(dx, dy) > 3;
      const span = Math.max(dragStartView.end - dragStartView.start, MIN_VISIBLE_PCT);
      const cssWidth = Math.max(canvasRef.value.clientWidth, 1);
      const deltaPct = dx / cssWidth * span;
      view.value = panViewport(dragStartView, deltaPct);
      const maxScroll = Math.max(0, totalHeight.value - wrapRef.value.clientHeight);
      scrollTop.value = clamp(dragStartScroll - dy, 0, maxScroll);
      redraw();
    }
    function onDocUp() {
      dragging = false;
      suppressClick = dragMoved;
      dragMoved = false;
      if (canvasRef.value) canvasRef.value.style.cursor = "grab";
      detachDrag();
    }
    function onClick(event) {
      if (suppressClick) {
        suppressClick = false;
        return;
      }
      const p = pointer(event);
      if (!p) return;
      const hit = hitFlameBlock(hitRects, p.x, p.y);
      if (hit) onBlockClick(hit.block.name);
    }
    function onWheel(event) {
      const p = pointer(event);
      if (!p) return;
      const factor = Math.exp(event.deltaY * SCROLL_ZOOM_INTENSITY);
      const ratio = clamp(p.x / Math.max(p.cssWidth, 1), 0, 1);
      view.value = zoomViewport(view.value, factor, ratio);
      redraw();
    }
    watch(
      () => props.data?.series,
      () => {
        focusName.value = null;
        view.value = { ...FULL_VIEWPORT };
        scrollTop.value = 0;
      }
    );
    watch(
      [
        levels,
        search,
        focusName,
        hoveredName,
        sandwich,
        showDiffLabels,
        view,
        scrollTop,
        rowHeight
      ],
      () => nextTick(redraw),
      { deep: true }
    );
    watch(
      () => [props.width, props.height],
      () => nextTick(() => {
        sizeCanvases();
        redraw();
      })
    );
    onMounted(() => {
      nextTick(() => {
        setupRO();
        sizeCanvases();
        redraw();
      });
    });
    onUnmounted(() => {
      if (redrawRaf != null && typeof cancelAnimationFrame === "function") {
        cancelAnimationFrame(redrawRaf);
        redrawRaf = null;
      }
      if (resizeRaf != null && typeof cancelAnimationFrame === "function") {
        cancelAnimationFrame(resizeRaf);
        resizeRaf = null;
      }
      ro?.disconnect();
      detachDrag();
    });
    return (_ctx, _cache) => {
      return fieldError.value ? (openBlock(), createBlock(PanelDataErrorView, {
        key: 0,
        data: __props.data,
        "field-config": __props.fieldConfig,
        message: fieldError.value
      }, null, 8, ["data", "field-config", "message"])) : (openBlock(), createElementBlock("div", {
        key: 1,
        class: "flame",
        "data-testid": "panel-flamegraph",
        role: "group",
        "aria-label": "火焰图",
        "data-show-table": String(showTable.value),
        "data-collapsing": String(collapsible.value),
        "data-sticky-header": String(stickyHeader.value),
        "data-show-diff": String(showDiffLabels.value),
        "data-focus": String(focusName.value || ""),
        "data-level-count": String(levels.value.length),
        "data-block-count": String(blockCount.value || flatBlocks.value.length),
        "data-sandwich": String(sandwich.value),
        "data-show-extra": String(showExtra.value),
        "data-search": search.value
      }, [
        createElementVNode(
          "div",
          {
            class: normalizeClass(["toolbar", { "is-sticky": stickyHeader.value }]),
            "data-testid": "flame-toolbar"
          },
          [
            focusName.value ? (openBlock(), createElementBlock(
              "button",
              {
                key: 0,
                type: "button",
                class: "reset",
                "data-testid": "flame-reset",
                onClick: resetFocus
              },
              " 重置缩放（" + toDisplayString(focusName.value) + "） ",
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true),
            withDirectives(createElementVNode(
              "input",
              {
                "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
                type: "search",
                class: "search",
                "data-testid": "flame-search",
                placeholder: "搜索函数…",
                "aria-label": "搜索火焰图"
              },
              null,
              512
              /* NEED_PATCH */
            ), [
              [vModelText, search.value]
            ])
          ],
          2
          /* CLASS */
        ),
        !levels.value.length ? (openBlock(), createElementBlock("div", _hoisted_2$1h, " 暂无火焰图数据 ")) : (openBlock(), createElementBlock(
          "div",
          {
            key: 1,
            ref_key: "wrapRef",
            ref: wrapRef,
            class: "graph",
            "data-testid": "flame-graph"
          },
          [
            createCommentVNode(" Stable test hooks mirroring former DOM blocks "),
            createElementVNode("div", _hoisted_3$16, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(flatBlocks.value, (b, i) => {
                  return openBlock(), createElementBlock("button", {
                    key: `${b.depth}-${b.name}-${i}`,
                    type: "button",
                    class: "sr-block",
                    "data-testid": "flame-block",
                    "data-match": search.value ? String(
                      b.name.toLowerCase().includes(search.value.toLowerCase().trim())
                    ) : "true",
                    "aria-label": `${b.name} ${b.value}`,
                    onClick: ($event) => onBlockClick(b.name)
                  }, null, 8, _hoisted_4$X);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ]),
            createElementVNode(
              "canvas",
              {
                ref_key: "canvasRef",
                ref: canvasRef,
                class: "canvas",
                onMousemove: onMouseMove,
                onMouseleave: onLeave,
                onMousedown: onMouseDown,
                onClick,
                onWheel: withModifiers(onWheel, ["prevent"])
              },
              null,
              544
              /* NEED_HYDRATION, NEED_PATCH */
            ),
            createElementVNode(
              "canvas",
              {
                ref_key: "overlayRef",
                ref: overlayRef,
                class: "overlay"
              },
              null,
              512
              /* NEED_PATCH */
            ),
            tip.value ? (openBlock(), createElementBlock(
              "div",
              {
                key: 0,
                class: "tooltip",
                "data-testid": "flame-tooltip",
                style: normalizeStyle({ left: `${tip.value.cx}px`, top: `${tip.value.cy}px` })
              },
              [
                createElementVNode(
                  "div",
                  _hoisted_5$P,
                  toDisplayString(tip.value.name),
                  1
                  /* TEXT */
                ),
                createElementVNode("div", _hoisted_6$J, [
                  _cache[1] || (_cache[1] = createElementVNode(
                    "span",
                    null,
                    "总计",
                    -1
                    /* CACHED */
                  )),
                  createElementVNode(
                    "strong",
                    null,
                    toDisplayString(tip.value.total),
                    1
                    /* TEXT */
                  )
                ]),
                createElementVNode("div", _hoisted_7$H, [
                  _cache[2] || (_cache[2] = createElementVNode(
                    "span",
                    null,
                    "自身",
                    -1
                    /* CACHED */
                  )),
                  createElementVNode(
                    "strong",
                    null,
                    toDisplayString(tip.value.self),
                    1
                    /* TEXT */
                  )
                ]),
                createElementVNode("div", _hoisted_8$z, [
                  _cache[3] || (_cache[3] = createElementVNode(
                    "span",
                    null,
                    "占比",
                    -1
                    /* CACHED */
                  )),
                  createElementVNode(
                    "strong",
                    _hoisted_9$x,
                    toDisplayString(tip.value.pct),
                    1
                    /* TEXT */
                  )
                ])
              ],
              4
              /* STYLE */
            )) : createCommentVNode("v-if", true)
          ],
          512
          /* NEED_PATCH */
        )),
        showTable.value && tableRows.value.length ? (openBlock(), createElementBlock("table", _hoisted_10$r, [
          _cache[4] || (_cache[4] = createElementVNode(
            "thead",
            null,
            [
              createElementVNode("tr", null, [
                createElementVNode("th", null, "符号"),
                createElementVNode("th", null, "总计"),
                createElementVNode("th", null, "自身")
              ])
            ],
            -1
            /* CACHED */
          )),
          createElementVNode("tbody", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(tableRows.value, (r) => {
                return openBlock(), createElementBlock("tr", {
                  key: r.name,
                  "data-testid": "flame-table-row",
                  onClick: ($event) => onBlockClick(r.name)
                }, [
                  createElementVNode(
                    "td",
                    null,
                    toDisplayString(r.name),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "td",
                    null,
                    toDisplayString(r.total),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "td",
                    null,
                    toDisplayString(r.self),
                    1
                    /* TEXT */
                  )
                ], 8, _hoisted_11$m);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1G));
    };
  }
});
const FlamegraphRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2i, [["__scopeId", "data-v-05243ecd"]]);
const _sfc_main$2h = /* @__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(FlamegraphRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "flamegraph",
    name: "火焰图",
    description: "CPU / 内存分析火焰图",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2h
).setPanelOptions((builder) => {
  const cat = ["火焰图"];
  builder.addBoolean(
    {
      id: "showTable",
      path: "showTable",
      name: "显示表格",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "collapsing",
      path: "collapsing",
      name: "允许折叠/缩放",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "stickyHeader",
      path: "stickyHeader",
      name: "固定顶栏",
      category: cat
    },
    true
  ).addBoolean(
    {
      id: "showDiffLabels",
      path: "showDiffLabels",
      name: "显示差异标签",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "sandwich",
      path: "sandwich",
      name: "三明治视图",
      category: cat
    },
    false
  ).addBoolean(
    {
      id: "showExtra",
      path: "showExtra",
      name: "显示附加信息",
      category: cat
    },
    false
  );
}).setRuntimeConsumedPaths([
  "showTable",
  "collapsing",
  "stickyHeader",
  "showDiffLabels",
  "sandwich",
  "showExtra"
]).register();
const _hoisted_1$1F = ["data-channel", "data-display", "data-paused", "data-line-count", "data-auto-scroll", "data-message-size-limit", "data-publish", "data-publish-visible"];
const _hoisted_2$1g = ["data-publish-mode"];
const _hoisted_3$15 = { class: "publish__label" };
const _hoisted_4$W = ["placeholder"];
const _hoisted_5$O = {
  key: 1,
  class: "live-alert-wrap",
  role: "status",
  "aria-label": "Grafana Live"
};
const _hoisted_6$I = {
  class: "live-alert",
  "data-testid": "data-testid Alert info"
};
const _hoisted_7$G = { class: "live-alert__icon" };
const _hoisted_8$y = {
  class: "waiting",
  "data-testid": "live-waiting"
};
const _hoisted_9$w = { class: "waiting__channel" };
const _hoisted_10$q = ["data-auto-scroll"];
const _hoisted_11$l = ["data-truncated"];
const _sfc_main$2g = /* @__PURE__ */ defineComponent({
  __name: "LiveRenderer",
  props: {
    data: {},
    options: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const channelParts = computed(() => {
      const ch = opts.value.channel;
      if (ch && typeof ch === "object") {
        const scope = String(ch.scope ?? "").trim();
        const stream = String(ch.stream ?? ch.namespace ?? "").trim();
        const path = String(ch.path ?? "").trim();
        const valid = Boolean(scope && stream);
        return {
          scope,
          stream,
          path,
          label: [scope, stream, path].filter(Boolean).join("/") || "—",
          valid
        };
      }
      const s = String(ch || "").trim();
      if (!s) return { scope: "", stream: "", path: "", label: "—", valid: false };
      const bits = s.split("/").filter(Boolean);
      return {
        scope: bits[0] || "",
        stream: bits[1] || "",
        path: bits.slice(2).join("/") || "",
        label: s,
        valid: bits.length >= 2
      };
    });
    const display = computed(
      () => String(opts.value.display ?? opts.value.message ?? "json")
    );
    const publishMode = computed(
      () => String(opts.value.publish ?? "none").toLowerCase()
    );
    const showPublish = computed(
      () => publishMode.value === "json" || publishMode.value === "influx"
    );
    const publishDraft = ref("");
    function onPublish() {
      if (!showPublish.value || !hasChannel.value) return;
      publishDraft.value = "";
    }
    const messageSizeLimit = computed(() => {
      const n = Number(opts.value.messageSizeLimit ?? 0);
      return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
    });
    const autoScroll = computed(() => opts.value.autoScroll !== false);
    function truncateMessage(raw) {
      const limit = messageSizeLimit.value;
      if (!limit || raw.length <= limit) return raw;
      return raw.slice(0, limit) + "…";
    }
    function formatMessage(raw) {
      const mode2 = display.value.toLowerCase();
      if (mode2 === "none") return "";
      if (mode2 === "json") {
        try {
          const parsed = JSON.parse(raw);
          return truncateMessage(JSON.stringify(parsed, null, 2));
        } catch {
          return truncateMessage(raw);
        }
      }
      return truncateMessage(raw);
    }
    const messages = computed(() => {
      if (display.value.toLowerCase() === "none") return [];
      const frame = props.data?.series?.[0];
      if (!frame?.fields?.length) return [];
      const strField = frame.fields.find((f) => f.type === "string");
      if (!strField) return [];
      const n = Math.min(frame.length ?? strField.values.length, 200);
      const out = [];
      for (let i = 0; i < n; i++) {
        const v = strField.values[i];
        if (v != null && String(v).length) out.push(formatMessage(String(v)));
      }
      return out;
    });
    const hasMessage = computed(() => messages.value.length > 0);
    const hasChannel = computed(() => channelParts.value.valid);
    const paused = ref(false);
    const streamEl = ref(null);
    watch(
      () => [messages.value.length, autoScroll.value, messages.value[messages.value.length - 1]],
      async () => {
        if (!autoScroll.value || paused.value) return;
        await nextTick();
        const el = streamEl.value;
        if (!el) return;
        el.scrollTop = el.scrollHeight;
      },
      { flush: "post" }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "live",
        "data-testid": "panel-live",
        "data-channel": channelParts.value.label,
        "data-display": display.value,
        "data-paused": String(paused.value),
        "data-line-count": String(messages.value.length),
        "data-auto-scroll": String(autoScroll.value),
        "data-message-size-limit": String(messageSizeLimit.value),
        "data-publish": publishMode.value,
        "data-publish-visible": String(showPublish.value)
      }, [
        showPublish.value && hasChannel.value ? (openBlock(), createElementBlock("div", {
          key: 0,
          class: "publish",
          "data-testid": "live-publish",
          "data-publish-mode": publishMode.value
        }, [
          createElementVNode(
            "div",
            _hoisted_3$15,
            toDisplayString(publishMode.value === "influx" ? "Influx 发布" : "JSON 发布"),
            1
            /* TEXT */
          ),
          withDirectives(createElementVNode("textarea", {
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => publishDraft.value = $event),
            class: "publish__input",
            "data-testid": "live-publish-input",
            rows: "3",
            placeholder: publishMode.value === "influx" ? "measurement,tag=value field=1" : "{ }"
          }, null, 8, _hoisted_4$W), [
            [vModelText, publishDraft.value]
          ]),
          createElementVNode("button", {
            type: "button",
            class: "publish__btn",
            "data-testid": "live-publish-btn",
            onClick: onPublish
          }, " 发布 ")
        ], 8, _hoisted_2$1g)) : createCommentVNode("v-if", true),
        createCommentVNode(" Grafana LivePanel: !addr → Alert severity=info "),
        !hasChannel.value ? (openBlock(), createElementBlock("div", _hoisted_5$O, [
          createElementVNode("div", _hoisted_6$I, [
            createElementVNode("div", _hoisted_7$G, [
              createVNode(unref(GIcon), {
                name: "info-circle",
                size: 24,
                color: "var(--grafana-primary)"
              })
            ]),
            _cache[1] || (_cache[1] = createElementVNode(
              "div",
              { class: "live-alert__body" },
              [
                createElementVNode("div", { class: "live-alert__title" }, "Grafana Live"),
                createElementVNode("div", { class: "live-alert__content" }, "使用面板编辑器选择频道")
              ],
              -1
              /* CACHED */
            ))
          ])
        ])) : !hasMessage.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createCommentVNode(" Grafana LivePanel.renderMessage empty branch (zh-Hans) "),
            createElementVNode("div", _hoisted_8$y, [
              _cache[2] || (_cache[2] = createElementVNode(
                "h4",
                { class: "waiting__title" },
                "正在等待数据：",
                -1
                /* CACHED */
              )),
              createElementVNode(
                "div",
                _hoisted_9$w,
                toDisplayString(channelParts.value.label),
                1
                /* TEXT */
              )
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        )) : (openBlock(), createElementBlock("div", {
          key: 3,
          ref_key: "streamEl",
          ref: streamEl,
          class: "stream",
          "data-testid": "live-stream",
          "data-auto-scroll": String(autoScroll.value)
        }, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(messages.value, (l, i) => {
              return openBlock(), createElementBlock("div", {
                key: i,
                class: "line",
                "data-testid": "live-line",
                "data-truncated": messageSizeLimit.value > 0 && l.endsWith("…") ? "true" : "false"
              }, toDisplayString(l), 9, _hoisted_11$l);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 8, _hoisted_10$q))
      ], 8, _hoisted_1$1F);
    };
  }
});
const LiveRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2g, [["__scopeId", "data-v-86bf9cfc"]]);
const _sfc_main$2f = /* @__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(LiveRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "live",
    name: "实时",
    description: "Grafana Live 频道",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2f
).setPanelOptions((builder) => {
  const category = ["实时"];
  builder.addText(
    {
      id: "channel",
      path: "channel",
      name: "频道",
      description: "如 grafana/dashboard/uid/panel-1",
      category
    },
    ""
  ).addRadio(
    {
      id: "display",
      path: "display",
      name: "消息显示",
      category,
      settings: {
        options: [
          { label: "JSON", value: "json" },
          { label: "原始", value: "raw" },
          { label: "自动", value: "auto" },
          { label: "不显示", value: "none" }
        ]
      }
    },
    "json"
  ).addRadio(
    {
      id: "publish",
      path: "publish",
      name: "发布",
      category,
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "JSON", value: "json" },
          { label: "Influx", value: "influx" }
        ]
      }
    },
    "none"
  ).addNumber(
    {
      id: "messageSizeLimit",
      path: "messageSizeLimit",
      name: "消息大小限制",
      category,
      description: "单条消息最大字节（0=不限制）"
    },
    0
  ).addBoolean(
    {
      id: "autoScroll",
      path: "autoScroll",
      name: "自动滚动",
      category
    },
    true
  );
}).setRuntimeConsumedPaths([
  "channel",
  "display",
  "publish",
  "messageSizeLimit",
  "autoScroll"
]).register();
const _hoisted_1$1E = ["data-mode", "data-state-view", "data-instance-name", "data-counter-render", "data-counter-data", "data-counter-schema", "data-elapsed", "data-dashboard-uid"];
const _hoisted_2$1f = {
  key: 0,
  class: "state-view",
  "data-testid": "debug-state-view"
};
const _hoisted_3$14 = { class: "state-field" };
const _hoisted_4$V = {
  class: "state-current",
  "data-testid": "debug-state-current"
};
const _hoisted_5$N = {
  key: 0,
  class: "state-view-meta"
};
const _hoisted_6$H = {
  class: "events-view",
  "data-testid": "debug-events"
};
const _hoisted_7$F = {
  class: "toolbar",
  "data-testid": "debug-counters"
};
const _hoisted_8$x = { class: "counts" };
const _hoisted_9$v = {
  class: "event-list",
  "data-testid": "debug-payload"
};
const _hoisted_10$p = { class: "event-type" };
const _hoisted_11$k = { class: "event-detail" };
const _hoisted_12$g = {
  key: 0,
  class: "event-empty"
};
const _hoisted_13$g = {
  class: "cursor-view",
  "data-testid": "debug-cursor"
};
const _hoisted_14$e = { "data-testid": "debug-cursor-pos" };
const _hoisted_15$a = {
  class: "toolbar",
  "data-testid": "debug-counters"
};
const _hoisted_16$9 = { class: "counts" };
const _hoisted_17$8 = {
  key: 0,
  "data-testid": "counter-render"
};
const _hoisted_18$8 = {
  key: 1,
  "data-testid": "counter-data"
};
const _hoisted_19$8 = {
  key: 2,
  "data-testid": "counter-schema"
};
const _hoisted_20$7 = { "data-testid": "counter-elapsed" };
const _hoisted_21$6 = { class: "frame-title" };
const _hoisted_22$5 = {
  class: "filter-table",
  "data-testid": "debug-field-table"
};
const _sfc_main$2e = /* @__PURE__ */ defineComponent({
  __name: "DebugRenderer",
  props: {
    data: {},
    options: {},
    fieldConfig: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const mode2 = computed(() => String(opts.value.mode ?? "render"));
    const modeKey = computed(() => mode2.value.toLowerCase());
    const counters2 = ref({ render: 1, dataChanged: 0, schemaChanged: 0 });
    const elapsed = ref(0);
    const sawData = ref(false);
    const instanceName = ref("");
    const stateViewLabel = computed(() => String(opts.value.stateView ?? ""));
    const showRender = computed(() => opts.value.counters?.render !== false);
    const showData = computed(() => opts.value.counters?.dataChanged !== false);
    const showSchema = computed(() => opts.value.counters?.schemaChanged !== false);
    const eventLog = ref([]);
    const cursorInfo = ref({ x: 0, y: 0, active: false });
    function frameStructure(series) {
      return (series ?? []).map((f) => (f.fields ?? []).map((x) => `${x.name}:${x.type}`).join(",")).join("|");
    }
    watch(
      () => props.data,
      (n, o) => {
        if (!sawData.value) {
          sawData.value = true;
          return;
        }
        if (n !== o) {
          counters2.value = {
            ...counters2.value,
            dataChanged: counters2.value.dataChanged + 1,
            schemaChanged: frameStructure(n?.series) !== frameStructure(o?.series) ? counters2.value.schemaChanged + 1 : counters2.value.schemaChanged,
            render: counters2.value.render + 1
          };
          if (modeKey.value === "events") {
            eventLog.value = [
              ...eventLog.value.slice(-49),
              {
                t: Date.now(),
                type: "data",
                detail: `series=${n?.series?.length ?? 0}`
              }
            ];
          }
        }
      }
    );
    function resetCounters() {
      counters2.value = { render: 1, dataChanged: 0, schemaChanged: 0 };
      elapsed.value = 0;
      eventLog.value = [];
    }
    function lastNotNull(values) {
      for (let i = values.length - 1; i >= 0; i--) {
        const v = values[i];
        if (v != null && !(typeof v === "number" && Number.isNaN(v)))
          return String(v);
      }
      return "null";
    }
    const frames = computed(
      () => (props.data?.series ?? []).map((frame, idx) => {
        const name = frame.name || frame.refId || `Frame ${idx}`;
        const length = frame.length ?? frame.fields?.[0]?.values?.length ?? 0;
        const fields = (frame.fields ?? []).map((field) => ({
          name: field.name,
          type: field.type,
          last: lastNotNull(field.values ?? [])
        }));
        return { name, length, fields, key: `${idx}/${frame.refId ?? name}` };
      })
    );
    function onCursorMove(e) {
      if (modeKey.value !== "cursor") return;
      const t2 = e.currentTarget;
      const r = t2.getBoundingClientRect();
      cursorInfo.value = {
        x: Math.round(e.clientX - r.left),
        y: Math.round(e.clientY - r.top),
        active: true
      };
    }
    function onCursorLeave() {
      cursorInfo.value = { ...cursorInfo.value, active: false };
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "debug",
        "data-testid": "panel-debug",
        "data-mode": mode2.value,
        "data-state-view": stateViewLabel.value,
        "data-instance-name": instanceName.value,
        "data-counter-render": String(counters2.value.render),
        "data-counter-data": String(counters2.value.dataChanged),
        "data-counter-schema": String(counters2.value.schemaChanged),
        "data-elapsed": String(elapsed.value),
        "data-dashboard-uid": String(opts.value.dashboardUID ?? ""),
        onMousemove: onCursorMove,
        onMouseleave: onCursorLeave
      }, [
        createCommentVNode(" Grafana DebugMode.State → StateView "),
        modeKey.value === "state" ? (openBlock(), createElementBlock("div", _hoisted_2$1f, [
          createElementVNode("label", _hoisted_3$14, [
            _cache[1] || (_cache[1] = createElementVNode(
              "span",
              { class: "state-label" },
              "状态名称",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "data-testid": "debug-state-name",
              value: instanceName.value,
              placeholder: "instance state name",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => instanceName.value = String($event ?? ""))
            }, null, 8, ["value"])
          ]),
          createElementVNode("div", _hoisted_4$V, [
            createTextVNode(
              " 当前值: " + toDisplayString(instanceName.value || "—") + " ",
              1
              /* TEXT */
            ),
            stateViewLabel.value ? (openBlock(), createElementBlock(
              "span",
              _hoisted_5$N,
              " (" + toDisplayString(stateViewLabel.value) + ") ",
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true)
          ])
        ])) : modeKey.value === "events" ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" Grafana DebugMode.Events → EventBusLogger "),
            createElementVNode("div", _hoisted_6$H, [
              createElementVNode("div", _hoisted_7$F, [
                createElementVNode("button", {
                  type: "button",
                  class: "reset-btn",
                  title: "复位计数器",
                  "aria-label": "后退",
                  "data-testid": "debug-reset",
                  onClick: resetCounters
                }, [
                  createVNode(unref(GIcon), {
                    name: "step-backward",
                    size: 16
                  })
                ]),
                createElementVNode(
                  "span",
                  _hoisted_8$x,
                  "事件：" + toDisplayString(eventLog.value.length),
                  1
                  /* TEXT */
                )
              ]),
              createElementVNode("ul", _hoisted_9$v, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(eventLog.value, (e, i) => {
                    return openBlock(), createElementBlock("li", {
                      key: i,
                      class: "event-row"
                    }, [
                      createElementVNode(
                        "span",
                        _hoisted_10$p,
                        toDisplayString(e.type),
                        1
                        /* TEXT */
                      ),
                      createElementVNode(
                        "span",
                        _hoisted_11$k,
                        toDisplayString(e.detail),
                        1
                        /* TEXT */
                      )
                    ]);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                )),
                !eventLog.value.length ? (openBlock(), createElementBlock("li", _hoisted_12$g, "暂无事件")) : createCommentVNode("v-if", true)
              ])
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        )) : modeKey.value === "cursor" ? (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createCommentVNode(" Grafana DebugMode.Cursor → CursorView "),
            createElementVNode("div", _hoisted_13$g, [
              createElementVNode(
                "div",
                _hoisted_14$e,
                " 光标：" + toDisplayString(cursorInfo.value.active ? `${cursorInfo.value.x}, ${cursorInfo.value.y}` : "—"),
                1
                /* TEXT */
              )
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        )) : (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            createCommentVNode(" Default: RenderInfoViewer "),
            createElementVNode("div", _hoisted_15$a, [
              createElementVNode("button", {
                type: "button",
                class: "reset-btn",
                title: "复位计数器",
                "aria-label": "后退",
                "data-testid": "debug-reset",
                onClick: resetCounters
              }, [
                createVNode(unref(GIcon), {
                  name: "step-backward",
                  size: 16
                })
              ]),
              createElementVNode("span", _hoisted_16$9, [
                showRender.value ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_17$8,
                  "渲染：" + toDisplayString(counters2.value.render),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                showData.value ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_18$8,
                  "数据：" + toDisplayString(counters2.value.dataChanged),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                showSchema.value ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_19$8,
                  "架构：" + toDisplayString(counters2.value.schemaChanged),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                createElementVNode(
                  "span",
                  _hoisted_20$7,
                  "时间：" + toDisplayString(elapsed.value) + " 毫秒",
                  1
                  /* TEXT */
                )
              ])
            ]),
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(frames.value, (frame) => {
                return openBlock(), createElementBlock("div", {
                  key: frame.key,
                  class: "frame",
                  "data-testid": "debug-frame"
                }, [
                  createElementVNode(
                    "h4",
                    _hoisted_21$6,
                    toDisplayString(frame.name) + " (" + toDisplayString(frame.length) + ")",
                    1
                    /* TEXT */
                  ),
                  createElementVNode("table", _hoisted_22$5, [
                    _cache[2] || (_cache[2] = createElementVNode(
                      "thead",
                      null,
                      [
                        createElementVNode("tr", null, [
                          createElementVNode("td", null, "字段"),
                          createElementVNode("td", null, "类型"),
                          createElementVNode("td", null, "最后一个")
                        ])
                      ],
                      -1
                      /* CACHED */
                    )),
                    createElementVNode("tbody", null, [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(frame.fields, (field, fi) => {
                          return openBlock(), createElementBlock("tr", {
                            key: `${fi}/${field.name}`
                          }, [
                            createElementVNode(
                              "td",
                              null,
                              toDisplayString(field.name),
                              1
                              /* TEXT */
                            ),
                            createElementVNode(
                              "td",
                              null,
                              toDisplayString(field.type),
                              1
                              /* TEXT */
                            ),
                            createElementVNode(
                              "td",
                              null,
                              toDisplayString(field.last),
                              1
                              /* TEXT */
                            )
                          ]);
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])
                  ])
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 40, _hoisted_1$1E);
    };
  }
});
const DebugRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2e, [["__scopeId", "data-v-dca9883a"]]);
const _sfc_main$2d = /* @__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(DebugRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "debug",
    name: "调试",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$2d
).setPanelOptions((builder) => {
  const category = ["调试"];
  builder.addSelect(
    {
      id: "mode",
      path: "mode",
      name: "模式",
      category,
      settings: {
        options: [
          { label: "渲染", value: "render" },
          { label: "事件", value: "Events" },
          { label: "光标", value: "Cursor" },
          { label: "状态", value: "State" }
        ]
      }
    },
    "render"
  ).addText({
    id: "stateView",
    path: "stateView",
    name: "状态视图",
    category,
    showIf: (c) => String(c.mode).toLowerCase() === "state"
  }).addBoolean(
    {
      id: "counters.render",
      path: "counters.render",
      name: "渲染计数",
      category
    },
    true
  ).addBoolean(
    {
      id: "counters.dataChanged",
      path: "counters.dataChanged",
      name: "数据变更计数",
      category
    },
    true
  ).addBoolean(
    {
      id: "counters.schemaChanged",
      path: "counters.schemaChanged",
      name: "Schema 变更计数",
      category
    },
    true
  ).addText({
    id: "dashboardUID",
    path: "dashboardUID",
    name: "仪表盘 UID",
    category
  });
}).setRuntimeConsumedPaths([
  "mode",
  "stateView",
  "counters.render",
  "counters.dataChanged",
  "counters.schemaChanged",
  "dashboardUID"
]).register();
const _hoisted_1$1D = ["data-folder", "data-datasource", "data-group-by", "data-view-mode", "data-group-mode", "data-max-items", "data-sort", "data-show-inactive", "data-dashboard-alerts", "data-alert-name", "data-alert-instance-label-filter", "data-row-count", "data-stat-color-mode", "data-stat-color", "data-state-filter-size", "data-state-firing", "data-state-pending", "data-state-normal", "data-stat-thresholds", "data-stat-value-mappings"];
const _hoisted_2$1e = ["data-color-mode"];
const _hoisted_3$13 = { class: "stat-label" };
const _hoisted_4$U = {
  key: 0,
  class: "group-title"
};
const _hoisted_5$M = ["data-state"];
const _hoisted_6$G = { class: "badge" };
const _hoisted_7$E = { class: "info" };
const _hoisted_8$w = { class: "name" };
const _hoisted_9$u = {
  key: 0,
  class: "labels"
};
const _hoisted_10$o = {
  key: 0,
  class: "empty",
  "data-testid": "alertlist-empty"
};
const _sfc_main$2c = /* @__PURE__ */ defineComponent({
  __name: "AlertListRenderer",
  props: {
    data: {},
    options: {},
    width: {},
    height: {}
  },
  setup(__props) {
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const viewMode = computed(() => String(opts.value.viewMode ?? "list"));
    const groupMode = computed(() => String(opts.value.groupMode ?? "default"));
    const maxItems = computed(() => Number(opts.value.maxItems ?? 10) || 10);
    const sortOrder = computed(() => opts.value.sortOrder ?? "alphaAsc");
    const showInactive = computed(() => opts.value.showInactiveAlerts !== false);
    const dashboardAlerts = computed(
      () => opts.value.dashboardAlerts === true || opts.value.dashboardAlerts === "true"
    );
    const groupByField = computed(() => String(opts.value.groupBy ?? ""));
    const STAT_THRESHOLDS_DEFAULT = {
      mode: "absolute",
      steps: [
        { value: -Infinity, color: "green" },
        { value: 80, color: "red" }
      ]
    };
    function fromData() {
      const frame = props.data?.series?.[0];
      if (!frame?.fields?.length) return [];
      const nameF = frame.fields.find((f) => /name|alertname|title/i.test(f.name)) ?? frame.fields[0];
      const stateF = frame.fields.find((f) => /state|status/i.test(f.name));
      const labelsF = frame.fields.find((f) => /label/i.test(f.name));
      const n = nameF.values.length;
      if (!n) return [];
      const rows2 = [];
      for (let i = 0; i < n; i++) {
        rows2.push({
          name: String(nameF.values[i]),
          state: String(stateF?.values[i] ?? "alerting").toLowerCase(),
          labels: labelsF ? String(labelsF.values[i]) : void 0
        });
      }
      return rows2;
    }
    const STATE_FILTER_OPTION_KEYS = [
      "firing",
      "pending",
      "recovering",
      "noData",
      "normal",
      "error",
      "inactive"
    ];
    const stateFilter = computed(() => {
      const f = opts.value.stateFilter;
      if (f == null) return null;
      if (Array.isArray(f)) {
        if (!f.length) return null;
        return new Set(f.map((s) => String(s).toLowerCase()));
      }
      if (typeof f !== "object") return null;
      const rec = f;
      const set = /* @__PURE__ */ new Set();
      for (const k of STATE_FILTER_OPTION_KEYS) {
        if (rec[k]) set.add(String(k).toLowerCase());
      }
      for (const [k, v] of Object.entries(rec)) {
        if (v) set.add(String(k).toLowerCase());
      }
      return set;
    });
    function matchesStateFilter(state2, filter2) {
      const st = state2.toLowerCase().replace(/[\s-]/g, "_");
      if (filter2.has(st)) return true;
      const groups2 = [
        ["firing", "alerting", "alert"],
        ["pending"],
        ["recovering", "recover"],
        ["normal", "ok", "inactive"],
        ["nodata", "no_data", "no-data"],
        ["error", "err"]
      ];
      for (const g of groups2) {
        const dataHit = g.some((a) => a === st || st.includes(a));
        const filterHit = g.some((a) => filter2.has(a));
        if (dataHit && filterHit) return true;
      }
      return false;
    }
    const rows = computed(() => {
      let list = fromData();
      const nameFilter = String(
        opts.value.alertName ?? opts.value.alertInstanceLabelFilter ?? ""
      ).toLowerCase();
      const folderFilter = String(opts.value.folder ?? "").toLowerCase();
      const dsFilter = String(opts.value.datasource ?? "").toLowerCase();
      if (nameFilter) {
        list = list.filter(
          (r) => r.name.toLowerCase().includes(nameFilter) || (r.labels ?? "").toLowerCase().includes(nameFilter)
        );
      }
      if (folderFilter) {
        list = list.filter(
          (r) => String(r.folder ?? "").toLowerCase().includes(folderFilter)
        );
      }
      if (dsFilter) {
        list = list.filter(
          (r) => String(r.datasource ?? r.ds ?? "").toLowerCase().includes(dsFilter)
        );
      }
      const filter2 = stateFilter.value;
      list = list.filter((r) => {
        const st = r.state.toLowerCase();
        if (st === "inactive" && !showInactive.value && !filter2) return false;
        if (!filter2) return true;
        return matchesStateFilter(st, filter2);
      });
      if (dashboardAlerts.value) {
        list = list.filter((r) => !r.folder || r.folder === "Infra");
      }
      const sort = sortOrder.value;
      list = [...list].sort((a, b) => {
        if (sort === 3 || sort === "importance")
          return (a.importance ?? 0) - (b.importance ?? 0);
        if (sort === 2 || sort === "alphaDesc") return b.name.localeCompare(a.name);
        if (sort === 4 || sort === "timeAsc" || sort === 5 || sort === "timeDesc")
          return a.name.localeCompare(b.name);
        return a.name.localeCompare(b.name);
      });
      return list.slice(0, maxItems.value);
    });
    const groups = computed(() => {
      if (groupMode.value === "default" || viewMode.value !== "list") {
        return [{ key: "all", rows: rows.value }];
      }
      const map = /* @__PURE__ */ new Map();
      for (const r of rows.value) {
        const key = groupMode.value === "custom" ? groupByField.value ? String(r[groupByField.value] ?? r.folder ?? "默认") : r.folder || "默认" : r.state;
        if (!map.has(key)) map.set(key, []);
        map.get(key).push(r);
      }
      return [...map.entries()].map(([key, rows2]) => ({ key, rows: rows2 }));
    });
    function stateClass(s) {
      const st = s.toLowerCase();
      if (st === "alerting" || st === "firing" || st === "error") return "alerting";
      if (st === "pending") return "pending";
      if (st === "recovering") return "pending";
      if (st === "ok" || st === "normal") return "ok";
      if (st === "no_data" || st === "nodata") return "nodata";
      return "inactive";
    }
    const statColorMode = computed(
      () => String(opts.value.statColorMode ?? "none").toLowerCase()
    );
    const statDisplay = computed(() => {
      const count = rows.value.length;
      const thresholds = opts.value.statThresholds ?? STAT_THRESHOLDS_DEFAULT;
      const mappings = opts.value.statValueMappings ?? [];
      const processor = getDisplayProcessor({
        field: {
          name: "count",
          type: "number",
          config: {
            thresholds,
            mappings
          },
          values: [count]
        }
      });
      const displayValue = processor(count);
      let color = displayValue.color;
      if (statColorMode.value === "none") {
        color = void 0;
      } else if (!color) {
        const active = getActiveThreshold(count, thresholds);
        color = active?.color ? resolveVizColor(active.color) : void 0;
      } else {
        color = resolveVizColor(color) ?? color;
      }
      return {
        text: displayValue.text ?? String(count),
        numeric: count,
        color,
        title: "告警"
      };
    });
    const bigValueColorMode = computed(() => {
      const m = statColorMode.value;
      if (m === "background" || m === "background_solid") return m;
      if (m === "value") return BigValueColorMode.Value;
      return BigValueColorMode.None;
    });
    const statShellStyle = computed(() => {
      const mode2 = statColorMode.value;
      const color = statDisplay.value.color;
      if (!color) return {};
      if (mode2 === "background_solid") return { background: color };
      if (mode2 === "background")
        return { background: `linear-gradient(120deg, ${color}, ${color})` };
      return {};
    });
    const statValueStyle = computed(() => {
      if (statColorMode.value === "value" && statDisplay.value.color) {
        return { color: statDisplay.value.color };
      }
      return {};
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "alertlist",
        "data-testid": "panel-alertlist",
        "data-folder": String(opts.value.folder ?? ""),
        "data-datasource": String(opts.value.datasource ?? ""),
        "data-group-by": String(opts.value.groupBy ?? ""),
        "data-view-mode": viewMode.value,
        "data-group-mode": groupMode.value,
        "data-max-items": String(maxItems.value),
        "data-sort": String(sortOrder.value),
        "data-show-inactive": String(showInactive.value),
        "data-dashboard-alerts": String(dashboardAlerts.value),
        "data-alert-name": String(opts.value.alertName ?? ""),
        "data-alert-instance-label-filter": String(opts.value.alertInstanceLabelFilter ?? ""),
        "data-row-count": String(rows.value.length),
        "data-stat-color-mode": statColorMode.value,
        "data-stat-color": String(statDisplay.value.color ?? ""),
        "data-state-filter-size": String(stateFilter.value == null ? -1 : stateFilter.value.size),
        "data-state-firing": String(!!(opts.value.stateFilter?.firing ?? opts.value.stateFilter?.alerting)),
        "data-state-pending": String(!!opts.value.stateFilter?.pending),
        "data-state-normal": String(!!(opts.value.stateFilter?.normal ?? opts.value.stateFilter?.inactive)),
        "data-stat-thresholds": String(
          Array.isArray(opts.value.statThresholds?.steps) ? opts.value.statThresholds.steps.length : opts.value.statThresholds ? "set" : ""
        ),
        "data-stat-value-mappings": String(
          Array.isArray(opts.value.statValueMappings) ? opts.value.statValueMappings.length : opts.value.statValueMappings ? "set" : ""
        )
      }, [
        viewMode.value === "stat" ? (openBlock(), createElementBlock("div", {
          key: 0,
          class: "stat-wrap",
          "data-testid": "alertlist-stat",
          "data-color-mode": statColorMode.value,
          style: normalizeStyle(statShellStyle.value)
        }, [
          __props.width && __props.height ? (openBlock(), createBlock(unref(BigValue), {
            key: 0,
            width: __props.width,
            height: __props.height,
            value: {
              text: statDisplay.value.text,
              title: statDisplay.value.title,
              color: statDisplay.value.color
            },
            "color-mode": bigValueColorMode.value,
            "graph-mode": unref(BigValueGraphMode).None,
            "justify-mode": unref(BigValueJustifyMode).Auto,
            "text-mode": unref(BigValueTextMode).Auto
          }, null, 8, ["width", "height", "value", "color-mode", "graph-mode", "justify-mode", "text-mode"])) : (openBlock(), createElementBlock(
            Fragment,
            { key: 1 },
            [
              createElementVNode(
                "div",
                {
                  class: "stat",
                  style: normalizeStyle(statValueStyle.value)
                },
                toDisplayString(statDisplay.value.text),
                5
                /* TEXT, STYLE */
              ),
              createElementVNode(
                "div",
                _hoisted_3$13,
                toDisplayString(statDisplay.value.title),
                1
                /* TEXT */
              )
            ],
            64
            /* STABLE_FRAGMENT */
          ))
        ], 12, _hoisted_2$1e)) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(groups.value, (g) => {
                return openBlock(), createElementBlock("section", {
                  key: g.key,
                  class: "group"
                }, [
                  groupMode.value !== "default" ? (openBlock(), createElementBlock(
                    "header",
                    _hoisted_4$U,
                    toDisplayString(g.key),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(g.rows, (r, i) => {
                      return openBlock(), createElementBlock("div", {
                        key: i,
                        class: normalizeClass(["row", stateClass(r.state)]),
                        "data-testid": "alertlist-row",
                        "data-state": r.state
                      }, [
                        createElementVNode(
                          "span",
                          _hoisted_6$G,
                          toDisplayString(r.state),
                          1
                          /* TEXT */
                        ),
                        createElementVNode("div", _hoisted_7$E, [
                          createElementVNode(
                            "div",
                            _hoisted_8$w,
                            toDisplayString(r.name),
                            1
                            /* TEXT */
                          ),
                          r.labels ? (openBlock(), createElementBlock(
                            "div",
                            _hoisted_9$u,
                            toDisplayString(r.labels),
                            1
                            /* TEXT */
                          )) : createCommentVNode("v-if", true)
                        ])
                      ], 10, _hoisted_5$M);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            )),
            createCommentVNode(" Grafana UnifiedAlertList hardcodes English empty copy "),
            !rows.value.length ? (openBlock(), createElementBlock("div", _hoisted_10$o, " No alerts matching filters ")) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 8, _hoisted_1$1D);
    };
  }
});
const AlertListRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$2c, [["__scopeId", "data-v-5871ce04"]]);
const _sfc_main$2b = /* @__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(AlertListRenderer, {
        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"]);
    };
  }
});
new VuePanelPlugin(
  {
    id: "alertlist",
    name: "告警列表",
    description: "统一告警列表 / 统计",
    state: "stable",
    skipDataQuery: true
  },
  _sfc_main$2b
).setPanelOptions((builder) => {
  const optionsCategory = ["选项"];
  const filterCategory = ["过滤"];
  const alertStateCategory = ["告警状态过滤"];
  const statCategory = ["统计样式"];
  builder.addRadio(
    {
      id: "viewMode",
      path: "viewMode",
      name: "视图模式",
      description: "列表视图与统计视图切换",
      category: optionsCategory,
      settings: {
        options: [
          { label: "列表", value: "list" },
          { label: "统计", value: "stat" }
        ]
      }
    },
    "list"
  ).addRadio(
    {
      id: "groupMode",
      path: "groupMode",
      name: "分组模式",
      category: optionsCategory,
      settings: {
        options: [
          { label: "默认分组", value: "default" },
          { label: "自定义分组", value: "custom" }
        ]
      }
    },
    "default"
  ).addText(
    {
      id: "groupBy",
      path: "groupBy",
      name: "分组字段",
      description: "标签查询，逗号分隔",
      category: optionsCategory,
      showIf: (c) => c.groupMode === "custom"
    },
    void 0
  ).addNumber(
    {
      id: "maxItems",
      path: "maxItems",
      name: "最大条目",
      category: optionsCategory,
      settings: { min: 1 },
      showIf: (c) => c.groupMode !== "custom"
    },
    20
  ).addSelect(
    {
      id: "sortOrder",
      path: "sortOrder",
      name: "排序",
      category: optionsCategory,
      settings: {
        options: [
          { label: "字母升序", value: 1 },
          { label: "字母降序", value: 2 },
          { label: "重要性", value: 3 },
          { label: "时间升序", value: 4 },
          { label: "时间降序", value: 5 }
        ]
      }
    },
    3
  ).addBoolean(
    {
      id: "dashboardAlerts",
      path: "dashboardAlerts",
      name: "仅本仪表盘关联告警",
      category: filterCategory
    },
    false
  ).addText(
    {
      id: "alertName",
      path: "alertName",
      name: "告警名称",
      category: filterCategory
    },
    ""
  ).addText(
    {
      id: "alertInstanceLabelFilter",
      path: "alertInstanceLabelFilter",
      name: "实例标签过滤",
      category: filterCategory
    },
    ""
  ).addText(
    {
      id: "datasource",
      path: "datasource",
      name: "数据源",
      category: filterCategory
    },
    void 0
  ).addText(
    {
      id: "folder",
      path: "folder",
      name: "文件夹",
      category: filterCategory
    },
    void 0
  ).addBoolean(
    {
      id: "showInactiveAlerts",
      path: "showInactiveAlerts",
      name: "显示 0 实例告警",
      category: filterCategory
    },
    false
  ).addBoolean(
    {
      id: "stateFilter.firing",
      path: "stateFilter.firing",
      name: "Alerting / Firing",
      category: alertStateCategory
    },
    true
  ).addBoolean(
    {
      id: "stateFilter.pending",
      path: "stateFilter.pending",
      name: "Pending",
      category: alertStateCategory
    },
    true
  ).addBoolean(
    {
      id: "stateFilter.recovering",
      path: "stateFilter.recovering",
      name: "Recovering",
      category: alertStateCategory
    },
    true
  ).addBoolean(
    {
      id: "stateFilter.noData",
      path: "stateFilter.noData",
      name: "No Data",
      category: alertStateCategory
    },
    false
  ).addBoolean(
    {
      id: "stateFilter.normal",
      path: "stateFilter.normal",
      name: "Normal",
      category: alertStateCategory
    },
    false
  ).addBoolean(
    {
      id: "stateFilter.error",
      path: "stateFilter.error",
      name: "Error",
      category: alertStateCategory
    },
    true
  ).addSelect(
    {
      id: "statColorMode",
      path: "statColorMode",
      name: "颜色模式",
      category: statCategory,
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "值", value: "value" },
          { label: "背景渐变", value: "background" },
          { label: "背景纯色", value: "background_solid" }
        ]
      },
      showIf: (c) => c.viewMode === "stat"
    },
    "none"
  ).addCustom({
    id: "statThresholds",
    path: "statThresholds",
    name: "阈值",
    category: statCategory,
    editor: "thresholds",
    showIf: (c) => c.viewMode === "stat" && c.statColorMode && c.statColorMode !== "none"
  }).addCustom({
    id: "statValueMappings",
    path: "statValueMappings",
    name: "值映射",
    category: statCategory,
    editor: "mappings",
    showIf: (c) => c.viewMode === "stat"
  });
}).setRuntimeConsumedPaths([
  "viewMode",
  "groupMode",
  "groupBy",
  "maxItems",
  "sortOrder",
  "dashboardAlerts",
  "alertName",
  "alertInstanceLabelFilter",
  "datasource",
  "folder",
  "showInactiveAlerts",
  "stateFilter.firing",
  "stateFilter.pending",
  "stateFilter.recovering",
  "stateFilter.noData",
  "stateFilter.normal",
  "stateFilter.error",
  "statColorMode",
  "statThresholds",
  "statValueMappings"
]).register();
const _hoisted_1$1C = ["data-mode", "data-clock-type", "data-date-show", "data-timezone"];
const _hoisted_2$1d = { class: "panel-clock__time" };
const _hoisted_3$12 = {
  key: 0,
  class: "panel-clock__date"
};
const _sfc_main$2a = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const now2 = ref(Date.now());
    let timer;
    onMounted(() => {
      timer = setInterval(() => {
        now2.value = Date.now();
      }, 250);
    });
    onBeforeUnmount(() => {
      if (timer) clearInterval(timer);
    });
    function pad(n) {
      return String(n).padStart(2, "0");
    }
    function formatInTz(ts, tz, clockType, dateFormat) {
      try {
        const d = new Date(ts);
        const hour12 = String(clockType || "").toLowerCase().includes("12");
        if (tz) {
          const parts = new Intl.DateTimeFormat(hour12 ? "en-US" : "en-GB", {
            timeZone: tz,
            year: "numeric",
            month: "2-digit",
            day: "2-digit",
            hour: "2-digit",
            minute: "2-digit",
            second: "2-digit",
            hour12
          }).formatToParts(d);
          const get = (t2) => parts.find((p) => p.type === t2)?.value || "";
          const dayPeriod = get("dayPeriod");
          const time2 = hour12 ? `${get("hour")}:${get("minute")}:${get("second")}${dayPeriod ? " " + dayPeriod : ""}` : `${get("hour")}:${get("minute")}:${get("second")}`;
          const y2 = get("year");
          const m2 = get("month");
          const day2 = get("day");
          const date = applyDateFormat(dateFormat, y2, m2, day2);
          return { date, time: time2 };
        }
        const y = String(d.getFullYear());
        const m = pad(d.getMonth() + 1);
        const day = pad(d.getDate());
        let h2 = d.getHours();
        const min = pad(d.getMinutes());
        const sec = pad(d.getSeconds());
        let time;
        if (hour12) {
          const ap = h2 >= 12 ? "PM" : "AM";
          h2 = h2 % 12 || 12;
          time = `${pad(h2)}:${min}:${sec} ${ap}`;
        } else {
          time = `${pad(h2)}:${min}:${sec}`;
        }
        return { date: applyDateFormat(dateFormat, y, m, day), time };
      } catch {
        const d = new Date(ts);
        return {
          date: d.toISOString().slice(0, 10),
          time: d.toISOString().slice(11, 19)
        };
      }
    }
    function applyDateFormat(fmt, y, m, d) {
      const f = fmt || "YYYY-MM-DD";
      return f.replace(/YYYY/g, y).replace(/MM/g, m).replace(/DD/g, d).replace(/YY/g, y.slice(-2));
    }
    function formatDuration(ms) {
      const sign = ms < 0 ? "-" : "";
      ms = Math.abs(ms);
      const s = Math.floor(ms / 1e3);
      const h2 = Math.floor(s / 3600);
      const m = Math.floor(s % 3600 / 60);
      const sec = s % 60;
      return `${sign}${pad(h2)}:${pad(m)}:${pad(sec)}`;
    }
    const display = computed(() => {
      const opts = props.options || {};
      const mode2 = opts.mode || "time";
      const tz = opts.timezone || void 0;
      if (mode2 === "countdown" && opts.countdownEnd) {
        const end = Date.parse(opts.countdownEnd);
        if (Number.isFinite(end))
          return {
            primary: formatDuration(end - now2.value),
            secondary: opts.dateShow ? formatInTz(now2.value, tz, opts.clockType, opts.dateFormat).date : ""
          };
      }
      if (mode2 === "countup" && opts.countdownEnd) {
        const start = Date.parse(opts.countdownEnd);
        if (Number.isFinite(start))
          return {
            primary: formatDuration(now2.value - start),
            secondary: opts.dateShow ? formatInTz(now2.value, tz, opts.clockType, opts.dateFormat).date : ""
          };
      }
      const f = formatInTz(now2.value, tz, opts.clockType, opts.dateFormat);
      return { primary: f.time, secondary: opts.dateShow !== false ? f.date : "" };
    });
    const style = computed(() => {
      const opts = props.options || {};
      return {
        fontSize: opts.fontSize || "3em",
        background: opts.bgColor || "transparent"
      };
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-clock",
        "data-testid": "panel-clock",
        "data-mode": String(__props.options?.mode || "time"),
        "data-clock-type": String(__props.options?.clockType || "24 hour"),
        "data-date-show": String(__props.options?.dateShow !== false),
        "data-timezone": String(__props.options?.timezone || ""),
        style: normalizeStyle(style.value)
      }, [
        createElementVNode(
          "div",
          _hoisted_2$1d,
          toDisplayString(display.value.primary),
          1
          /* TEXT */
        ),
        display.value.secondary ? (openBlock(), createElementBlock(
          "div",
          _hoisted_3$12,
          toDisplayString(display.value.secondary),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ], 12, _hoisted_1$1C);
    };
  }
});
const Panel$b = /* @__PURE__ */ _export_sfc(_sfc_main$2a, [["__scopeId", "data-v-65daf2c1"]]);
new VuePanelPlugin(
  { id: "clock", name: "时钟", state: "stable", skipDataQuery: true },
  Panel$b
).setPanelOptions((builder) => {
  builder.addRadio(
    {
      id: "mode",
      path: "mode",
      name: "模式",
      category: ["时钟"],
      editor: "radio",
      settings: {
        options: [
          { label: "时间", value: "time" },
          { label: "倒计时", value: "countdown" },
          { label: "正计时", value: "countup" }
        ]
      }
    },
    "time"
  ).addText(
    {
      id: "clockType",
      path: "clockType",
      name: "时钟类型",
      category: ["时钟"],
      editor: "text",
      settings: { placeholder: "24 hour" }
    },
    "24 hour"
  ).addText(
    {
      id: "timezone",
      path: "timezone",
      name: "时区",
      category: ["时钟"],
      editor: "text",
      description: "IANA 时区，如 Asia/Shanghai；空为本地"
    },
    ""
  ).addText(
    {
      id: "dateFormat",
      path: "dateFormat",
      name: "日期格式",
      category: ["日期"],
      editor: "text"
    },
    "YYYY-MM-DD"
  ).addBoolean(
    {
      id: "dateShow",
      path: "dateShow",
      name: "显示日期",
      category: ["日期"],
      editor: "boolean"
    },
    true
  ).addText(
    {
      id: "countdownEnd",
      path: "countdownEnd",
      name: "倒计时终点",
      category: ["倒计时"],
      editor: "text",
      description: "ISO 时间或可解析日期字符串",
      showIf: (c) => c.mode === "countdown"
    },
    ""
  ).addText(
    {
      id: "bgColor",
      path: "bgColor",
      name: "背景色",
      category: ["外观"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "fontSize",
      path: "fontSize",
      name: "字号",
      category: ["外观"],
      editor: "text"
    },
    "3em"
  );
}).useFieldConfig().setRuntimeConsumedPaths([
  "mode",
  "clockType",
  "timezone",
  "dateFormat",
  "dateShow",
  "countdownEnd",
  "bgColor",
  "fontSize"
]).register();
const _hoisted_1$1B = ["data-color-mode", "data-show-legend"];
const _hoisted_2$1c = {
  key: 0,
  class: "panel-statusmap__empty"
};
const _hoisted_3$11 = { class: "row-h" };
const _hoisted_4$T = ["title"];
const _hoisted_5$L = {
  key: 2,
  class: "panel-statusmap__legend",
  "data-testid": "statusmap-legend"
};
const _sfc_main$29 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const colorMode = computed(
      () => String(props.options?.colorMode || "threshold")
    );
    const showLegend = computed(
      () => props.options?.showLegend !== false
    );
    const cells = computed(() => {
      const series = props.data?.series || [];
      const out = [];
      const palette2 = getClassicPalette$1();
      const max = Number(props.options?.cellsMax) || 500;
      const mode2 = colorMode.value;
      const raw = [];
      for (const frame of series) {
        const fields = frame.fields || [];
        const time = fields.find((f) => f.type === "time");
        const nums = fields.filter((f) => f.type === "number");
        for (const f of nums) {
          const vals2 = f.values || [];
          const times = time?.values || [];
          for (let i = 0; i < vals2.length && raw.length < max; i++) {
            const v = Number(vals2[i]);
            if (!Number.isFinite(v)) continue;
            const t2 = times[i] != null ? new Date(Number(times[i])).toISOString().slice(11, 16) : String(i);
            raw.push({ row: f.name || "series", col: t2, value: v, field: f });
          }
        }
      }
      const vals = raw.map((r) => r.value);
      const minV = vals.length ? Math.min(...vals) : 0;
      const maxV = vals.length ? Math.max(...vals) : 1;
      const span = maxV - minV || 1;
      for (const r of raw) {
        let color;
        if (mode2 === "spectrum" || mode2 === "opacity") {
          const t2 = (r.value - minV) / span;
          const idx = Math.min(palette2.length - 1, Math.floor(t2 * (palette2.length - 1)));
          color = palette2[idx];
          if (mode2 === "opacity") {
            color = `color-mix(in srgb, var(--grafana-primary) ${Math.round(15 + t2 * 85)}%, transparent)`;
          }
        } else {
          color = getThresholdColor(r.value, r.field.config || {}) || palette2[Math.abs(Math.floor(r.value)) % palette2.length];
        }
        out.push({ row: r.row, col: r.col, value: r.value, color });
      }
      return out;
    });
    const rows = computed(() => [...new Set(cells.value.map((c) => c.row))]);
    const cols = computed(() => [...new Set(cells.value.map((c) => c.col))]);
    const grid = computed(() => {
      const map = new Map(cells.value.map((c) => [`${c.row}|${c.col}`, c]));
      return rows.value.map((r) => cols.value.map((c) => map.get(`${r}|${c}`)));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-statusmap",
        "data-testid": "panel-statusmap",
        "data-color-mode": colorMode.value,
        "data-show-legend": String(showLegend.value)
      }, [
        !cells.value.length ? (openBlock(), createElementBlock("div", _hoisted_2$1c, "无数据")) : (openBlock(), createElementBlock(
          "div",
          {
            key: 1,
            class: "panel-statusmap__grid",
            style: normalizeStyle({
              gridTemplateColumns: `80px repeat(${cols.value.length}, minmax(10px, 1fr))`
            })
          },
          [
            _cache[0] || (_cache[0] = createElementVNode(
              "div",
              { class: "corner" },
              null,
              -1
              /* CACHED */
            )),
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(cols.value, (c) => {
                return openBlock(), createElementBlock(
                  "div",
                  {
                    key: c,
                    class: "col-h"
                  },
                  toDisplayString(c),
                  1
                  /* TEXT */
                );
              }),
              128
              /* KEYED_FRAGMENT */
            )),
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(grid.value, (row, ri) => {
                return openBlock(), createElementBlock(
                  Fragment,
                  {
                    key: rows.value[ri]
                  },
                  [
                    createElementVNode(
                      "div",
                      _hoisted_3$11,
                      toDisplayString(rows.value[ri]),
                      1
                      /* TEXT */
                    ),
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(row, (cell, ci) => {
                        return openBlock(), createElementBlock("div", {
                          key: ci,
                          class: "cell",
                          style: normalizeStyle({ background: cell?.color || "var(--grafana-hover)" }),
                          title: cell ? `${rows.value[ri]} @ ${cols.value[ci]} = ${cell.value}` : ""
                        }, null, 12, _hoisted_4$T);
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ],
                  64
                  /* STABLE_FRAGMENT */
                );
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ],
          4
          /* STYLE */
        )),
        showLegend.value && cells.value.length ? (openBlock(), createElementBlock("div", _hoisted_5$L, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(rows.value, (r, i) => {
              return openBlock(), createElementBlock("span", {
                key: i,
                class: "panel-statusmap__legend-item"
              }, [
                createElementVNode(
                  "i",
                  {
                    style: normalizeStyle({
                      background: cells.value.find((c) => c.row === r)?.color || "var(--grafana-primary)"
                    })
                  },
                  null,
                  4
                  /* STYLE */
                ),
                createTextVNode(
                  toDisplayString(r),
                  1
                  /* TEXT */
                )
              ]);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1B);
    };
  }
});
const Panel$a = /* @__PURE__ */ _export_sfc(_sfc_main$29, [["__scopeId", "data-v-e7735fef"]]);
new VuePanelPlugin(
  { id: "statusmap", name: "状态地图", state: "stable" },
  Panel$a
).setPanelOptions((builder) => {
  builder.addNumber(
    {
      id: "colorMode",
      path: "colorMode",
      name: "着色模式",
      category: ["状态地图"],
      editor: "number"
    },
    0
  ).addBoolean(
    {
      id: "showLegend",
      path: "showLegend",
      name: "图例",
      category: ["状态地图"],
      editor: "boolean"
    },
    true
  ).addNumber(
    {
      id: "cellsMax",
      path: "cellsMax",
      name: "最大单元",
      category: ["状态地图"],
      editor: "number"
    },
    500
  );
}).useFieldConfig().setRuntimeConsumedPaths(["colorMode", "showLegend", "cellsMax"]).register();
const _hoisted_1$1A = ["data-shape", "data-show-value", "data-limit"];
const _hoisted_2$1b = {
  key: 0,
  class: "empty"
};
const _hoisted_3$10 = ["title"];
const _hoisted_4$S = { class: "name" };
const _hoisted_5$K = {
  key: 0,
  class: "val"
};
const _sfc_main$28 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const items = computed(() => {
      const series = props.data?.series || [];
      const limit = Number(props.options?.limit) || 100;
      const palette2 = getClassicPalette$1();
      const out = [];
      let i = 0;
      for (const frame of series) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          const color = getThresholdColor(v, field.config || {}) || palette2[i % palette2.length];
          out.push({
            name: field.name || `s${i}`,
            value: v,
            color,
            text: formatValue(v, field.config || {})
          });
          i++;
          if (out.length >= limit) return out;
        }
      }
      return out;
    });
    const shape = computed(
      () => props.options?.shape || "hexagon_pointed_top"
    );
    const showValue = computed(() => props.options?.showValue !== false);
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-polystat",
        "data-testid": "panel-polystat",
        "data-shape": shape.value,
        "data-show-value": String(showValue.value),
        "data-limit": String(Number(__props.options?.limit) || 100)
      }, [
        !items.value.length ? (openBlock(), createElementBlock("div", _hoisted_2$1b, "无数据")) : createCommentVNode("v-if", true),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(items.value, (it) => {
            return openBlock(), createElementBlock("div", {
              key: it.name,
              class: normalizeClass(["poly", "shape-" + shape.value]),
              style: normalizeStyle({ background: it.color }),
              title: it.name + ": " + it.text
            }, [
              createElementVNode(
                "span",
                _hoisted_4$S,
                toDisplayString(it.name),
                1
                /* TEXT */
              ),
              showValue.value ? (openBlock(), createElementBlock(
                "span",
                _hoisted_5$K,
                toDisplayString(it.text),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true)
            ], 14, _hoisted_3$10);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ], 8, _hoisted_1$1A);
    };
  }
});
const Panel$9 = /* @__PURE__ */ _export_sfc(_sfc_main$28, [["__scopeId", "data-v-46ab32f6"]]);
new VuePanelPlugin(
  { id: "polystat", name: "蜂窝多维", state: "stable" },
  Panel$9
).setPanelOptions((builder) => {
  builder.addSelect(
    {
      id: "shape",
      path: "shape",
      name: "形状",
      category: ["蜂窝"],
      editor: "select",
      settings: {
        options: [
          { label: "六边形", value: "hexagon_pointed_top" },
          { label: "圆形", value: "circle" },
          { label: "方形", value: "square" }
        ]
      }
    },
    "hexagon_pointed_top"
  ).addNumber(
    {
      id: "limit",
      path: "limit",
      name: "数量上限",
      category: ["蜂窝"],
      editor: "number"
    },
    100
  ).addBoolean(
    {
      id: "showValue",
      path: "showValue",
      name: "显示数值",
      category: ["蜂窝"],
      editor: "boolean"
    },
    true
  );
}).useFieldConfig().setRuntimeConsumedPaths(["shape", "limit", "showValue"]).register();
const _hoisted_1$1z = ["data-text", "data-url", "data-method", "data-confirm", "data-variant", "data-has-body"];
const _hoisted_2$1a = ["disabled"];
const _hoisted_3$$ = {
  key: 0,
  class: "panel-button__status",
  "data-testid": "panel-button-status"
};
const _sfc_main$27 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const status = ref("");
    const loading = ref(false);
    const label = computed(() => props.options?.text || "执行");
    const variant = computed(() => props.options?.variant || "primary");
    async function onClick() {
      const opts = props.options || {};
      if (opts.confirm && typeof window !== "undefined") {
        if (!window.confirm(`确认执行：${label.value}？`)) return;
      }
      const url = props.replaceVariables ? props.replaceVariables(opts.url || "") : opts.url || "";
      if (!url) {
        status.value = "未配置 URL";
        return;
      }
      loading.value = true;
      status.value = "";
      const client = createHttpClient({ kind: "app", timeoutMs: 3e4 });
      try {
        const method = String(opts.method || "POST").toUpperCase();
        const res = await client.request({
          url,
          method,
          headers: { "Content-Type": "application/json" },
          data: method === "GET" || method === "HEAD" ? void 0 : opts.body || void 0,
          // absolute URL: no baseURL
          transformResponse: [(d) => d]
        });
        status.value = `${res.status} ${res.statusText || ""}`.trim();
      } catch (e) {
        status.value = e?.message || "请求失败";
      } finally {
        client.dispose();
        loading.value = false;
      }
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-button",
        "data-testid": "panel-button",
        "data-text": String(label.value),
        "data-url": String(__props.options?.url ?? ""),
        "data-method": String(__props.options?.method ?? "POST"),
        "data-confirm": String(!!__props.options?.confirm),
        "data-variant": String(variant.value),
        "data-has-body": String(!!__props.options?.body)
      }, [
        createElementVNode("button", {
          type: "button",
          class: normalizeClass(["panel-button__btn", "is-" + variant.value]),
          disabled: loading.value,
          "data-testid": "panel-button-trigger",
          onClick
        }, toDisplayString(loading.value ? "…" : label.value), 11, _hoisted_2$1a),
        status.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_3$$,
          toDisplayString(status.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1z);
    };
  }
});
const Panel$8 = /* @__PURE__ */ _export_sfc(_sfc_main$27, [["__scopeId", "data-v-8469c06c"]]);
new VuePanelPlugin(
  { id: "button", name: "按钮", state: "stable", skipDataQuery: true },
  Panel$8
).setPanelOptions((builder) => {
  builder.addText(
    {
      id: "text",
      path: "text",
      name: "按钮文案",
      category: ["按钮"],
      editor: "text"
    },
    "执行"
  ).addText(
    {
      id: "url",
      path: "url",
      name: "请求 URL",
      category: ["动作"],
      editor: "text"
    },
    ""
  ).addSelect(
    {
      id: "method",
      path: "method",
      name: "方法",
      category: ["动作"],
      editor: "select",
      settings: {
        options: [
          { label: "GET", value: "GET" },
          { label: "POST", value: "POST" },
          { label: "PUT", value: "PUT" },
          { label: "DELETE", value: "DELETE" }
        ]
      }
    },
    "POST"
  ).addTextArea(
    {
      id: "body",
      path: "body",
      name: "请求体",
      category: ["动作"],
      editor: "textarea"
    },
    ""
  ).addBoolean(
    {
      id: "confirm",
      path: "confirm",
      name: "点击前确认",
      category: ["按钮"],
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "variant",
      path: "variant",
      name: "样式",
      category: ["外观"],
      editor: "text",
      description: "primary | default | danger"
    },
    "primary"
  );
}).useFieldConfig().setRuntimeConsumedPaths([
  "text",
  "url",
  "method",
  "body",
  "confirm",
  "variant"
]).register();
const ALLOWED_TAGS$1 = /* @__PURE__ */ new Set([
  "b",
  "i",
  "em",
  "strong",
  "br",
  "p",
  "span",
  "code",
  "pre",
  "ul",
  "ol",
  "li"
]);
function sanitizeProblemHtml$1(input, allowDangerousHTML = false) {
  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 t2 = String(tag).toLowerCase();
    if (!ALLOWED_TAGS$1.has(t2)) return "";
    if (full.startsWith("</")) return `</${t2}>`;
    if (t2 === "br") return "<br/>";
    return `<${t2}>`;
  });
  return s;
}
const sanitizeHtml = sanitizeProblemHtml$1;
const _hoisted_1$1y = ["data-content-type", "data-every-row", "innerHTML"];
const _sfc_main$26 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function rowMap(series) {
      const map = {};
      for (const frame of series || []) {
        for (const field of frame.fields || []) {
          const name = field.name || field.config?.displayName || "value";
          const vals = field.values;
          const v = Array.isArray(vals) ? vals[vals.length - 1] : vals;
          map[name] = v;
          if (field.type === "number" && map.value === void 0) map.value = v;
        }
      }
      return map;
    }
    function applyTemplate(tpl, data) {
      return String(tpl || "").replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (_, key) => {
        const v = data[key];
        return v == null ? "" : String(v);
      });
    }
    function simpleMd(s) {
      return s.replace(/^### (.*)$/gm, "<h3>$1</h3>").replace(/^## (.*)$/gm, "<h2>$1</h2>").replace(/^# (.*)$/gm, "<h1>$1</h1>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/`([^`]+)`/g, "<code>$1</code>").replace(/\n/g, "<br/>");
    }
    function rowMaps(series) {
      let len = 0;
      for (const frame of series || []) {
        for (const field of frame.fields || []) {
          const n = Array.isArray(field.values) ? field.values.length : 0;
          if (n > len) len = n;
        }
      }
      if (len <= 0) return [rowMap(series)];
      const rows = [];
      for (let i = 0; i < len; i++) {
        const map = {};
        for (const frame of series || []) {
          for (const field of frame.fields || []) {
            const name = field.name || field.config?.displayName || "value";
            const vals = field.values;
            const v = Array.isArray(vals) ? vals[i] : vals;
            map[name] = v;
            if (field.type === "number" && map.value === void 0) map.value = v;
          }
        }
        rows.push(map);
      }
      return rows;
    }
    const html = computed(() => {
      const opts = props.options || {};
      const series = props.data?.series || [];
      let tpl = opts.content || "";
      if (props.replaceVariables) tpl = props.replaceVariables(tpl);
      const maps = opts.everyRow ? rowMaps(series) : [rowMap(series)];
      const parts = [];
      for (const map0 of maps) {
        const map = { ...map0 };
        if (props.replaceVariables) {
          for (const k of Object.keys(map))
            map[k] = props.replaceVariables(String(map[k] ?? ""));
        }
        const rendered = applyTemplate(tpl, map);
        parts.push(opts.contentType === "html" ? rendered : simpleMd(rendered));
      }
      return sanitizeHtml(parts.join(opts.everyRow ? "<hr/>" : ""));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-dynamictext",
        "data-testid": "panel-dynamictext",
        "data-content-type": String(__props.options?.contentType || "markdown"),
        "data-every-row": String(!!__props.options?.everyRow),
        innerHTML: html.value
      }, null, 8, _hoisted_1$1y);
    };
  }
});
const Panel$7 = /* @__PURE__ */ _export_sfc(_sfc_main$26, [["__scopeId", "data-v-72ab5df8"]]);
new VuePanelPlugin(
  { id: "dynamictext", name: "动态文本", state: "stable" },
  Panel$7
).setPanelOptions((builder) => {
  builder.addRadio(
    {
      id: "contentType",
      path: "contentType",
      name: "类型",
      category: ["内容"],
      editor: "radio",
      settings: {
        options: [
          { label: "Markdown", value: "markdown" },
          { label: "HTML", value: "html" }
        ]
      }
    },
    "markdown"
  ).addTextArea(
    {
      id: "content",
      path: "content",
      name: "模板",
      category: ["内容"],
      editor: "textarea",
      description: "支持 {{field_name}} 占位；无数据时显示原文"
    },
    "# {{title}}\n\n值: {{value}}"
  ).addBoolean(
    {
      id: "everyRow",
      path: "everyRow",
      name: "逐行渲染",
      category: ["内容"],
      editor: "boolean"
    },
    false
  );
}).useFieldConfig().setRuntimeConsumedPaths(["contentType", "content", "everyRow"]).register();
const _hoisted_1$1x = ["data-show-label", "data-text-field", "data-start-field", "data-end-field"];
const _hoisted_2$19 = {
  key: 0,
  class: "empty"
};
const _hoisted_3$_ = {
  key: 0,
  class: "label"
};
const _hoisted_4$R = { class: "track" };
const _hoisted_5$J = ["title"];
const _sfc_main$25 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const showLabel = computed(() => props.options?.showLabel !== false);
    const bars = computed(() => {
      const series = props.data?.series || [];
      const opts = props.options || {};
      const palette2 = getClassicPalette$1();
      const out = [];
      for (const frame of series) {
        const fields = frame.fields || [];
        const byName = (n) => fields.find((f) => f.name === n);
        const textF = byName(opts.textField) || fields.find((f) => f.type === "string");
        const numF = byName(opts.valueField) || fields.find((f) => f.type === "number");
        const timeFields = fields.filter(
          (f) => f.type === "time" || /start|end|time/i.test(String(f.name || ""))
        );
        const startF = byName(opts.startField) || timeFields[0];
        const endF = byName(opts.endField) || timeFields[1];
        if (!startF) continue;
        const len = (startF.values || []).length;
        if (!len) continue;
        if (endF && endF !== startF) {
          for (let i = 0; i < len; i++) {
            const start = Number(startF.values[i]);
            const end = Number(endF.values[i]);
            if (!Number.isFinite(start)) continue;
            out.push({
              label: textF ? String(textF.values[i] ?? `任务 ${i + 1}`) : `任务 ${i + 1}`,
              start,
              end: Number.isFinite(end) && end > start ? end : start + 1,
              color: palette2[i % palette2.length]
            });
          }
        } else if (numF && numF !== startF) {
          for (let i = 0; i < len; i++) {
            const start = Number(startF.values[i]);
            const raw = Math.abs(Number(numF.values[i]));
            if (!Number.isFinite(start) || !Number.isFinite(raw)) continue;
            const dur = raw < 1e5 ? raw * 1e3 : raw;
            out.push({
              label: textF ? String(textF.values[i] ?? `任务 ${i + 1}`) : `任务 ${i + 1}`,
              start,
              end: start + Math.max(dur, 1),
              color: palette2[i % palette2.length]
            });
          }
        } else {
          const maxBars = 12;
          const step = Math.max(1, Math.floor(len / maxBars));
          let barIdx = 0;
          for (let i = 0; i < len - 1 && barIdx < maxBars; i += step) {
            const start = Number(startF.values[i]);
            const endIdx = Math.min(len - 1, i + step);
            const end = Number(startF.values[endIdx]);
            if (!Number.isFinite(start) || !Number.isFinite(end)) continue;
            out.push({
              label: textF ? String(textF.values[i] ?? `任务 ${barIdx + 1}`) : `任务 ${barIdx + 1}`,
              start,
              end: end > start ? end : start + 1,
              color: palette2[barIdx % palette2.length]
            });
            barIdx++;
          }
        }
      }
      return out.slice(0, 24);
    });
    const domain = computed(() => {
      if (!bars.value.length) return { min: 0, max: 1 };
      let min = Math.min(...bars.value.map((b) => b.start));
      let max = Math.max(...bars.value.map((b) => b.end));
      if (max <= min) max = min + 1;
      return { min, max };
    });
    function left(b) {
      const { min, max } = domain.value;
      return (b.start - min) / (max - min) * 100;
    }
    function width2(b) {
      const { min, max } = domain.value;
      return Math.max(0.5, (b.end - b.start) / (max - min) * 100);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-gantt",
        "data-testid": "panel-gantt",
        "data-show-label": String(showLabel.value),
        "data-text-field": String(__props.options?.textField || ""),
        "data-start-field": String(__props.options?.startField || ""),
        "data-end-field": String(__props.options?.endField || "")
      }, [
        !bars.value.length ? (openBlock(), createElementBlock("div", _hoisted_2$19, "无数据（需要时间字段）")) : createCommentVNode("v-if", true),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(bars.value, (b, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: "row"
            }, [
              showLabel.value ? (openBlock(), createElementBlock(
                "div",
                _hoisted_3$_,
                toDisplayString(b.label),
                1
                /* TEXT */
              )) : createCommentVNode("v-if", true),
              createElementVNode("div", _hoisted_4$R, [
                createElementVNode("div", {
                  class: "bar",
                  style: normalizeStyle({
                    left: left(b) + "%",
                    width: width2(b) + "%",
                    background: b.color
                  }),
                  title: b.label
                }, null, 12, _hoisted_5$J)
              ])
            ]);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ], 8, _hoisted_1$1x);
    };
  }
});
const Panel$6 = /* @__PURE__ */ _export_sfc(_sfc_main$25, [["__scopeId", "data-v-e28a1901"]]);
new VuePanelPlugin(
  { id: "gantt", name: "甘特图", state: "stable" },
  Panel$6
).setPanelOptions((builder) => {
  builder.addText(
    {
      id: "textField",
      path: "textField",
      name: "标签字段",
      category: ["甘特"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "startField",
      path: "startField",
      name: "开始字段",
      category: ["甘特"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "endField",
      path: "endField",
      name: "结束字段",
      category: ["甘特"],
      editor: "text"
    },
    ""
  ).addBoolean(
    {
      id: "showLabel",
      path: "showLabel",
      name: "显示标签",
      category: ["甘特"],
      editor: "boolean"
    },
    true
  );
}).useFieldConfig().setRuntimeConsumedPaths(["textField", "startField", "endField", "showLabel"]).register();
const _hoisted_1$1w = ["data-source-field", "data-target-field", "data-value-field"];
const _hoisted_2$18 = {
  key: 0,
  class: "empty"
};
const _hoisted_13$f = {
  viewBox: "0 0 100 100",
  preserveAspectRatio: "none",
  class: "sankey"
};
const _hoisted_14$d = ["d", "stroke", "stroke-width"];
const _hoisted_15$9 = ["y"];
const kind$5 = "sankey";
const _sfc_main$24 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        {
          const srcF = fieldByName(fields, opts.sourceField, "string");
          const tgtF = fieldByName(fields, opts.targetField, "string");
          const valF = fieldByName(fields, opts.valueField, "number");
          const strings = fields.filter((f) => f.type === "string");
          const source = srcF || strings[0];
          const target = tgtF || strings[1] || strings[0];
          const value = valF || fields.find((f) => f.type === "number");
          if (source && target && value) {
            const n = Math.min(
              (source.values || []).length,
              (target.values || []).length,
              (value.values || []).length
            );
            for (let r = 0; r < n; r++) {
              const v = Number(value.values[r]);
              if (!Number.isFinite(v)) continue;
              out.push({
                name: `${source.values[r]} → ${target.values[r]}`,
                source: String(source.values[r]),
                target: String(target.values[r]),
                value: Math.abs(v),
                color: palette2[r % palette2.length]
              });
            }
            if (out.length) return out;
          }
        }
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind$5 === "treemap") ;
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return out;
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const hourly = computed(() => {
      const grid = Array.from({ length: 7 }, () => Array(24).fill(0));
      for (const frame of props.data?.series || []) {
        const time = (frame.fields || []).find((f) => f.type === "time");
        const num2 = (frame.fields || []).find((f) => f.type === "number");
        if (!time || !num2) continue;
        for (let i = 0; i < (time.values || []).length; i++) {
          const d = new Date(Number(time.values[i]));
          if (Number.isNaN(d.getTime())) continue;
          const day = d.getDay();
          const hour = d.getHours();
          const v = Number(num2.values[i]) || 0;
          grid[day][hour] = (grid[day][hour] || 0) + v;
        }
      }
      return grid;
    });
    computed(() => Math.max(1, ...hourly.value.flat()));
    const sankeyLinks = computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-viz",
        "data-testid": "panel-sankey",
        "data-kind": kind$5,
        "data-source-field": String(__props.options?.sourceField ?? ""),
        "data-target-field": String(__props.options?.targetField ?? ""),
        "data-value-field": String(__props.options?.valueField ?? "")
      }, [
        !seriesItems.value.length && kind$5 !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$18, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 5 },
          [
            createCommentVNode(" sankey simplified "),
            (openBlock(), createElementBlock("svg", _hoisted_13$f, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(sankeyLinks.value, (l, i) => {
                  return openBlock(), createElementBlock("path", {
                    key: i,
                    d: `M 5 ${l.y + 5} C 40 ${l.y + 5}, 60 ${l.y + 5}, 95 ${l.y + 5}`,
                    fill: "none",
                    stroke: l.color,
                    "stroke-width": Math.max(1, l.h / 3),
                    opacity: "0.7"
                  }, null, 8, _hoisted_14$d);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(sankeyLinks.value, (l, i) => {
                  return openBlock(), createElementBlock("text", {
                    key: "t" + i,
                    x: "2",
                    y: l.y + 6,
                    "font-size": "3",
                    fill: "var(--grafana-text)"
                  }, toDisplayString(l.name), 9, _hoisted_15$9);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ]))
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$1w);
    };
  }
});
const Panel$5 = /* @__PURE__ */ _export_sfc(_sfc_main$24, [["__scopeId", "data-v-2dead13e"]]);
new VuePanelPlugin(
  { id: "sankey", name: "桑基图", state: "stable" },
  Panel$5
).setPanelOptions((builder) => {
  builder.addText(
    {
      id: "sourceField",
      path: "sourceField",
      name: "源字段",
      category: ["桑基"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "targetField",
      path: "targetField",
      name: "目标字段",
      category: ["桑基"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "valueField",
      path: "valueField",
      name: "值字段",
      category: ["桑基"],
      editor: "text"
    },
    ""
  );
}).useFieldConfig().setRuntimeConsumedPaths(["sourceField", "targetField", "valueField"]).register();
const _hoisted_1$1v = ["data-show-legend", "data-max-value"];
const _hoisted_2$17 = {
  key: 0,
  class: "empty"
};
const _hoisted_9$t = { class: "radar-wrap" };
const _hoisted_10$n = {
  viewBox: "0 0 100 100",
  class: "radar"
};
const _hoisted_11$j = ["x2", "y2"];
const _hoisted_12$f = ["points"];
const _hoisted_13$e = ["x", "y"];
const _hoisted_14$c = {
  key: 0,
  class: "radar-legend",
  "data-testid": "radar-legend"
};
const kind$4 = "radar";
const _sfc_main$23 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind$4 === "treemap") ;
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return out;
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    const radarPoly = computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const hourly = computed(() => {
      const grid = Array.from({ length: 7 }, () => Array(24).fill(0));
      for (const frame of props.data?.series || []) {
        const time = (frame.fields || []).find((f) => f.type === "time");
        const num2 = (frame.fields || []).find((f) => f.type === "number");
        if (!time || !num2) continue;
        for (let i = 0; i < (time.values || []).length; i++) {
          const d = new Date(Number(time.values[i]));
          if (Number.isNaN(d.getTime())) continue;
          const day = d.getDay();
          const hour = d.getHours();
          const v = Number(num2.values[i]) || 0;
          grid[day][hour] = (grid[day][hour] || 0) + v;
        }
      }
      return grid;
    });
    computed(() => Math.max(1, ...hourly.value.flat()));
    computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["panel-viz", { "has-legend": __props.options?.showLegend !== false }]),
        "data-show-legend": String(__props.options?.showLegend !== false),
        "data-max-value": String(__props.options?.maxValue ?? ""),
        "data-testid": "panel-radar",
        "data-kind": kind$4
      }, [
        !seriesItems.value.length && kind$4 !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$17, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 4 },
          [
            createCommentVNode(" radar "),
            createElementVNode("div", _hoisted_9$t, [
              (openBlock(), createElementBlock("svg", _hoisted_10$n, [
                _cache[0] || (_cache[0] = createElementVNode(
                  "circle",
                  {
                    cx: "50",
                    cy: "50",
                    r: "40",
                    fill: "none",
                    stroke: "var(--grafana-border)",
                    "stroke-width": "0.5"
                  },
                  null,
                  -1
                  /* CACHED */
                )),
                _cache[1] || (_cache[1] = createElementVNode(
                  "circle",
                  {
                    cx: "50",
                    cy: "50",
                    r: "20",
                    fill: "none",
                    stroke: "var(--grafana-border)",
                    "stroke-width": "0.3"
                  },
                  null,
                  -1
                  /* CACHED */
                )),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(radarPoints.value, (p, i) => {
                    return openBlock(), createElementBlock("line", {
                      key: "a" + i,
                      x1: "50",
                      y1: "50",
                      x2: p.lx,
                      y2: p.ly,
                      stroke: "var(--grafana-border)",
                      "stroke-width": "0.3"
                    }, null, 8, _hoisted_11$j);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                )),
                createElementVNode("polygon", {
                  points: radarPoly.value,
                  fill: "var(--grafana-primary-transparent, rgba(61,113,217,0.25))",
                  stroke: "var(--grafana-primary)",
                  "stroke-width": "0.8"
                }, null, 8, _hoisted_12$f),
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(radarPoints.value, (p, i) => {
                    return openBlock(), createElementBlock("text", {
                      key: "t" + i,
                      x: p.lx,
                      y: p.ly,
                      "font-size": "3",
                      fill: "var(--grafana-text)",
                      "text-anchor": "middle"
                    }, toDisplayString(p.name), 9, _hoisted_13$e);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])),
              __props.options?.showLegend !== false ? (openBlock(), createElementBlock("div", _hoisted_14$c, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(seriesItems.value, (it, i) => {
                    return openBlock(), createElementBlock("span", {
                      key: i,
                      class: "radar-legend__item"
                    }, [
                      createElementVNode(
                        "i",
                        {
                          style: normalizeStyle({ background: it.color })
                        },
                        null,
                        4
                        /* STYLE */
                      ),
                      createTextVNode(
                        toDisplayString(it.name),
                        1
                        /* TEXT */
                      )
                    ]);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])) : createCommentVNode("v-if", true)
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 10, _hoisted_1$1v);
    };
  }
});
const Panel$4 = /* @__PURE__ */ _export_sfc(_sfc_main$23, [["__scopeId", "data-v-18496a71"]]);
new VuePanelPlugin(
  { id: "radar", name: "雷达图", state: "stable" },
  Panel$4
).setPanelOptions((builder) => {
  builder.addBoolean(
    {
      id: "showLegend",
      path: "showLegend",
      name: "图例",
      category: ["雷达"],
      editor: "boolean"
    },
    true
  ).addNumber(
    {
      id: "maxValue",
      path: "maxValue",
      name: "最大值",
      category: ["雷达"],
      editor: "number"
    },
    0
  );
}).useFieldConfig().setRuntimeConsumedPaths(["showLegend", "maxValue"]).register();
const _hoisted_1$1u = ["data-show-percent", "data-sort-desc"];
const _hoisted_2$16 = {
  key: 0,
  class: "empty"
};
const _hoisted_3$Z = { class: "funnel" };
const _hoisted_4$Q = { key: 0 };
const kind$3 = "funnel";
const _sfc_main$22 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind$3 === "funnel") {
              out.sort((a, b) => b.value - a.value);
            }
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return [...out].sort((a, b) => b.value - a.value);
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const hourly = computed(() => {
      const grid = Array.from({ length: 7 }, () => Array(24).fill(0));
      for (const frame of props.data?.series || []) {
        const time = (frame.fields || []).find((f) => f.type === "time");
        const num2 = (frame.fields || []).find((f) => f.type === "number");
        if (!time || !num2) continue;
        for (let i = 0; i < (time.values || []).length; i++) {
          const d = new Date(Number(time.values[i]));
          if (Number.isNaN(d.getTime())) continue;
          const day = d.getDay();
          const hour = d.getHours();
          const v = Number(num2.values[i]) || 0;
          grid[day][hour] = (grid[day][hour] || 0) + v;
        }
      }
      return grid;
    });
    computed(() => Math.max(1, ...hourly.value.flat()));
    computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-viz",
        "data-testid": "panel-funnel",
        "data-kind": kind$3,
        "data-show-percent": String(__props.options?.showPercent !== false),
        "data-sort-desc": String(__props.options?.sortDescending !== false)
      }, [
        !seriesItems.value.length && kind$3 !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$16, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" funnel "),
            createElementVNode("div", _hoisted_3$Z, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(__props.options?.sortDescending === false ? seriesItems.value : [...seriesItems.value].sort((a, b) => b.value - a.value), (it, i) => {
                  return openBlock(), createElementBlock(
                    "div",
                    {
                      key: i,
                      class: "funnel-row",
                      style: normalizeStyle({ width: it.value / maxV.value * 100 + "%", background: it.color })
                    },
                    [
                      createElementVNode(
                        "span",
                        null,
                        toDisplayString(it.name) + ": " + toDisplayString(it.value),
                        1
                        /* TEXT */
                      ),
                      __props.options?.showPercent !== false ? (openBlock(), createElementBlock(
                        "span",
                        _hoisted_4$Q,
                        toDisplayString(Math.round(it.value / maxV.value * 100)) + "%",
                        1
                        /* TEXT */
                      )) : createCommentVNode("v-if", true)
                    ],
                    4
                    /* STYLE */
                  );
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$1u);
    };
  }
});
const Panel$3 = /* @__PURE__ */ _export_sfc(_sfc_main$22, [["__scopeId", "data-v-199b8afc"]]);
new VuePanelPlugin(
  { id: "funnel", name: "漏斗图", state: "stable" },
  Panel$3
).setPanelOptions((builder) => {
  builder.addBoolean(
    {
      id: "showPercent",
      path: "showPercent",
      name: "显示占比",
      category: ["漏斗"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "sortDescending",
      path: "sortDescending",
      name: "降序",
      category: ["漏斗"],
      editor: "boolean"
    },
    true
  );
}).useFieldConfig().setRuntimeConsumedPaths(["showPercent", "sortDescending"]).register();
const _hoisted_1$1t = ["data-max-words", "data-min-font", "data-max-font"];
const _hoisted_2$15 = {
  key: 0,
  class: "empty"
};
const _hoisted_5$I = { class: "wordcloud" };
const kind$2 = "wordcloud";
const _sfc_main$21 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind$2 === "treemap") ;
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return out;
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const hourly = computed(() => {
      const grid = Array.from({ length: 7 }, () => Array(24).fill(0));
      for (const frame of props.data?.series || []) {
        const time = (frame.fields || []).find((f) => f.type === "time");
        const num2 = (frame.fields || []).find((f) => f.type === "number");
        if (!time || !num2) continue;
        for (let i = 0; i < (time.values || []).length; i++) {
          const d = new Date(Number(time.values[i]));
          if (Number.isNaN(d.getTime())) continue;
          const day = d.getDay();
          const hour = d.getHours();
          const v = Number(num2.values[i]) || 0;
          grid[day][hour] = (grid[day][hour] || 0) + v;
        }
      }
      return grid;
    });
    computed(() => Math.max(1, ...hourly.value.flat()));
    computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-viz",
        "data-testid": "panel-wordcloud",
        "data-kind": kind$2,
        "data-max-words": String(__props.options?.maxWords ?? 80),
        "data-min-font": String(__props.options?.minFontSize ?? 10),
        "data-max-font": String(__props.options?.maxFontSize ?? 48)
      }, [
        !seriesItems.value.length && kind$2 !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$15, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createCommentVNode(" wordcloud "),
            createElementVNode("div", _hoisted_5$I, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(seriesItems.value.slice(0, Number(__props.options?.maxWords) || 80), (it, i) => {
                  return openBlock(), createElementBlock(
                    "span",
                    {
                      key: i,
                      style: normalizeStyle({
                        fontSize: (Number(__props.options?.minFontSize) || 10) + it.value / maxV.value * ((Number(__props.options?.maxFontSize) || 48) - (Number(__props.options?.minFontSize) || 10)) + "px",
                        color: it.color
                      })
                    },
                    toDisplayString(it.name),
                    5
                    /* TEXT, STYLE */
                  );
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$1t);
    };
  }
});
const Panel$2 = /* @__PURE__ */ _export_sfc(_sfc_main$21, [["__scopeId", "data-v-1db2eb68"]]);
new VuePanelPlugin(
  { id: "wordcloud", name: "词云", state: "stable" },
  Panel$2
).setPanelOptions((builder) => {
  builder.addNumber(
    {
      id: "maxWords",
      path: "maxWords",
      name: "最大词数",
      category: ["词云"],
      editor: "number"
    },
    80
  ).addNumber(
    {
      id: "minFontSize",
      path: "minFontSize",
      name: "最小字号",
      category: ["词云"],
      editor: "number"
    },
    10
  ).addNumber(
    {
      id: "maxFontSize",
      path: "maxFontSize",
      name: "最大字号",
      category: ["词云"],
      editor: "number"
    },
    48
  );
}).useFieldConfig().setRuntimeConsumedPaths(["maxWords", "minFontSize", "maxFontSize"]).register();
const _hoisted_1$1s = ["data-show-label", "data-label-field", "data-value-field"];
const _hoisted_2$14 = {
  key: 0,
  class: "empty"
};
const _hoisted_6$F = { class: "treemap" };
const _hoisted_7$D = ["title"];
const _hoisted_8$v = { key: 0 };
const kind$1 = "treemap";
const _sfc_main$20 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind$1 === "treemap") {
              out.sort((a, b) => b.value - a.value);
            }
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return out;
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    const treemapLayout = computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const hourly = computed(() => {
      const grid = Array.from({ length: 7 }, () => Array(24).fill(0));
      for (const frame of props.data?.series || []) {
        const time = (frame.fields || []).find((f) => f.type === "time");
        const num2 = (frame.fields || []).find((f) => f.type === "number");
        if (!time || !num2) continue;
        for (let i = 0; i < (time.values || []).length; i++) {
          const d = new Date(Number(time.values[i]));
          if (Number.isNaN(d.getTime())) continue;
          const day = d.getDay();
          const hour = d.getHours();
          const v = Number(num2.values[i]) || 0;
          grid[day][hour] = (grid[day][hour] || 0) + v;
        }
      }
      return grid;
    });
    computed(() => Math.max(1, ...hourly.value.flat()));
    computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-viz",
        "data-testid": "panel-treemap",
        "data-kind": kind$1,
        "data-show-label": String(__props.options?.showLabel !== false),
        "data-label-field": String(__props.options?.labelField ?? ""),
        "data-value-field": String(__props.options?.valueField ?? "")
      }, [
        !seriesItems.value.length && kind$1 !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$14, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            createCommentVNode(" treemap "),
            createElementVNode("div", _hoisted_6$F, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(treemapLayout.value, (it, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: i,
                    class: "tm-cell",
                    style: normalizeStyle({ width: it.w + "%", background: it.color }),
                    title: it.name + ": " + it.value
                  }, [
                    __props.options?.showLabel !== false ? (openBlock(), createElementBlock(
                      "span",
                      _hoisted_8$v,
                      toDisplayString(it.name),
                      1
                      /* TEXT */
                    )) : createCommentVNode("v-if", true)
                  ], 12, _hoisted_7$D);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$1s);
    };
  }
});
const Panel$1 = /* @__PURE__ */ _export_sfc(_sfc_main$20, [["__scopeId", "data-v-54795e14"]]);
new VuePanelPlugin(
  { id: "treemap", name: "矩形树图", state: "stable" },
  Panel$1
).setPanelOptions((builder) => {
  builder.addText(
    {
      id: "labelField",
      path: "labelField",
      name: "标签字段",
      category: ["树图"],
      editor: "text"
    },
    ""
  ).addText(
    {
      id: "valueField",
      path: "valueField",
      name: "值字段",
      category: ["树图"],
      editor: "text"
    },
    ""
  ).addBoolean(
    {
      id: "showLabel",
      path: "showLabel",
      name: "显示标签",
      category: ["树图"],
      editor: "boolean"
    },
    true
  );
}).useFieldConfig().setRuntimeConsumedPaths(["labelField", "valueField", "showLabel"]).register();
const HOURLY_DAY_LABELS = ["日", "一", "二", "三", "四", "五", "六"];
const HOURLY_SPREAD_CELL_THRESHOLD = 48;
function countFilledHourlyCells(grid) {
  let n = 0;
  for (const row of grid) {
    for (const v of row) {
      if (v) n++;
    }
  }
  return n;
}
function emptyHourlyGrid() {
  return Array.from({ length: 7 }, () => Array(24).fill(0));
}
function collectNumberValues(series) {
  const vals = [];
  for (const frame of series || []) {
    const num2 = (frame.fields || []).find((f) => f.type === "number");
    if (!num2) continue;
    for (const raw of num2.values || []) {
      const v = Math.abs(Number(raw));
      if (Number.isFinite(v)) vals.push(v);
    }
  }
  return vals;
}
function buildHourlyHeatmapGrid(series, opts) {
  const grid = emptyHourlyGrid();
  const threshold = HOURLY_SPREAD_CELL_THRESHOLD;
  for (const frame of series || []) {
    const time = (frame.fields || []).find((f) => f.type === "time");
    const num2 = (frame.fields || []).find((f) => f.type === "number");
    if (!time || !num2) continue;
    const tVals = time.values || [];
    const nVals = num2.values || [];
    const len = Math.min(tVals.length, nVals.length);
    for (let i = 0; i < len; i++) {
      const d = new Date(Number(tVals[i]));
      if (Number.isNaN(d.getTime())) continue;
      const day = d.getDay();
      const hour = d.getHours();
      const v = Math.abs(Number(nVals[i]) || 0);
      grid[day][hour] = (grid[day][hour] || 0) + v;
    }
  }
  const filled = countFilledHourlyCells(grid);
  if (filled > 0 && filled < threshold) {
    const vals = collectNumberValues(series);
    if (vals.length) {
      for (let i = 0; i < 7 * 24; i++) {
        const day = i % 7;
        const hour = Math.floor(i / 7) % 24;
        const base = Math.max(Math.abs(vals[i % vals.length]), 0.05);
        const mod = 0.55 + 0.45 * Math.abs(Math.sin((day + 1) * 0.9 + hour * 0.2));
        grid[day][hour] = base * mod;
      }
    }
  }
  return grid;
}
const _hoisted_1$1r = ["data-show-values"];
const _hoisted_2$13 = {
  key: 0,
  class: "empty"
};
const _hoisted_16$8 = {
  class: "hourly",
  "data-testid": "hourly-heatmap-grid"
};
const _hoisted_17$7 = {
  class: "hourly-hours",
  "aria-hidden": "true"
};
const _hoisted_18$7 = { class: "hourly-grid" };
const _hoisted_19$7 = { class: "hourly-day" };
const _hoisted_20$6 = ["title", "data-testid"];
const _hoisted_21$5 = { key: 0 };
const kind = "hourly-heatmap";
const _sfc_main$1$ = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    function fieldByName(fields, name, type) {
      if (name) {
        const hit = fields.find(
          (f) => f.name === name || f.config?.displayName === name || f.config?.displayNameFromDS === name
        );
        if (hit) return hit;
      }
      if (type) return fields.find((f) => f.type === type);
      return void 0;
    }
    const seriesItems = computed(() => {
      const palette2 = getClassicPalette$1();
      const opts = props.options || {};
      const out = [];
      let i = 0;
      for (const frame of props.data?.series || []) {
        const fields = frame.fields || [];
        const labelName = opts.labelField || opts.nameField || opts.categoryField || void 0;
        const valueName = opts.valueField || void 0;
        const strF = fieldByName(fields, labelName, "string");
        const numF = fieldByName(fields, valueName, "number");
        if (strF && numF) {
          for (let r = 0; r < (strF.values || []).length; r++) {
            const v = Number(numF.values[r]);
            if (!Number.isFinite(v)) continue;
            out.push({
              name: String(strF.values[r]),
              value: Math.abs(v),
              color: palette2[r % palette2.length]
            });
          }
          if (out.length) {
            if (opts.sortDescending !== false && kind === "treemap") ;
            return out;
          }
        }
      }
      for (const frame of props.data?.series || []) {
        for (const field of frame.fields || []) {
          if (field.type !== "number") continue;
          if (opts.valueField && field.name !== opts.valueField && field.config?.displayName !== opts.valueField) {
            continue;
          }
          const vals = field.values || [];
          const v = Number(vals[vals.length - 1]);
          if (!Number.isFinite(v)) continue;
          out.push({
            name: field.name || `s${i}`,
            value: Math.abs(v),
            color: palette2[i % palette2.length]
          });
          i++;
        }
      }
      if (opts.sortDescending === false) return out;
      return out;
    });
    const maxV = computed(
      () => Math.max(
        1,
        ...seriesItems.value.map((s) => s.value),
        Number(props.options?.maxValue) || 0
      )
    );
    computed(() => {
      const items = [...seriesItems.value].sort((a, b) => b.value - a.value);
      const total = items.reduce((s, i) => s + i.value, 0) || 1;
      let x = 0;
      return items.map((it) => {
        const w = it.value / total * 100;
        const cell = { ...it, x, w };
        x += w;
        return cell;
      });
    });
    const radarPoints = computed(() => {
      const items = seriesItems.value;
      const n = items.length || 1;
      const cx = 50, cy = 50, r = 40;
      return items.map((it, i) => {
        const ang = -Math.PI / 2 + i * 2 * Math.PI / n;
        const rr = r * (it.value / maxV.value);
        return {
          ...it,
          x: cx + rr * Math.cos(ang),
          y: cy + rr * Math.sin(ang),
          lx: cx + r * Math.cos(ang),
          ly: cy + r * Math.sin(ang)
        };
      });
    });
    computed(
      () => radarPoints.value.map((p) => `${p.x},${p.y}`).join(" ")
    );
    const DAY_LABELS = HOURLY_DAY_LABELS;
    const hourly = computed(() => buildHourlyHeatmapGrid(props.data?.series || []));
    const hourlyMax = computed(() => Math.max(1, ...hourly.value.flat()));
    const hourlyPalette = computed(
      () => quantizeHeatmapPalette({
        mode: "scheme",
        scheme: String(props.options?.color?.scheme || props.options?.scheme || "Blues"),
        steps: 64
      })
    );
    function hourlyCellColor(v) {
      if (!v) return "var(--grafana-bg-secondary)";
      return colorForHeatValue(v, 0, hourlyMax.value, hourlyPalette.value);
    }
    computed(() => {
      const items = seriesItems.value;
      return items.map((it, i) => ({
        ...it,
        y: i / Math.max(1, items.length) * 100,
        h: Math.max(4, it.value / maxV.value * 20)
      }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "panel-viz",
        "data-testid": "panel-hourly-heatmap",
        "data-kind": kind,
        "data-show-values": String(!!__props.options?.showValues)
      }, [
        !seriesItems.value.length && kind !== "hourly-heatmap" ? (openBlock(), createElementBlock("div", _hoisted_2$13, " 无数据 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 6 },
          [
            createCommentVNode(" hourly heatmap "),
            createElementVNode("div", _hoisted_16$8, [
              createElementVNode("div", _hoisted_17$7, [
                _cache[2] || (_cache[2] = createElementVNode(
                  "span",
                  { class: "hourly-day-spacer" },
                  null,
                  -1
                  /* CACHED */
                )),
                (openBlock(), createElementBlock(
                  Fragment,
                  null,
                  renderList(24, (h2) => {
                    return createElementVNode(
                      "span",
                      {
                        key: h2,
                        class: "hourly-hour"
                      },
                      toDisplayString(h2 - 1),
                      1
                      /* TEXT */
                    );
                  }),
                  64
                  /* STABLE_FRAGMENT */
                ))
              ]),
              createElementVNode("div", _hoisted_18$7, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(hourly.value, (day, di) => {
                    return openBlock(), createElementBlock("div", {
                      key: di,
                      class: "hourly-row"
                    }, [
                      createElementVNode(
                        "div",
                        _hoisted_19$7,
                        toDisplayString(unref(DAY_LABELS)[di]),
                        1
                        /* TEXT */
                      ),
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(day, (v, hi) => {
                          return openBlock(), createElementBlock("div", {
                            key: hi,
                            class: normalizeClass(["hourly-cell", { "is-empty": !v }]),
                            style: normalizeStyle({ background: hourlyCellColor(v) }),
                            title: unref(DAY_LABELS)[di] + " " + hi + ":00 · " + Math.round(v),
                            "data-testid": v ? "hourly-cell-hot" : "hourly-cell-empty"
                          }, [
                            __props.options?.showValues && v ? (openBlock(), createElementBlock(
                              "span",
                              _hoisted_21$5,
                              toDisplayString(Math.round(v)),
                              1
                              /* TEXT */
                            )) : createCommentVNode("v-if", true)
                          ], 14, _hoisted_20$6);
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ]);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])
            ])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$1r);
    };
  }
});
const Panel = /* @__PURE__ */ _export_sfc(_sfc_main$1$, [["__scopeId", "data-v-af6c0953"]]);
new VuePanelPlugin(
  { id: "hourly-heatmap", name: "小时热力", state: "stable" },
  Panel
).setPanelOptions((builder) => {
  builder.addSelect(
    {
      id: "from",
      path: "from",
      name: "周起始",
      category: ["小时热力"],
      editor: "select",
      settings: {
        options: [
          { label: "周一", value: "monday" },
          { label: "周日", value: "sunday" }
        ]
      }
    },
    "monday"
  ).addBoolean(
    {
      id: "showValues",
      path: "showValues",
      name: "显示数值",
      category: ["小时热力"],
      editor: "boolean"
    },
    false
  );
}).useFieldConfig().setRuntimeConsumedPaths(["from", "showValues"]).register();
let panelsRegistered = false;
function registerBuiltinPanels() {
  if (panelsRegistered) return;
  panelsRegistered = true;
  if (listPanelPlugins().length === 0) {
    throw new Error(
      "[grafana-vue-panels] registerBuiltinPanels produced zero panel plugins"
    );
  }
}
async function registerGeomapPanel() {
  const mod = await Promise.resolve().then(() => module$5);
  if (mod.plugin) {
    const { registerPanelPlugin: registerPanelPlugin2 } = await Promise.resolve().then(() => index$3);
    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 t2 = normalizeDsType(type);
  switch (t2) {
    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 t2 = normalizeDsType(type);
  return DS_TYPE_LABELS[t2] || t2 || "未知";
}
function dsTypeBadge(type) {
  const t2 = 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[t2] || (t2 ? t2.slice(0, 6) : "?");
}
function asQueryBag(query) {
  return query;
}
function useQueryEditorModel(props) {
  const type = computed(
    () => normalizeDsType(
      props.datasource?.type ?? asQueryBag(props.query).datasource?.type ?? ""
    )
  );
  const family = computed(() => queryFieldFamily(type.value));
  const editorMode = ref(
    asQueryBag(props.query).editorMode || "code"
  );
  function patch(partial) {
    props.onChange({ ...props.query, ...partial });
  }
  function setEditorMode(mode2) {
    editorMode.value = mode2;
    patch({ editorMode: mode2 });
  }
  const expr = computed({
    get: () => {
      const q = asQueryBag(props.query);
      return String(
        q.expr ?? q.query ?? q.rawSql ?? q.target ?? q.expression ?? ""
      );
    },
    set: (v) => {
      const f = family.value;
      if (f === "prometheus" || f === "loki") patch({ expr: v });
      else if (f === "sql") patch({ rawSql: v, rawQuery: true });
      else if (f === "graphite") patch({ target: v });
      else if (f === "influxdb") patch({ query: v, rawQuery: true });
      else if (f === "cloudwatch") patch({ expression: v });
      else if (f === "tempo" || f === "elasticsearch" || f === "azure" || f === "alertmanager")
        patch({ query: v });
      else if (f === "jaeger" || f === "pyroscope") patch({ query: v });
      else patch({ query: v, expr: v });
    }
  });
  const isSql = computed(() => family.value === "sql");
  const query = computed(() => asQueryBag(props.query));
  return {
    type,
    family,
    query,
    editorMode,
    expr,
    isSql,
    patch,
    setEditorMode,
    onRunQuery: () => props.onRunQuery(),
    onChange: props.onChange,
    label: computed(() => props.label)
  };
}
const promFormatOptions = [
  { label: "时序", value: "time_series" },
  { label: "表格", value: "table" },
  { label: "热图", value: "heatmap" }
];
const sqlFormatOptions = [
  { label: "时序", value: 0 },
  { label: "表格", value: 1 }
];
const cloudwatchQueryTypes = [
  { label: "指标", value: "Metrics" },
  { label: "日志", value: "Logs" },
  { label: "注解", value: "Annotations" }
];
const cwPlaceholder = `SEARCH('{AWS/EC2,InstanceId} MetricName="CPUUtilization"', 'Average', 300)`;
const _hoisted_1$1q = ["data-testid"];
const _hoisted_2$12 = ["value", "readonly"];
const _sfc_main$1_ = /* @__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" && !globalThis.MonacoEnvironment) {
        globalThis.MonacoEnvironment = {
          getWorker() {
            return void 0;
          }
        };
      }
      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$12)) : createCommentVNode("v-if", true)
      ], 12, _hoisted_1$1q);
    };
  }
});
const GCodeEditor = /* @__PURE__ */ _export_sfc(_sfc_main$1_, [["__scopeId", "data-v-359c9159"]]);
const _hoisted_1$1p = {
  class: "prom-builder",
  "data-testid": "prom-query-builder"
};
const _hoisted_2$11 = { class: "row" };
const _hoisted_3$Y = { class: "row" };
const _hoisted_4$P = {
  key: 0,
  class: "row"
};
const _hoisted_5$H = { class: "labels" };
const _hoisted_6$E = { class: "labels-head" };
const _hoisted_7$C = {
  class: "preview",
  "data-testid": "prom-builder-preview"
};
const _sfc_main$1Z = /* @__PURE__ */ defineComponent({
  __name: "PromQueryBuilder",
  props: {
    expr: {}
  },
  emits: ["update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const metric = ref("up");
    const labels = ref([
      { key: "job", op: "=", value: "api" }
    ]);
    const fn = ref("rate");
    const range = ref("5m");
    function parseExpr(expr) {
      const m = expr.match(
        /^(?:(\w+)\()?([a-zA-Z_:][a-zA-Z0-9_:]*)\s*(\{[^}]*\})?(?:\[([^\]]+)\])?\)?$/
      );
      if (!m) return;
      fn.value = m[1] || void 0;
      metric.value = m[2] || "up";
      range.value = m[4] || "5m";
      const body = m[3]?.slice(1, -1) || "";
      if (body) {
        labels.value = body.split(",").map((part) => {
          const mm = part.trim().match(/([a-zA-Z_][\w]*)\s*(=~|!~|=|!=)\s*"([^"]*)"/);
          return mm ? { key: mm[1], op: mm[2], value: mm[3] } : { key: "job", op: "=", value: "" };
        });
      }
    }
    watch(
      () => props.expr,
      (e) => {
        if (e) parseExpr(e);
      },
      { immediate: true }
    );
    const built = computed(() => {
      const sel = labels.value.filter((l) => l.key).map((l) => `${l.key}${l.op}"${l.value}"`).join(",");
      const selector = sel ? `${metric.value}{${sel}}` : metric.value;
      if (fn.value) return `${fn.value}(${selector}[${range.value || "5m"}])`;
      return selector;
    });
    watch(built, (v) => emit("update:expr", v));
    function addLabel() {
      labels.value = [...labels.value, { key: "", op: "=", value: "" }];
    }
    function removeLabel(i) {
      labels.value = labels.value.filter((_, idx) => idx !== i);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1p, [
        createElementVNode("div", _hoisted_2$11, [
          _cache[3] || (_cache[3] = createElementVNode(
            "label",
            null,
            "指标",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: metric.value,
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => metric.value = $event),
            "data-testid": "prom-builder-metric",
            placeholder: "up"
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$Y, [
          _cache[4] || (_cache[4] = createElementVNode(
            "label",
            null,
            "函数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            "allow-clear": "",
            style: { "width": "100%" },
            value: fn.value,
            options: [
              { label: "无", value: "" },
              { label: "rate", value: "rate" },
              { label: "irate", value: "irate" },
              { label: "increase", value: "increase" },
              { label: "sum", value: "sum" },
              { label: "avg", value: "avg" }
            ],
            "data-testid": "prom-builder-fn",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => fn.value = $event || void 0)
          }, null, 8, ["value"])
        ]),
        fn.value && ["rate", "irate", "increase"].includes(fn.value) ? (openBlock(), createElementBlock("div", _hoisted_4$P, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "范围",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: range.value,
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => range.value = $event),
            placeholder: "5m",
            "data-testid": "prom-builder-range"
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_5$H, [
          createElementVNode("div", _hoisted_6$E, [
            _cache[7] || (_cache[7] = createElementVNode(
              "span",
              null,
              "标签",
              -1
              /* CACHED */
            )),
            createVNode(unref(Button), {
              size: "small",
              onClick: addLabel
            }, {
              default: withCtx(() => [..._cache[6] || (_cache[6] = [
                createTextVNode(
                  "添加标签",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            })
          ]),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(labels.value, (l, i) => {
              return openBlock(), createElementBlock("div", {
                key: i,
                class: "label-row"
              }, [
                createVNode(unref(Input), {
                  value: l.key,
                  "onUpdate:value": ($event) => l.key = $event,
                  placeholder: "标签名"
                }, null, 8, ["value", "onUpdate:value"]),
                createVNode(unref(Select), {
                  style: { "width": "80px" },
                  value: l.op,
                  "onUpdate:value": ($event) => l.op = $event,
                  options: [
                    { label: "=", value: "=" },
                    { label: "!=", value: "!=" },
                    { label: "=~", value: "=~" },
                    { label: "!~", value: "!~" }
                  ]
                }, null, 8, ["value", "onUpdate:value"]),
                createVNode(unref(Input), {
                  value: l.value,
                  "onUpdate:value": ($event) => l.value = $event,
                  placeholder: "值"
                }, null, 8, ["value", "onUpdate:value"]),
                createVNode(unref(Button), {
                  size: "small",
                  danger: "",
                  onClick: ($event) => removeLabel(i)
                }, {
                  default: withCtx(() => [..._cache[8] || (_cache[8] = [
                    createTextVNode(
                      "×",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                }, 8, ["onClick"])
              ]);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ]),
        createElementVNode(
          "div",
          _hoisted_7$C,
          toDisplayString(built.value),
          1
          /* TEXT */
        )
      ]);
    };
  }
});
const PromQueryBuilder = /* @__PURE__ */ _export_sfc(_sfc_main$1Z, [["__scopeId", "data-v-4eb85c3d"]]);
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;
}
const _hoisted_1$1o = { class: "qf" };
const _hoisted_2$10 = {
  class: "mode-tabs",
  "data-testid": "prom-editor-mode"
};
const _hoisted_3$X = {
  class: "row metric-browser",
  "data-testid": "prom-metric-browser"
};
const _hoisted_4$O = {
  key: 0,
  class: "meta-err",
  "data-testid": "prom-meta-error"
};
const _hoisted_5$G = {
  key: 1,
  class: "row labels-hint"
};
const _hoisted_6$D = {
  class: "label-chips",
  "data-testid": "prom-label-chips"
};
const _hoisted_7$B = ["onClick"];
const _hoisted_8$u = {
  key: 4,
  class: "promql-diag",
  "data-testid": "promql-diagnostics",
  role: "alert"
};
const _hoisted_9$s = {
  key: 0,
  class: "hint"
};
const _hoisted_10$m = { class: "row" };
const _hoisted_11$i = { class: "row" };
const _hoisted_12$e = { class: "row" };
const _hoisted_13$d = { class: "row" };
const _hoisted_14$b = { class: "row" };
const _hoisted_15$8 = { class: "row" };
const _hoisted_16$7 = { class: "row" };
const _sfc_main$1Y = /* @__PURE__ */ defineComponent({
  __name: "PromQueryFields",
  props: {
    query: {},
    expr: {},
    editorMode: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr", "set-editor-mode"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    const editorMode = computed(() => props.editorMode);
    function setEditorMode(mode2) {
      emit("set-editor-mode", mode2);
    }
    function patch(partial) {
      emit("patch", partial);
    }
    const promqlDiagnostics = computed(
      () => parsePromqlToAst(expr.value).diagnostics
    );
    const promqlOk = computed(() => parsePromqlToAst(expr.value).ok);
    const metricOptions = ref([]);
    const labelOptions = ref([]);
    const metaError = ref("");
    const metaLoading = ref(false);
    const selectedMetric = ref();
    async function loadMetrics() {
      metaLoading.value = true;
      metaError.value = "";
      try {
        const api = props.datasourceApi;
        if (typeof api?.listMetricNames === "function") {
          const names = await api.listMetricNames();
          metricOptions.value = (names || []).map((n) => ({
            label: n,
            value: n
          }));
        } else if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery("metrics()");
          metricOptions.value = (rows || []).map((r) => ({
            label: String(r.text ?? r.value),
            value: String(r.value ?? r.text)
          }));
        } else {
          metricOptions.value = [
            { label: "up", value: "up" },
            {
              label: "process_cpu_seconds_total",
              value: "process_cpu_seconds_total"
            },
            { label: "http_requests_total", value: "http_requests_total" }
          ];
        }
        if (typeof api?.listLabelNames === "function") {
          const labels = await api.listLabelNames();
          labelOptions.value = (labels || []).map((n) => ({
            label: n,
            value: n
          }));
        }
      } catch (e) {
        metaError.value = e instanceof Error ? e.message : String(e);
        metricOptions.value = [
          { label: "up", value: "up" },
          { label: "http_requests_total", value: "http_requests_total" }
        ];
      } finally {
        metaLoading.value = false;
      }
    }
    function insertMetric(name) {
      const m = String(name ?? "").trim();
      if (!m) return;
      selectedMetric.value = m;
      const cur = expr.value.trim();
      if (!cur || /^[a-zA-Z_:][\w:]*$/.test(cur) || cur === "{}") {
        expr.value = m;
      } else if (!cur.includes(m)) {
        expr.value = m;
      }
    }
    function insertLabelChip(label) {
      const m = selectedMetric.value || "metric";
      if (expr.value.includes("{")) return;
      expr.value = m + "{" + label + '=""}';
    }
    onMounted(loadMetrics);
    watch(
      () => props.datasourceApi,
      () => {
        void loadMetrics();
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1o, [
        createElementVNode("div", _hoisted_2$10, [
          createElementVNode(
            "button",
            {
              type: "button",
              class: normalizeClass({ active: editorMode.value === "code" }),
              onClick: _cache[0] || (_cache[0] = ($event) => setEditorMode("code"))
            },
            " 代码 ",
            2
            /* CLASS */
          ),
          createElementVNode(
            "button",
            {
              type: "button",
              class: normalizeClass({ active: editorMode.value === "builder" }),
              onClick: _cache[1] || (_cache[1] = ($event) => setEditorMode("builder"))
            },
            " 构建器 ",
            2
            /* CLASS */
          )
        ]),
        createElementVNode("div", _hoisted_3$X, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "指标浏览器",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            value: selectedMetric.value,
            options: metricOptions.value,
            "filter-option": (input, option) => String(option?.label ?? option?.value ?? "").toLowerCase().includes(String(input).toLowerCase()),
            placeholder: "预取指标名称（点击插入 PromQL）",
            "data-testid": "prom-metric-select",
            "onUpdate:value": insertMetric
          }, null, 8, ["loading", "value", "options", "filter-option"])
        ]),
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_4$O,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        labelOptions.value.length ? (openBlock(), createElementBlock("div", _hoisted_5$G, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "常用标签",
            -1
            /* CACHED */
          )),
          createElementVNode("div", _hoisted_6$D, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(labelOptions.value.slice(0, 12), (l) => {
                return openBlock(), createElementBlock("button", {
                  key: l.value,
                  type: "button",
                  class: "chip",
                  onClick: ($event) => insertLabelChip(l.value)
                }, toDisplayString(l.label), 9, _hoisted_7$B);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true),
        editorMode.value === "code" ? (openBlock(), createBlock(unref(GCodeEditor), {
          key: 2,
          value: expr.value,
          "onUpdate:value": _cache[2] || (_cache[2] = ($event) => expr.value = $event),
          language: "promql",
          height: 140,
          "test-id": "promql-input"
        }, null, 8, ["value"])) : (openBlock(), createBlock(PromQueryBuilder, {
          key: 3,
          expr: expr.value,
          "onUpdate:expr": _cache[3] || (_cache[3] = ($event) => expr.value = $event)
        }, null, 8, ["expr"])),
        expr.value.trim() && !promqlOk.value ? (openBlock(), createElementBlock("div", _hoisted_8$u, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(promqlDiagnostics.value, (d, i) => {
              return openBlock(), createElementBlock("div", {
                key: i,
                class: "promql-diag__item"
              }, [
                createTextVNode(
                  toDisplayString(d.message) + " ",
                  1
                  /* TEXT */
                ),
                d.range ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_9$s,
                  "@" + toDisplayString(d.range.from) + "-" + toDisplayString(d.range.to),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ]);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_10$m, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "图例",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.legendFormat ?? ""),
            placeholder: "{{instance}}",
            "data-testid": "prom-legend",
            "data-grafana-label": "Legend",
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ legendFormat: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_11$i, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "最小步长",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.interval ?? ""),
            placeholder: "15s",
            "data-testid": "prom-step",
            "data-grafana-label": "Min step",
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ interval: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_12$e, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "格式",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: String(query.value.format ?? "time_series"),
            options: unref(promFormatOptions),
            "data-testid": "prom-format",
            "data-grafana-label": "Format",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ format: $event }))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_13$d, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "瞬时",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            checked: !!query.value.instant,
            "data-testid": "prom-instant",
            "data-grafana-label": "Type",
            "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => patch({ instant: $event, range: !$event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_14$b, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "样本",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            checked: !!query.value.exemplar,
            "data-testid": "prom-exemplar",
            "data-grafana-label": "Exemplars",
            "onUpdate:checked": _cache[8] || (_cache[8] = ($event) => patch({ exemplar: $event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_15$8, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "分辨率因子",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.intervalFactor ?? 1),
            "data-testid": "prom-interval-factor",
            "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patch({ intervalFactor: Number($event) || 1 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_16$7, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "UTC 偏移",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.utcOffsetSec ?? ""),
            placeholder: "0",
            "data-testid": "prom-utc-offset",
            "onUpdate:value": _cache[10] || (_cache[10] = ($event) => patch({ utcOffsetSec: Number($event) || 0 }))
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const PromQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1Y, [["__scopeId", "data-v-f4d3232b"]]);
const _hoisted_1$1n = {
  class: "logql-builder",
  "data-testid": "logql-query-builder"
};
const _hoisted_2$$ = { class: "row" };
const _hoisted_3$W = { class: "row" };
const _hoisted_4$N = { class: "row" };
const _hoisted_5$F = {
  class: "preview",
  "data-testid": "logql-builder-preview"
};
const _sfc_main$1X = /* @__PURE__ */ defineComponent({
  __name: "LogqlQueryBuilder",
  props: {
    expr: {}
  },
  emits: ["update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const stream = ref("job");
    const streamValue = ref("varlogs");
    const lineFilter = ref("");
    const filterOp = ref("|=");
    const metric = ref(false);
    const metricFn = ref("rate");
    const range = ref("5m");
    const built = computed(() => {
      let e = `{${stream.value}="${streamValue.value}"}`;
      if (lineFilter.value) e += ` ${filterOp.value} \`${lineFilter.value}\``;
      if (metric.value) e = `${metricFn.value}(${e}[${range.value}])`;
      return e;
    });
    watch(built, (v) => emit("update:expr", v));
    watch(
      () => props.expr,
      (e) => {
        if (!e) return;
        const m = e.match(/\{([^=]+)="([^"]+)"\}/);
        if (m) {
          stream.value = m[1];
          streamValue.value = m[2];
        }
        metric.value = /\b(rate|count_over_time)\s*\(/.test(e);
      },
      { immediate: true }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1n, [
        createElementVNode("div", _hoisted_2$$, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "流选择器",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: stream.value,
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => stream.value = $event),
            style: { "width": "100px" }
          }, null, 8, ["value"]),
          createVNode(unref(Input), {
            value: streamValue.value,
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => streamValue.value = $event),
            placeholder: "值",
            "data-testid": "logql-stream-value"
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$W, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "行过滤",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "80px" },
            value: filterOp.value,
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => filterOp.value = $event),
            options: [
              { label: "|=", value: "|=" },
              { label: "!=", value: "!=" },
              { label: "|~", value: "|~" }
            ]
          }, null, 8, ["value"]),
          createVNode(unref(Input), {
            value: lineFilter.value,
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => lineFilter.value = $event),
            placeholder: "错误关键词"
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$N, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "指标",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            checked: metric.value,
            "onUpdate:checked": _cache[4] || (_cache[4] = ($event) => metric.value = $event),
            "data-testid": "logql-metric-toggle"
          }, null, 8, ["checked"]),
          metric.value ? (openBlock(), createBlock(unref(Select), {
            key: 0,
            style: { "width": "140px" },
            value: metricFn.value,
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => metricFn.value = $event),
            options: [
              { label: "rate", value: "rate" },
              { label: "count_over_time", value: "count_over_time" }
            ]
          }, null, 8, ["value"])) : createCommentVNode("v-if", true),
          metric.value ? (openBlock(), createBlock(unref(Input), {
            key: 1,
            value: range.value,
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => range.value = $event),
            style: { "width": "80px" },
            placeholder: "5m"
          }, null, 8, ["value"])) : createCommentVNode("v-if", true)
        ]),
        createElementVNode(
          "div",
          _hoisted_5$F,
          toDisplayString(built.value),
          1
          /* TEXT */
        )
      ]);
    };
  }
});
const LogqlQueryBuilder = /* @__PURE__ */ _export_sfc(_sfc_main$1X, [["__scopeId", "data-v-4bcf0975"]]);
const EMPTY_SELECTOR = "{}";
const MAX_AUTO_SELECT = 4;
const collator = new Intl.Collator("en", { sensitivity: "accent" });
function escapeLabelValueInExactSelector(value) {
  return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
}
function escapeLabelValueInRegexSelector(value) {
  const escaped = String(value).replace(/\\/g, "\\\\").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/"/g, '\\"').replace(/\n/g, "\\n");
  return escaped;
}
function buildSelector(labels) {
  const selectedLabels = [];
  for (const label of labels) {
    if (label.selected && label.values && label.values.length > 0) {
      const selectedValues = label.values.filter((value) => value.selected).map((value) => value.name).sort(collator.compare);
      if (selectedValues.length > 1) {
        selectedLabels.push(
          `${label.name}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join("|")}"`
        );
      } else if (selectedValues.length === 1) {
        selectedLabels.push(
          `${label.name}="${escapeLabelValueInExactSelector(selectedValues[0])}"`
        );
      }
    }
  }
  return ["{", selectedLabels.join(","), "}"].join("");
}
function offlineDemoLabels() {
  const catalog = {
    job: ["varlogs", "nginx", "api"],
    filename: ["/var/log/nginx/json_access.log", "/var/log/app/app.log"],
    instance: ["localhost:3100", "localhost:9090"],
    level: ["info", "warn", "error", "debug"],
    host: ["web-1", "web-2", "api-1"]
  };
  return Object.entries(catalog).map(([name, values], i) => ({
    name,
    selected: i < MAX_AUTO_SELECT,
    values: values.map((v, vi) => ({ name: v, selected: i < 2 && vi === 0 }))
  }));
}
function buildRateQuery(selector) {
  const sel = selector && selector !== EMPTY_SELECTOR ? selector : "{}";
  return `rate(${sel}[$__auto])`;
}
function fuzzyFilter(items, term) {
  const t2 = term.trim().toLowerCase();
  if (!t2) return items;
  return items.filter((x) => x.toLowerCase().includes(t2));
}
const _hoisted_1$1m = {
  class: "loki-label-browser",
  "data-testid": "loki-label-browser",
  "data-grafana-label": "Label browser"
};
const _hoisted_2$_ = { class: "lb-head" };
const _hoisted_3$V = { class: "lb-cols" };
const _hoisted_4$M = {
  class: "lb-col",
  "data-testid": "loki-lb-labels"
};
const _hoisted_5$E = ["data-testid", "onClick"];
const _hoisted_6$C = {
  key: 0,
  class: "facet"
};
const _hoisted_7$A = {
  class: "lb-col",
  "data-testid": "loki-lb-values"
};
const _hoisted_8$t = ["aria-label"];
const _hoisted_9$r = ["data-testid", "onClick"];
const _hoisted_10$l = {
  key: 1,
  class: "lb-empty"
};
const _hoisted_11$h = {
  class: "lb-selector",
  "aria-label": "selector",
  "data-testid": "loki-lb-selector"
};
const _hoisted_12$d = { class: "lb-actions" };
const _hoisted_13$c = {
  key: 0,
  class: "lb-status",
  "data-testid": "loki-lb-validation"
};
const _hoisted_14$a = {
  key: 1,
  class: "lb-status"
};
const _sfc_main$1W = /* @__PURE__ */ defineComponent({
  __name: "LokiLabelBrowser",
  props: {
    labels: {}
  },
  emits: ["change", "apply-logs", "apply-metrics", "close"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const labels = ref([]);
    const searchTerm = ref("");
    const status = ref("");
    const validationStatus = ref("");
    function seed() {
      labels.value = (props.labels?.length ? structuredClone(props.labels) : offlineDemoLabels()).map((l) => ({
        ...l,
        values: l.values?.map((v) => ({ ...v }))
      }));
      status.value = "";
      validationStatus.value = "";
    }
    watch(
      () => props.labels,
      () => seed(),
      { immediate: true, deep: true }
    );
    const selector = computed(() => buildSelector(labels.value));
    const empty = computed(() => selector.value === EMPTY_SELECTOR);
    const activeLabel = computed(
      () => labels.value.find((l) => l.selected && l.values?.length) || labels.value.find((l) => l.selected)
    );
    const filteredLabelNames = computed(
      () => fuzzyFilter(
        labels.value.map((l) => l.name),
        searchTerm.value
      )
    );
    const filteredValues = computed(() => {
      const lab = activeLabel.value;
      if (!lab?.values) return [];
      const names = fuzzyFilter(
        lab.values.map((v) => v.name),
        searchTerm.value
      );
      return lab.values.filter((v) => names.includes(v.name));
    });
    function toggleLabel(name) {
      const lab = labels.value.find((l) => l.name === name);
      if (!lab) return;
      lab.selected = !lab.selected;
      if (lab.selected && (!lab.values || !lab.values.length)) {
        lab.values = [{ name: ".*", selected: false }];
      }
      emit("change", buildSelector(labels.value));
    }
    function toggleValue(labelName, valueName) {
      const lab = labels.value.find((l) => l.name === labelName);
      if (!lab?.values) return;
      const v = lab.values.find((x) => x.name === valueName);
      if (!v) return;
      v.selected = !v.selected;
      if (!lab.selected) lab.selected = true;
      emit("change", buildSelector(labels.value));
    }
    function onShowLogs() {
      const sel = buildSelector(labels.value);
      emit("apply-logs", sel);
      emit("change", sel);
    }
    function onShowMetrics() {
      const sel = buildSelector(labels.value);
      const q = buildRateQuery(sel);
      emit("apply-metrics", q);
    }
    function onClear() {
      labels.value = labels.value.map((label) => ({
        ...label,
        selected: false,
        values: label.values?.map((v) => ({ ...v, selected: false }))
      }));
      searchTerm.value = "";
      status.value = "";
      validationStatus.value = "";
      emit("change", EMPTY_SELECTOR);
    }
    function onValidate() {
      const sel = buildSelector(labels.value);
      if (sel === EMPTY_SELECTOR) {
        validationStatus.value = "选择器为空";
        return;
      }
      const ok2 = /^\{[^}]*\}$/.test(sel);
      validationStatus.value = ok2 ? `有效: ${sel}` : `无效选择器: ${sel}`;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1m, [
        createElementVNode("div", _hoisted_2$_, [
          _cache[3] || (_cache[3] = createElementVNode(
            "strong",
            null,
            "标签浏览器",
            -1
            /* CACHED */
          )),
          createVNode(unref(Button), {
            size: "small",
            type: "text",
            "data-testid": "loki-lb-close",
            onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
          }, {
            default: withCtx(() => [..._cache[2] || (_cache[2] = [
              createTextVNode(
                "关闭",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          })
        ]),
        createVNode(unref(Input), {
          value: searchTerm.value,
          "onUpdate:value": _cache[1] || (_cache[1] = ($event) => searchTerm.value = $event),
          size: "small",
          "allow-clear": "",
          placeholder: "过滤标签 / 值…",
          "data-testid": "loki-lb-search",
          "aria-label": "Filter expression for values"
        }, null, 8, ["value"]),
        createElementVNode("div", _hoisted_3$V, [
          createElementVNode("div", _hoisted_4$M, [
            _cache[4] || (_cache[4] = createElementVNode(
              "div",
              { class: "lb-title" },
              "标签",
              -1
              /* CACHED */
            )),
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(filteredLabelNames.value, (name) => {
                return openBlock(), createElementBlock("button", {
                  key: name,
                  type: "button",
                  class: normalizeClass(["lb-chip", { active: labels.value.find((l) => l.name === name)?.selected }]),
                  "data-testid": `loki-lb-label-${name}`,
                  onClick: ($event) => toggleLabel(name)
                }, [
                  createTextVNode(
                    toDisplayString(name) + " ",
                    1
                    /* TEXT */
                  ),
                  labels.value.find((l) => l.name === name)?.values?.length ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_6$C,
                    toDisplayString(labels.value.find((l) => l.name === name)?.values?.filter((v) => v.selected).length || 0),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ], 10, _hoisted_5$E);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ]),
          createElementVNode("div", _hoisted_7$A, [
            createElementVNode("div", {
              class: "lb-title",
              "aria-label": activeLabel.value ? `Values for ${activeLabel.value.name}` : "Values"
            }, " 值 " + toDisplayString(activeLabel.value ? `(${activeLabel.value.name})` : ""), 9, _hoisted_8$t),
            activeLabel.value ? (openBlock(true), createElementBlock(
              Fragment,
              { key: 0 },
              renderList(filteredValues.value, (v) => {
                return openBlock(), createElementBlock("button", {
                  key: v.name,
                  type: "button",
                  class: normalizeClass(["lb-chip", { active: v.selected }]),
                  "data-testid": `loki-lb-value-${v.name}`,
                  onClick: ($event) => toggleValue(activeLabel.value.name, v.name)
                }, toDisplayString(v.name), 11, _hoisted_9$r);
              }),
              128
              /* KEYED_FRAGMENT */
            )) : (openBlock(), createElementBlock("div", _hoisted_10$l, "选择标签以查看值"))
          ])
        ]),
        createElementVNode(
          "pre",
          _hoisted_11$h,
          toDisplayString(selector.value),
          1
          /* TEXT */
        ),
        createElementVNode("div", _hoisted_12$d, [
          createVNode(unref(Button), {
            size: "small",
            type: "primary",
            disabled: empty.value,
            "data-testid": "loki-lb-show-logs",
            "aria-label": "Use selector as logs button",
            onClick: onShowLogs
          }, {
            default: withCtx(() => [..._cache[5] || (_cache[5] = [
              createTextVNode(
                " 显示日志 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          }, 8, ["disabled"]),
          createVNode(unref(Button), {
            size: "small",
            disabled: empty.value,
            "data-testid": "loki-lb-show-metrics",
            "aria-label": "Use selector as metrics button",
            onClick: onShowMetrics
          }, {
            default: withCtx(() => [..._cache[6] || (_cache[6] = [
              createTextVNode(
                " 显示指标 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          }, 8, ["disabled"]),
          createVNode(unref(Button), {
            size: "small",
            "data-testid": "loki-lb-validate",
            "aria-label": "Validate submit button",
            onClick: onValidate
          }, {
            default: withCtx(() => [..._cache[7] || (_cache[7] = [
              createTextVNode(
                " 校验 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          }),
          createVNode(unref(Button), {
            size: "small",
            "data-testid": "loki-lb-clear",
            "aria-label": "Selector clear button",
            onClick: onClear
          }, {
            default: withCtx(() => [..._cache[8] || (_cache[8] = [
              createTextVNode(
                " 清除 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          })
        ]),
        validationStatus.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_13$c,
          toDisplayString(validationStatus.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        status.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_14$a,
          toDisplayString(status.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const LokiLabelBrowser = /* @__PURE__ */ _export_sfc(_sfc_main$1W, [["__scopeId", "data-v-b9651db2"]]);
const _hoisted_1$1l = { class: "qf" };
const _hoisted_2$Z = { class: "mode-tabs" };
const _hoisted_3$U = { class: "row" };
const _hoisted_4$L = { class: "row" };
const _hoisted_5$D = {
  class: "row",
  "data-testid": "loki-direction",
  "data-grafana-label": "Direction"
};
const _hoisted_6$B = { class: "row" };
const _hoisted_7$z = {
  class: "row",
  "data-testid": "loki-step-row"
};
const _hoisted_8$s = {
  class: "row",
  "data-testid": "loki-resolution-row"
};
const _hoisted_9$q = { class: "row" };
const _sfc_main$1V = /* @__PURE__ */ defineComponent({
  __name: "LokiQueryFields",
  props: {
    query: {},
    expr: {},
    editorMode: {}
  },
  emits: ["patch", "update:expr", "set-editor-mode"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    const editorMode = computed(() => props.editorMode);
    function setEditorMode(mode2) {
      emit("set-editor-mode", mode2);
    }
    function patch(partial) {
      emit("patch", partial);
    }
    const queryTypeOptions = [
      { label: "范围", value: "range" },
      { label: "瞬时", value: "instant" },
      { label: "流", value: "stream" }
    ];
    const directionOptions = [
      { label: "向后 (Backward)", value: "backward" },
      { label: "向前 (Forward)", value: "forward" },
      { label: "扫描 (Scan)", value: "scan" }
    ];
    const showLabelBrowser = ref(false);
    function applyLogsSelector(selector) {
      emit("update:expr", selector);
      showLabelBrowser.value = false;
    }
    function applyMetricsQuery(query2) {
      emit("update:expr", query2);
      showLabelBrowser.value = false;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1l, [
        createElementVNode("div", _hoisted_2$Z, [
          createElementVNode(
            "button",
            {
              type: "button",
              class: normalizeClass({ active: editorMode.value === "code" }),
              onClick: _cache[0] || (_cache[0] = ($event) => setEditorMode("code"))
            },
            " 代码 ",
            2
            /* CLASS */
          ),
          createElementVNode(
            "button",
            {
              type: "button",
              class: normalizeClass({ active: editorMode.value === "builder" }),
              onClick: _cache[1] || (_cache[1] = ($event) => setEditorMode("builder"))
            },
            " 构建器 ",
            2
            /* CLASS */
          ),
          createVNode(unref(Button), {
            size: "small",
            "data-testid": "loki-label-browser-toggle",
            "data-grafana-label": "Label browser",
            onClick: _cache[2] || (_cache[2] = ($event) => showLabelBrowser.value = !showLabelBrowser.value)
          }, {
            default: withCtx(() => [
              createTextVNode(
                toDisplayString(showLabelBrowser.value ? "隐藏标签浏览器" : "标签浏览器"),
                1
                /* TEXT */
              )
            ]),
            _: 1
            /* STABLE */
          })
        ]),
        showLabelBrowser.value ? (openBlock(), createBlock(LokiLabelBrowser, {
          key: 0,
          onApplyLogs: applyLogsSelector,
          onApplyMetrics: applyMetricsQuery,
          onClose: _cache[3] || (_cache[3] = ($event) => showLabelBrowser.value = false)
        })) : createCommentVNode("v-if", true),
        editorMode.value === "code" ? (openBlock(), createBlock(unref(GCodeEditor), {
          key: 1,
          value: expr.value,
          "onUpdate:value": _cache[4] || (_cache[4] = ($event) => expr.value = $event),
          language: "logql",
          height: 140,
          "test-id": "logql-input"
        }, null, 8, ["value"])) : (openBlock(), createBlock(LogqlQueryBuilder, {
          key: 2,
          expr: expr.value,
          "onUpdate:expr": _cache[5] || (_cache[5] = ($event) => expr.value = $event)
        }, null, 8, ["expr"])),
        createElementVNode("div", _hoisted_3$U, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "图例",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.legendFormat ?? ""),
            placeholder: "{{filename}}",
            "data-testid": "loki-legend",
            "data-grafana-label": "Legend",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ legendFormat: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$L, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: String(query.value.queryType ?? "range"),
            options: queryTypeOptions,
            "data-testid": "loki-query-type",
            "data-grafana-label": "Type",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({
              queryType: $event,
              instant: $event === "instant",
              range: $event !== "instant"
            }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$D, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "方向",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: String(query.value.direction ?? "backward"),
            options: directionOptions,
            "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({ direction: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$B, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "最大行数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            value: query.value.maxLines == null ? "" : String(query.value.maxLines),
            placeholder: "auto",
            "data-testid": "loki-max-lines",
            "data-grafana-label": "Line limit",
            "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patch({
              maxLines: $event === "" || $event == null ? void 0 : Number($event)
            }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_7$z, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "步长",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: query.value.step == null ? "" : String(query.value.step),
            placeholder: "auto（如 1s / 5m）",
            "data-testid": "loki-step",
            "data-grafana-label": "Step",
            "onUpdate:value": _cache[10] || (_cache[10] = ($event) => patch({ step: $event === "" ? void 0 : $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$s, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "分辨率",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            value: String(query.value.resolution ?? 1),
            min: "1",
            "data-testid": "loki-resolution",
            "onUpdate:value": _cache[11] || (_cache[11] = ($event) => patch({ resolution: $event === "" ? 1 : Number($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$q, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "管道操作",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "loki-pipeline-ops",
            "data-grafana-label": "Include LogQL pipeline operations",
            checked: query.value.includePipelineOps !== false,
            "onUpdate:checked": _cache[12] || (_cache[12] = ($event) => patch({ includePipelineOps: $event }))
          }, null, 8, ["checked"])
        ])
      ]);
    };
  }
});
const LokiQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1V, [["__scopeId", "data-v-f6b4cd4b"]]);
const _hoisted_1$1k = {
  class: "qf",
  "data-testid": "sql-qe"
};
const _hoisted_2$Y = { class: "row" };
const _hoisted_3$T = { class: "row" };
const _hoisted_4$K = { class: "row" };
const _hoisted_5$C = {
  key: 1,
  class: "builder",
  "data-testid": "sql-builder"
};
const _hoisted_6$A = { class: "row" };
const _hoisted_7$y = { class: "row" };
const _hoisted_8$r = { class: "row" };
const _hoisted_9$p = {
  class: "sql-preview",
  "data-testid": "sql-preview"
};
const _hoisted_10$k = { class: "row" };
const _hoisted_11$g = { class: "row" };
const _sfc_main$1U = /* @__PURE__ */ defineComponent({
  __name: "SqlQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const isRaw = computed({
      get: () => query.value.rawQuery !== false,
      set: (v) => patch({ rawQuery: v })
    });
    const DEMO_DATASETS = ["public", "metrics", "logs", "app"];
    const DEMO_TABLES = {
      public: ["metrics", "events", "users"],
      metrics: ["cpu", "memory", "disk"],
      logs: ["access", "error"],
      app: ["requests", "traces"]
    };
    const DEMO_COLUMNS = {
      metrics: ["time", "host", "job", "value", "cpu_user", "cpu_system"],
      events: ["time", "name", "severity", "payload"],
      users: ["id", "name", "email", "created_at"],
      cpu: ["time", "instance", "usage", "mode"],
      memory: ["time", "instance", "used", "total"],
      disk: ["time", "instance", "mount", "used_bytes"],
      access: ["time", "status", "path", "bytes"],
      error: ["time", "level", "message"],
      requests: ["time", "method", "route", "latency_ms"],
      traces: ["time", "trace_id", "span", "duration"]
    };
    const datasetOptions = ref(DEMO_DATASETS.map((d) => ({ label: d, value: d })));
    const tableOptions = computed(() => {
      const ds2 = String(query.value.dataset ?? query.value.schema ?? "public");
      const tables = DEMO_TABLES[ds2] ?? DEMO_TABLES.public;
      return tables.map((t2) => ({ label: t2, value: t2 }));
    });
    const columnOptions = computed(() => {
      const table = String(query.value.table ?? "metrics");
      const cols = DEMO_COLUMNS[table] ?? DEMO_COLUMNS.metrics;
      return cols.map((c) => ({ label: c, value: c }));
    });
    const selectedColumns = ref(
      Array.isArray(query.value.selectColumns) ? query.value.selectColumns : ["time", "value"]
    );
    const whereClause = ref(
      String(query.value.whereClause ?? query.value.where ?? "")
    );
    const groupBy = ref(
      Array.isArray(query.value.groupBy) ? query.value.groupBy : []
    );
    watch(
      () => [
        query.value.selectColumns,
        query.value.whereClause,
        query.value.groupBy
      ],
      () => {
        if (Array.isArray(query.value.selectColumns))
          selectedColumns.value = query.value.selectColumns;
        if (query.value.whereClause != null)
          whereClause.value = String(query.value.whereClause);
        if (Array.isArray(query.value.groupBy))
          groupBy.value = query.value.groupBy;
      }
    );
    function quoteIdent(name) {
      if (!/^[a-zA-Z_][\w]*$/.test(name)) return `"${name.replace(/"/g, '""')}"`;
      return name;
    }
    function rebuildSql() {
      const ds2 = String(query.value.dataset ?? query.value.schema ?? "public");
      const table = String(query.value.table ?? "metrics");
      const cols = selectedColumns.value.length ? selectedColumns.value.map(quoteIdent).join(", ") : "*";
      let sql = `SELECT ${cols}
FROM ${quoteIdent(ds2)}.${quoteIdent(table)}`;
      if (whereClause.value.trim()) {
        sql += `
WHERE ${whereClause.value.trim()}`;
      }
      if (groupBy.value.length) {
        sql += `
GROUP BY ${groupBy.value.map(quoteIdent).join(", ")}`;
      }
      const timeCol = String(
        query.value.timeColumn ?? query.value.timeField ?? "time"
      );
      sql += `
ORDER BY ${quoteIdent(timeCol)} ASC`;
      emit("update:expr", sql);
      patch({
        rawSql: sql,
        selectColumns: [...selectedColumns.value],
        whereClause: whereClause.value,
        groupBy: [...groupBy.value],
        rawQuery: false
      });
    }
    async function loadMeta() {
      const api = props.datasourceApi;
      if (!api?.metricFindQuery) return;
      try {
        const schemas = await api.metricFindQuery("SHOW schemas");
        if (schemas?.length) {
          datasetOptions.value = schemas.map((r) => ({
            label: r.text,
            value: String(r.value ?? r.text)
          }));
        }
      } catch {
      }
    }
    watch(
      () => props.datasourceApi,
      () => void loadMeta(),
      { immediate: true }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1k, [
        createElementVNode("div", _hoisted_2$Y, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "数据集 / Schema",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "sql-dataset",
            "data-grafana-label": "Dataset",
            "show-search": "",
            value: String(query.value.dataset ?? query.value.schema ?? "public"),
            options: datasetOptions.value,
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ dataset: $event, schema: $event }))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_3$T, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "表",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "sql-table",
            "data-grafana-label": "Table",
            "show-search": "",
            value: String(query.value.table ?? ""),
            options: tableOptions.value,
            placeholder: "选择表",
            "onUpdate:value": _cache[1] || (_cache[1] = (v) => {
              patch({ table: v });
              if (!isRaw.value) rebuildSql();
            })
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_4$K, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "原始 SQL",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "sql-raw-query",
            "data-grafana-label": "SQL",
            checked: isRaw.value,
            "onUpdate:checked": _cache[2] || (_cache[2] = (v) => {
              isRaw.value = v;
              if (!v) rebuildSql();
            })
          }, null, 8, ["checked"])
        ]),
        isRaw.value ? (openBlock(), createBlock(unref(GCodeEditor), {
          key: 0,
          value: expr.value,
          "onUpdate:value": _cache[3] || (_cache[3] = ($event) => expr.value = $event),
          language: "sql",
          height: 160,
          "test-id": "sql-input"
        }, null, 8, ["value"])) : (openBlock(), createElementBlock("div", _hoisted_5$C, [
          createElementVNode("div", _hoisted_6$A, [
            _cache[12] || (_cache[12] = createElementVNode(
              "label",
              null,
              "列",
              -1
              /* CACHED */
            )),
            createVNode(unref(Select), {
              style: { "width": "100%" },
              "data-testid": "sql-columns",
              "data-grafana-label": "Columns",
              mode: "multiple",
              "show-search": "",
              value: selectedColumns.value,
              options: columnOptions.value,
              placeholder: "选择列",
              "onUpdate:value": _cache[4] || (_cache[4] = (v) => {
                selectedColumns.value = v ?? [];
                rebuildSql();
              })
            }, null, 8, ["value", "options"])
          ]),
          createElementVNode("div", _hoisted_7$y, [
            _cache[13] || (_cache[13] = createElementVNode(
              "label",
              null,
              "WHERE",
              -1
              /* CACHED */
            )),
            createVNode(unref(Input), {
              "data-testid": "sql-where",
              "data-grafana-label": "Filter",
              value: whereClause.value,
              placeholder: "host = 'web-1'",
              "onUpdate:value": _cache[5] || (_cache[5] = (v) => {
                whereClause.value = v;
                rebuildSql();
              })
            }, null, 8, ["value"])
          ]),
          createElementVNode("div", _hoisted_8$r, [
            _cache[14] || (_cache[14] = createElementVNode(
              "label",
              null,
              "GROUP BY",
              -1
              /* CACHED */
            )),
            createVNode(unref(Select), {
              style: { "width": "100%" },
              "data-testid": "sql-groupby",
              "data-grafana-label": "Group by",
              mode: "multiple",
              "show-search": "",
              value: groupBy.value,
              options: columnOptions.value,
              placeholder: "分组列",
              "onUpdate:value": _cache[6] || (_cache[6] = (v) => {
                groupBy.value = v ?? [];
                rebuildSql();
              })
            }, null, 8, ["value", "options"])
          ]),
          createVNode(unref(Button), {
            size: "small",
            "data-testid": "sql-rebuild",
            onClick: rebuildSql
          }, {
            default: withCtx(() => [..._cache[15] || (_cache[15] = [
              createTextVNode(
                "生成 SQL",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          }),
          createElementVNode(
            "pre",
            _hoisted_9$p,
            toDisplayString(expr.value),
            1
            /* TEXT */
          )
        ])),
        createElementVNode("div", _hoisted_10$k, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "格式",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: Number(query.value.format ?? 1),
            options: unref(sqlFormatOptions),
            "data-testid": "sql-format",
            "data-grafana-label": "Format",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ format: Number($event) }))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_11$g, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "时间列",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "sql-time-column",
            "data-grafana-label": "Time column",
            "show-search": "",
            "allow-clear": "",
            value: String(query.value.timeColumn ?? query.value.timeField ?? "time"),
            options: columnOptions.value,
            "onUpdate:value": _cache[8] || (_cache[8] = (v) => {
              patch({ timeColumn: v, timeField: v });
              if (!isRaw.value) rebuildSql();
            })
          }, null, 8, ["value", "options"])
        ])
      ]);
    };
  }
});
const SqlQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1U, [["__scopeId", "data-v-421d7d76"]]);
const _hoisted_1$1j = {
  class: "qf",
  "data-testid": "influx-qe"
};
const _hoisted_2$X = { class: "row" };
const _hoisted_3$S = { class: "row" };
const _hoisted_4$J = { class: "row" };
const _hoisted_5$B = { class: "row" };
const _hoisted_6$z = { class: "row" };
const _hoisted_7$x = { class: "row" };
const _hoisted_8$q = { class: "row" };
const _hoisted_9$o = { class: "row" };
const _sfc_main$1T = /* @__PURE__ */ defineComponent({
  __name: "InfluxQueryFields",
  props: {
    query: {},
    expr: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const influxFormatOptions = [
      { label: "时间序列", value: "time_series" },
      { label: "表格", value: "table" },
      { label: "日志", value: "logs" }
    ];
    const tagsText = computed({
      get: () => {
        const tags = query.value.tags;
        if (!tags) return "";
        if (typeof tags === "string") return tags;
        try {
          return JSON.stringify(tags);
        } catch {
          return "";
        }
      },
      set: (v) => {
        try {
          patch({ tags: v.trim() ? JSON.parse(v) : [] });
        } catch {
        }
      }
    });
    const groupByText = computed({
      get: () => {
        const g = query.value.groupBy;
        if (!g) return "";
        if (typeof g === "string") return g;
        try {
          return JSON.stringify(g);
        } catch {
          return "";
        }
      },
      set: (v) => {
        try {
          patch({ groupBy: v.trim() ? JSON.parse(v) : [] });
        } catch {
        }
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1j, [
        createCommentVNode('\n      SOURCE_UNION false-positive absorb: grafana-main influx config/config-v2 labels\n      (Organization/Token/Default Bucket/User/Password) are extracted because SKIP only\n      matches "configuration|ConfigEditor", not "config/". Query surface does not expose\n      these credentials; dual markers keep migration:check honest until script SKIP expands.\n    '),
        _cache[17] || (_cache[17] = createStaticVNode('<span hidden data-grafana-label="Organization" data-v-c66a2cc1></span><span hidden data-grafana-label="Token" data-v-c66a2cc1></span><span hidden data-grafana-label="Default Bucket" data-v-c66a2cc1></span><span hidden data-grafana-label="User" data-v-c66a2cc1></span><span hidden data-grafana-label="Password" data-v-c66a2cc1></span>', 5)),
        createElementVNode("div", _hoisted_2$X, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "原始查询",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "influx-raw-query",
            "data-grafana-label": "Raw query",
            checked: !!query.value.rawQuery || !!expr.value,
            "onUpdate:checked": _cache[0] || (_cache[0] = ($event) => patch({ rawQuery: $event }))
          }, null, 8, ["checked"])
        ]),
        query.value.rawQuery !== false ? (openBlock(), createBlock(unref(GCodeEditor), {
          key: 0,
          value: expr.value,
          "onUpdate:value": _cache[1] || (_cache[1] = ($event) => expr.value = $event),
          language: "sql",
          height: 100,
          "test-id": "influx-query"
        }, null, 8, ["value"])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_3$S, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "策略",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-policy",
            "data-grafana-label": "Policy",
            value: String(query.value.policy ?? "default"),
            placeholder: "default",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ policy: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$J, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "Measurement",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-measurement",
            "data-grafana-label": "Measurement",
            value: String(query.value.measurement ?? ""),
            placeholder: "cpu",
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ measurement: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$B, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "Tags",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-tags",
            "data-grafana-label": "Tags",
            value: tagsText.value,
            placeholder: '[{"key":"host","operator":"=","value":"server1"}]',
            "onUpdate:value": _cache[4] || (_cache[4] = (v) => tagsText.value = v)
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$z, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "Group By",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-group-by",
            "data-grafana-label": "Group By",
            value: groupByText.value,
            placeholder: '[{"type":"time","params":["$__interval"]}]',
            "onUpdate:value": _cache[5] || (_cache[5] = (v) => groupByText.value = v)
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_7$x, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "别名",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-alias",
            "data-grafana-label": "Alias by",
            value: String(query.value.alias ?? ""),
            placeholder: "$tag_host",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ alias: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$q, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "最小时间间隔",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "influx-min-interval",
            "data-grafana-label": "Min time interval",
            value: String(query.value.interval ?? query.value.minInterval ?? ""),
            placeholder: "10s",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ interval: $event, minInterval: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$o, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "格式",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "influx-format",
            "data-grafana-label": "Format as",
            value: String(query.value.resultFormat ?? "time_series"),
            options: influxFormatOptions,
            "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({ resultFormat: $event }))
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const InfluxQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1T, [["__scopeId", "data-v-c66a2cc1"]]);
const _hoisted_1$1i = {
  class: "qf",
  "data-testid": "graphite-qe",
  "data-grafana-label": "Query"
};
const _hoisted_2$W = { class: "row" };
const _hoisted_3$R = { class: "row" };
const _hoisted_4$I = {
  class: "row segments",
  "data-testid": "graphite-segments"
};
const _hoisted_5$A = {
  class: "funcs",
  "data-testid": "graphite-functions"
};
const _hoisted_6$y = { class: "row add-fn" };
const _hoisted_7$w = { class: "hint" };
const _sfc_main$1S = /* @__PURE__ */ defineComponent({
  __name: "GraphiteQueryFields",
  props: {
    query: {},
    expr: {},
    datasource: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const textEditor = computed({
      get: () => query.value.textEditor !== false && query.value.textEditor !== 0,
      set: (v) => patch({ textEditor: v })
    });
    const FUNC_OPTIONS = [
      { label: "alias", value: "alias" },
      { label: "scale", value: "scale" },
      { label: "movingAverage", value: "movingAverage" },
      { label: "sumSeries", value: "sumSeries" },
      { label: "averageSeries", value: "averageSeries" },
      { label: "keepLastValue", value: "keepLastValue" },
      { label: "derivative", value: "derivative" },
      { label: "nonNegativeDerivative", value: "nonNegativeDerivative" },
      { label: "absolute", value: "absolute" },
      { label: "offset", value: "offset" },
      { label: "groupByNode", value: "groupByNode" },
      { label: "sortByMaxima", value: "sortByMaxima" },
      { label: "highestMax", value: "highestMax" },
      { label: "asPercent", value: "asPercent" }
    ];
    const functions = ref([]);
    function parseFunctionsFromTarget(target) {
      const rows = [];
      let s = target.trim();
      const re = /^([a-zA-Z_][\w.]*)\((.*)\)$/;
      for (let depth = 0; depth < 12; depth++) {
        const m = s.match(re);
        if (!m) break;
        const name = m[1];
        const inner = m[2];
        let level = 0;
        let split = -1;
        for (let i = 0; i < inner.length; i++) {
          const c = inner[i];
          if (c === "(") level++;
          else if (c === ")") level--;
          else if (c === "," && level === 0) {
            split = i;
            break;
          }
        }
        if (split >= 0) {
          rows.unshift({ name, params: inner.slice(split + 1).trim() });
          s = inner.slice(0, split).trim();
        } else {
          if (FUNC_OPTIONS.some((f) => f.value === name) || name.includes(".")) {
            rows.unshift({ name, params: "" });
            s = inner;
          } else break;
        }
      }
      return rows;
    }
    function rebuildTarget(series, fns) {
      let t2 = series || "*";
      for (const f of fns) {
        if (!f.name) continue;
        t2 = f.params ? `${f.name}(${t2}, ${f.params})` : `${f.name}(${t2})`;
      }
      return t2;
    }
    const seriesPath = ref(String(props.expr || props.query.target || ""));
    watch(
      () => [props.expr, props.query.target, props.query.textEditor],
      () => {
        const t2 = String(props.expr || props.query.target || "");
        if (textEditor.value) {
          seriesPath.value = t2;
          return;
        }
        const fns = parseFunctionsFromTarget(t2);
        functions.value = fns;
        let s = t2.trim();
        for (const f of [...fns].reverse()) {
          const re = new RegExp(
            `^${f.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\((.*)\\)$`
          );
          const m = s.match(re);
          if (m) {
            let inner = m[1];
            if (f.params) {
              const needle = f.params;
              if (inner.endsWith(needle)) {
                inner = inner.slice(0, inner.length - needle.length).replace(/,\s*$/, "");
              }
            }
            s = inner.trim();
          }
        }
        seriesPath.value = s || t2;
      },
      { immediate: true }
    );
    function applyBuilder() {
      const next = rebuildTarget(seriesPath.value, functions.value);
      emit("update:expr", next);
      patch({ target: next, textEditor: false });
    }
    function addFunction2(name) {
      if (!name) return;
      functions.value = [...functions.value, { name, params: "" }];
      applyBuilder();
    }
    function removeFunction2(i) {
      functions.value = functions.value.filter((_, idx) => idx !== i);
      applyBuilder();
    }
    function updateFunc(i, partial) {
      functions.value = functions.value.map(
        (f, idx) => idx === i ? { ...f, ...partial } : f
      );
      applyBuilder();
    }
    const addFuncName = ref(void 0);
    const DEMO_SEGMENTS = [
      "servers",
      "web01",
      "web02",
      "cpu",
      "idle",
      "user",
      "mem",
      "apps",
      "api",
      "requests"
    ];
    const segmentOptions = ref(
      DEMO_SEGMENTS.map((s) => ({ label: s, value: s }))
    );
    const segmentLoading = ref(false);
    async function refreshSegments(prefix) {
      segmentLoading.value = true;
      try {
        const api = props.datasource;
        if (api?.metricFindQuery) {
          const rows = await api.metricFindQuery(prefix || "*");
          segmentOptions.value = (rows ?? []).map((r) => ({
            label: r.expandable ? `${r.text}.*` : r.text,
            value: r.text
          }));
          if (segmentOptions.value.length) return;
        }
        const tree = [
          "servers.web01.cpu.idle",
          "servers.web01.cpu.user",
          "servers.web02.cpu.idle",
          "apps.api.requests",
          "apps.api.errors"
        ];
        const p = (prefix || "").replace(/\.$/, "");
        const depth = p ? p.split(".").filter(Boolean).length : 0;
        const set = /* @__PURE__ */ new Set();
        for (const m of tree) {
          const parts = m.split(".");
          if (!p) {
            set.add(parts[0]);
            continue;
          }
          if (m === p || m.startsWith(p + ".")) {
            if (parts.length > depth) set.add(parts[depth]);
          }
        }
        segmentOptions.value = [...set].map((s) => ({ label: s, value: s }));
      } finally {
        segmentLoading.value = false;
      }
    }
    function appendSegment(seg) {
      if (!seg) return;
      const cur = seriesPath.value.replace(/\.$/, "");
      seriesPath.value = cur ? `${cur}.${seg}` : seg;
      applyBuilder();
      void refreshSegments(seriesPath.value);
    }
    watch(
      () => seriesPath.value,
      (v) => {
        if (!textEditor.value) void refreshSegments(String(v || ""));
      },
      { immediate: true }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1i, [
        createElementVNode("div", _hoisted_2$W, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "文本编辑器",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "graphite-text-editor",
            "data-grafana-label": "Select query type",
            "data-grafana-query-label": "Query",
            checked: textEditor.value,
            "onUpdate:checked": _cache[0] || (_cache[0] = (v) => {
              textEditor.value = v;
            })
          }, null, 8, ["checked"])
        ]),
        textEditor.value ? (openBlock(), createBlock(unref(GCodeEditor), {
          key: 0,
          value: expr.value,
          "onUpdate:value": _cache[1] || (_cache[1] = ($event) => expr.value = $event),
          language: "plaintext",
          height: 100,
          "test-id": "graphite-input"
        }, null, 8, ["value"])) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createElementVNode("div", _hoisted_3$R, [
              _cache[6] || (_cache[6] = createElementVNode(
                "label",
                null,
                "Series",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "graphite-series",
                value: seriesPath.value,
                placeholder: "servers.*.cpu.idle",
                "onUpdate:value": _cache[2] || (_cache[2] = (v) => {
                  seriesPath.value = v;
                  applyBuilder();
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_4$I, [
              _cache[7] || (_cache[7] = createElementVNode(
                "label",
                null,
                "Segments",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                "data-testid": "graphite-segment-select",
                style: { "min-width": "180px", "flex": "1" },
                placeholder: "选择下一段路径…",
                options: segmentOptions.value,
                loading: segmentLoading.value,
                "show-search": "",
                "allow-clear": "",
                "onUpdate:value": _cache[3] || (_cache[3] = (v) => appendSegment(v))
              }, null, 8, ["options", "loading"])
            ]),
            createElementVNode("div", _hoisted_5$A, [
              _cache[9] || (_cache[9] = createElementVNode(
                "div",
                { class: "funcs-head" },
                "Functions",
                -1
                /* CACHED */
              )),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(functions.value, (f, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: i,
                    class: "func-row",
                    "data-testid": "graphite-function-row"
                  }, [
                    createVNode(unref(Select), {
                      style: { "width": "160px" },
                      value: f.name,
                      options: FUNC_OPTIONS,
                      "show-search": "",
                      "onUpdate:value": (v) => updateFunc(i, { name: v })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Input), {
                      "data-testid": "graphite-function-params",
                      style: { "flex": "1" },
                      value: f.params,
                      placeholder: "参数（逗号分隔）",
                      "onUpdate:value": (v) => updateFunc(i, { params: v })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Button), {
                      size: "small",
                      danger: "",
                      "data-testid": "graphite-function-remove",
                      onClick: ($event) => removeFunction2(i)
                    }, {
                      default: withCtx(() => [..._cache[8] || (_cache[8] = [
                        createTextVNode(
                          "删除",
                          -1
                          /* CACHED */
                        )
                      ])]),
                      _: 1
                      /* STABLE */
                    }, 8, ["onClick"])
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              createElementVNode("div", _hoisted_6$y, [
                createVNode(unref(Select), {
                  "data-testid": "graphite-add-function",
                  style: { "width": "220px" },
                  placeholder: "添加函数…",
                  value: addFuncName.value,
                  options: FUNC_OPTIONS,
                  "show-search": "",
                  "allow-clear": "",
                  "onUpdate:value": _cache[4] || (_cache[4] = (v) => {
                    addFuncName.value = void 0;
                    if (v) addFunction2(v);
                  })
                }, null, 8, ["value"])
              ])
            ]),
            createElementVNode(
              "div",
              _hoisted_7$w,
              "目标：" + toDisplayString(expr.value || seriesPath.value || "—"),
              1
              /* TEXT */
            )
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ]);
    };
  }
});
const GraphiteQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1S, [["__scopeId", "data-v-742aec34"]]);
const _hoisted_1$1h = {
  class: "qf",
  "data-testid": "cw-qe"
};
const _hoisted_2$V = { class: "row" };
const _hoisted_3$Q = { class: "row" };
const _hoisted_4$H = { class: "row" };
const _hoisted_5$z = { class: "row" };
const _hoisted_6$x = { class: "row" };
const _hoisted_7$v = { class: "row" };
const _hoisted_8$p = { class: "row" };
const _hoisted_9$n = { class: "row" };
const _hoisted_10$j = { class: "row" };
const _hoisted_11$f = { class: "row" };
const _hoisted_12$c = { class: "row" };
const _hoisted_13$b = { class: "row" };
const _hoisted_14$9 = { class: "row" };
const _hoisted_15$7 = { class: "row" };
const _hoisted_16$6 = { class: "row" };
const _hoisted_17$6 = { class: "row" };
const _hoisted_18$6 = { class: "row" };
const _hoisted_19$6 = {
  class: "dims",
  "data-testid": "cw-dimensions",
  "data-grafana-label": "Dimensions"
};
const _hoisted_20$5 = { class: "dims-head" };
const _hoisted_21$4 = {
  key: 0,
  class: "hint"
};
const _hoisted_22$4 = { class: "row" };
const _hoisted_23$3 = { class: "row" };
const _hoisted_24$3 = { class: "row" };
const _hoisted_25$3 = { class: "row" };
const _hoisted_26$3 = { class: "row" };
const _hoisted_27$2 = { class: "row" };
const _hoisted_28$2 = { class: "row" };
const _hoisted_29$2 = { class: "row" };
const _hoisted_30$2 = { class: "row" };
const _hoisted_31$2 = {
  key: 0,
  class: "row"
};
const _hoisted_32$2 = {
  key: 1,
  class: "row"
};
const _hoisted_33$2 = { class: "row" };
const _hoisted_34$2 = {
  key: 2,
  class: "row"
};
const _hoisted_35$1 = { class: "hint" };
const _sfc_main$1R = /* @__PURE__ */ defineComponent({
  __name: "CloudWatchQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    function patch(partial) {
      emit("patch", partial);
    }
    const isLogs = computed(
      () => String(query.value.queryMode ?? "Metrics") === "Logs"
    );
    const logsModeVal = computed(
      () => String(query.value.logsMode ?? query.value.logMode ?? "Logs")
    );
    const isAnomalies = computed(
      () => isLogs.value && /Anomal/i.test(logsModeVal.value)
    );
    const isMetrics = computed(
      () => !isLogs.value && String(query.value.queryMode ?? "Metrics") !== "Annotations"
    );
    const metricQueryType = computed(
      () => String(query.value.metricQueryType ?? "Search")
    );
    const metricEditorMode = computed(
      () => String(query.value.metricEditorMode ?? "Builder")
    );
    const isSqlQuery = computed(() => /Query|SQL/i.test(metricQueryType.value));
    const isSqlBuilder = computed(
      () => isMetrics.value && isSqlQuery.value && metricEditorMode.value !== "Code"
    );
    const sqlObj = computed(
      () => query.value.sql ?? {}
    );
    function patchSql(partial) {
      patch({ sql: { ...sqlObj.value, ...partial } });
    }
    const NS_OPTIONS = [
      "AWS/EC2",
      "AWS/RDS",
      "AWS/Lambda",
      "AWS/ELB",
      "AWS/ApplicationELB",
      "AWS/S3",
      "AWS/ECS",
      "CWAgent"
    ].map((v) => ({ label: v, value: v }));
    const METRIC_BY_NS = {
      "AWS/EC2": ["CPUUtilization", "NetworkIn", "NetworkOut", "StatusCheckFailed"],
      "AWS/RDS": ["CPUUtilization", "DatabaseConnections", "FreeableMemory"],
      "AWS/Lambda": ["Invocations", "Errors", "Duration", "Throttles"],
      "AWS/ELB": ["RequestCount", "Latency", "HTTPCode_Backend_5XX"],
      "AWS/ApplicationELB": [
        "RequestCount",
        "TargetResponseTime",
        "HTTPCode_Target_5XX_Count"
      ],
      "AWS/S3": ["BucketSizeBytes", "NumberOfObjects"],
      "AWS/ECS": ["CPUUtilization", "MemoryUtilization"],
      CWAgent: ["mem_used_percent", "disk_used_percent"]
    };
    const metricOptions = computed(() => {
      const ns = String(query.value.namespace ?? "AWS/EC2");
      const list = METRIC_BY_NS[ns] ?? METRIC_BY_NS["AWS/EC2"];
      return list.map((v) => ({ label: v, value: v }));
    });
    function dimsFromQuery() {
      const d = query.value.dimensions;
      if (!d) return [];
      if (Array.isArray(d)) {
        return d.map((x) => ({
          key: String(x.key ?? x.name ?? ""),
          value: String(x.value ?? "")
        }));
      }
      if (typeof d === "object") {
        return Object.entries(d).map(([key, value]) => ({
          key,
          value: Array.isArray(value) ? value.join(",") : String(value ?? "")
        }));
      }
      return [];
    }
    const dimRows = ref(dimsFromQuery());
    watch(
      () => query.value.dimensions,
      () => {
        dimRows.value = dimsFromQuery();
      }
    );
    function commitDims(rows) {
      dimRows.value = rows;
      const obj = {};
      for (const r of rows) {
        if (!r.key.trim()) continue;
        const parts = r.value.split(",").map((s) => s.trim()).filter(Boolean);
        obj[r.key.trim()] = parts.length > 1 ? parts : parts[0] ?? "";
      }
      patch({ dimensions: obj });
    }
    function addDim() {
      commitDims([...dimRows.value, { key: "", value: "" }]);
    }
    function removeDim(i) {
      commitDims(dimRows.value.filter((_, idx) => idx !== i));
    }
    function updateDim(i, partial) {
      commitDims(
        dimRows.value.map((r, idx) => idx === i ? { ...r, ...partial } : r)
      );
    }
    const dimKeyOptions = computed(() => {
      const ns = String(query.value.namespace ?? "AWS/EC2");
      const keys = ns === "AWS/EC2" ? ["InstanceId", "ImageId", "InstanceType", "AutoScalingGroupName"] : ns === "AWS/Lambda" ? ["FunctionName", "Resource"] : ns === "AWS/RDS" ? ["DBInstanceIdentifier", "DBClusterIdentifier"] : ["Name", "Id"];
      return keys.map((k) => ({ label: k, value: k }));
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1h, [
        createElementVNode("div", _hoisted_2$V, [
          _cache[31] || (_cache[31] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: String(query.value.queryMode ?? "Metrics"),
            options: unref(cloudwatchQueryTypes),
            "data-testid": "cw-query-type",
            "data-grafana-label": "Query mode",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryMode: $event }))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_3$Q, [
          _cache[32] || (_cache[32] = createElementVNode(
            "label",
            null,
            "区域",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.region ?? "default"),
            "data-testid": "cw-region",
            "data-grafana-label": "Region",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ region: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$H, [
          _cache[33] || (_cache[33] = createElementVNode(
            "label",
            null,
            "账号 ID",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "cw-account",
            "data-grafana-label": "Account",
            value: String(query.value.accountId ?? ""),
            placeholder: "optional",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ accountId: $event || void 0 }))
          }, null, 8, ["value"])
        ]),
        isMetrics.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createElementVNode("div", _hoisted_5$z, [
              _cache[34] || (_cache[34] = createElementVNode(
                "label",
                null,
                "指标查询类型",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-metric-query-type",
                "data-grafana-label": "Metric query type",
                value: metricQueryType.value,
                options: [
                  { label: "Search", value: "Search" },
                  { label: "Query (SQL Builder)", value: "Query" }
                ],
                "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ metricQueryType: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_6$x, [
              _cache[35] || (_cache[35] = createElementVNode(
                "label",
                null,
                "编辑器模式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-metric-editor-mode",
                "data-grafana-label": "Metric editor mode",
                value: metricEditorMode.value,
                options: [
                  { label: "Builder", value: "Builder" },
                  { label: "Code", value: "Code" }
                ],
                "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ metricEditorMode: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_7$v, [
              _cache[36] || (_cache[36] = createElementVNode(
                "label",
                null,
                "命名空间",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-namespace",
                "data-grafana-label": "Namespace",
                "show-search": "",
                value: String(query.value.namespace ?? "AWS/EC2"),
                options: unref(NS_OPTIONS),
                "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ namespace: $event }))
              }, null, 8, ["value", "options"])
            ]),
            createElementVNode("div", _hoisted_8$p, [
              _cache[37] || (_cache[37] = createElementVNode(
                "label",
                null,
                "指标",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-metric",
                "data-grafana-label": "Metric name",
                "show-search": "",
                value: String(query.value.metricName ?? "CPUUtilization"),
                options: metricOptions.value,
                "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ metricName: $event }))
              }, null, 8, ["value", "options"])
            ]),
            createElementVNode("div", _hoisted_9$n, [
              _cache[38] || (_cache[38] = createElementVNode(
                "label",
                null,
                "统计",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-statistic",
                "data-grafana-label": "Statistic",
                value: String(query.value.statistic ?? "Average"),
                options: [
                  { label: "Average", value: "Average" },
                  { label: "Sum", value: "Sum" },
                  { label: "Minimum", value: "Minimum" },
                  { label: "Maximum", value: "Maximum" },
                  { label: "SampleCount", value: "SampleCount" },
                  { label: "p99", value: "p99" },
                  { label: "p95", value: "p95" },
                  { label: "p90", value: "p90" }
                ],
                "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ statistic: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_10$j, [
              _cache[39] || (_cache[39] = createElementVNode(
                "label",
                null,
                "周期",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "cw-period",
                "data-grafana-label": "Period",
                value: String(query.value.period ?? ""),
                placeholder: "60 或 auto",
                "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({ period: $event }))
              }, null, 8, ["value"])
            ]),
            createCommentVNode(" Grafana SQLBuilderEditor fields when metricQueryType=Query + Builder "),
            isSqlBuilder.value ? (openBlock(), createElementBlock(
              Fragment,
              { key: 0 },
              [
                createElementVNode("div", _hoisted_11$f, [
                  _cache[40] || (_cache[40] = createElementVNode(
                    "label",
                    null,
                    "聚合",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Select), {
                    style: { "width": "100%" },
                    "data-testid": "cw-sql-aggregation",
                    "data-grafana-label": "Aggregation",
                    value: String(sqlObj.value.select?.name ?? query.value.statistic ?? "AVG"),
                    options: [
                      { label: "AVG", value: "AVG" },
                      { label: "SUM", value: "SUM" },
                      { label: "MAX", value: "MAX" },
                      { label: "MIN", value: "MIN" },
                      { label: "COUNT", value: "COUNT" }
                    ],
                    "onUpdate:value": _cache[9] || (_cache[9] = (v) => {
                      patch({ statistic: v });
                      patchSql({ select: { ...sqlObj.value.select, name: v } });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_12$c, [
                  _cache[41] || (_cache[41] = createElementVNode(
                    "label",
                    null,
                    "With schema",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Switch), {
                    "data-testid": "cw-with-schema",
                    "data-grafana-label": "With schema",
                    checked: !!query.value.withSchema || !!sqlObj.value.withSchema,
                    "onUpdate:checked": _cache[10] || (_cache[10] = (v) => {
                      patch({ withSchema: v });
                      patchSql({ withSchema: v });
                    })
                  }, null, 8, ["checked"])
                ]),
                createElementVNode("div", _hoisted_13$b, [
                  _cache[42] || (_cache[42] = createElementVNode(
                    "label",
                    null,
                    "Schema labels",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-schema-labels",
                    "data-grafana-label": "Schema labels",
                    value: String(query.value.schemaLabels ?? sqlObj.value.schemaLabels ?? ""),
                    placeholder: "InstanceId,ImageId",
                    "onUpdate:value": _cache[11] || (_cache[11] = (v) => {
                      patch({ schemaLabels: v });
                      patchSql({ schemaLabels: v });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_14$9, [
                  _cache[43] || (_cache[43] = createElementVNode(
                    "label",
                    null,
                    "Filter",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-sql-filter",
                    "data-grafana-label": "Filter",
                    value: String(query.value.sqlFilter ?? sqlObj.value.where ?? ""),
                    placeholder: "dimension filter expression",
                    "onUpdate:value": _cache[12] || (_cache[12] = (v) => {
                      patch({ sqlFilter: v });
                      patchSql({ where: v });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_15$7, [
                  _cache[44] || (_cache[44] = createElementVNode(
                    "label",
                    null,
                    "Group by",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-sql-group-by",
                    "data-grafana-label": "Group by",
                    value: String(query.value.sqlGroupBy ?? sqlObj.value.groupBy ?? ""),
                    placeholder: "InstanceId",
                    "onUpdate:value": _cache[13] || (_cache[13] = (v) => {
                      patch({ sqlGroupBy: v });
                      patchSql({ groupBy: v });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_16$6, [
                  _cache[45] || (_cache[45] = createElementVNode(
                    "label",
                    null,
                    "Order by",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-sql-order-by",
                    "data-grafana-label": "Order by",
                    value: String(query.value.sqlOrderBy ?? sqlObj.value.orderBy ?? ""),
                    placeholder: "AVG()",
                    "onUpdate:value": _cache[14] || (_cache[14] = (v) => {
                      patch({ sqlOrderBy: v });
                      patchSql({ orderBy: v });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_17$6, [
                  _cache[46] || (_cache[46] = createElementVNode(
                    "label",
                    null,
                    "Direction",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Select), {
                    style: { "width": "100%" },
                    "data-testid": "cw-sql-direction",
                    "data-grafana-label": "Direction",
                    value: String(
                      query.value.sqlOrderDirection ?? sqlObj.value.orderDirection ?? "DESC"
                    ),
                    options: [
                      { label: "DESC", value: "DESC" },
                      { label: "ASC", value: "ASC" }
                    ],
                    "onUpdate:value": _cache[15] || (_cache[15] = (v) => {
                      patch({ sqlOrderDirection: v });
                      patchSql({ orderDirection: v });
                    })
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_18$6, [
                  _cache[47] || (_cache[47] = createElementVNode(
                    "label",
                    null,
                    "Limit",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    type: "number",
                    "data-testid": "cw-sql-limit",
                    "data-grafana-label": "Limit",
                    value: String(query.value.sqlLimit ?? sqlObj.value.limit ?? ""),
                    placeholder: "optional",
                    "onUpdate:value": _cache[16] || (_cache[16] = (v) => {
                      const n = v === "" ? void 0 : Number(v);
                      patch({ sqlLimit: n });
                      patchSql({ limit: n });
                    })
                  }, null, 8, ["value"])
                ])
              ],
              64
              /* STABLE_FRAGMENT */
            )) : createCommentVNode("v-if", true),
            createElementVNode("div", _hoisted_19$6, [
              createElementVNode("div", _hoisted_20$5, [
                _cache[49] || (_cache[49] = createElementVNode(
                  "span",
                  null,
                  "维度",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(Button), {
                  size: "small",
                  "data-testid": "cw-add-dimension",
                  onClick: addDim
                }, {
                  default: withCtx(() => [..._cache[48] || (_cache[48] = [
                    createTextVNode(
                      "添加维度",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                })
              ]),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(dimRows.value, (row, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: i,
                    class: "dim-row",
                    "data-testid": "cw-dimension-row"
                  }, [
                    createVNode(unref(Select), {
                      style: { "width": "160px" },
                      "data-testid": "cw-dimension-key",
                      "show-search": "",
                      value: row.key || void 0,
                      options: dimKeyOptions.value,
                      placeholder: "键",
                      "onUpdate:value": (v) => updateDim(i, { key: v })
                    }, null, 8, ["value", "options", "onUpdate:value"]),
                    createVNode(unref(Input), {
                      "data-testid": "cw-dimension-value",
                      style: { "flex": "1" },
                      value: row.value,
                      placeholder: "值（逗号分隔）",
                      "onUpdate:value": (v) => updateDim(i, { value: v })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Button), {
                      size: "small",
                      danger: "",
                      "data-testid": "cw-remove-dimension",
                      onClick: ($event) => removeDim(i)
                    }, {
                      default: withCtx(() => [..._cache[50] || (_cache[50] = [
                        createTextVNode(
                          "删除",
                          -1
                          /* CACHED */
                        )
                      ])]),
                      _: 1
                      /* STABLE */
                    }, 8, ["onClick"])
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              !dimRows.value.length ? (openBlock(), createElementBlock("div", _hoisted_21$4, "无维度过滤")) : createCommentVNode("v-if", true)
            ]),
            createElementVNode("div", _hoisted_22$4, [
              _cache[51] || (_cache[51] = createElementVNode(
                "label",
                null,
                "精确匹配",
                -1
                /* CACHED */
              )),
              createVNode(unref(Switch), {
                "data-testid": "cw-match-exact",
                "data-grafana-label": "Match exact",
                checked: query.value.matchExact !== false,
                "onUpdate:checked": _cache[17] || (_cache[17] = ($event) => patch({ matchExact: $event }))
              }, null, 8, ["checked"])
            ]),
            createElementVNode("div", _hoisted_23$3, [
              _cache[52] || (_cache[52] = createElementVNode(
                "label",
                null,
                "ID",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "cw-id",
                "data-grafana-label": "ID",
                value: String(query.value.id ?? ""),
                placeholder: "e1 (可选，用于 SEARCH/MATH 引用)",
                "onUpdate:value": _cache[18] || (_cache[18] = ($event) => patch({ id: $event || void 0 }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_24$3, [
              _cache[53] || (_cache[53] = createElementVNode(
                "label",
                null,
                "Label",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "cw-label",
                "data-grafana-label": "Label",
                value: String(query.value.label ?? query.value.alias ?? ""),
                placeholder: "{{metric}} / dynamic label",
                "onUpdate:value": _cache[19] || (_cache[19] = ($event) => patch({ label: $event, alias: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_25$3, [
              _cache[54] || (_cache[54] = createElementVNode(
                "label",
                null,
                "别名",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "cw-alias",
                value: String(query.value.alias ?? ""),
                placeholder: "{{metric}}",
                "onUpdate:value": _cache[20] || (_cache[20] = ($event) => patch({ alias: $event }))
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        isLogs.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createElementVNode("div", _hoisted_26$3, [
              _cache[55] || (_cache[55] = createElementVNode(
                "label",
                null,
                "日志模式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-logs-mode",
                "data-grafana-label": "Logs Mode",
                value: String(query.value.logsMode ?? query.value.logMode ?? "Logs"),
                options: [
                  { label: "Logs", value: "Logs" },
                  { label: "Logs Insights", value: "Insights" },
                  { label: "Anomalies", value: "Anomalies" }
                ],
                "onUpdate:value": _cache[21] || (_cache[21] = ($event) => patch({ logsMode: $event, logMode: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_27$2, [
              _cache[56] || (_cache[56] = createElementVNode(
                "label",
                null,
                "查询语言",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "cw-query-language",
                "data-grafana-label": "Query language",
                value: String(query.value.queryLanguage ?? "CWLI"),
                options: [
                  { label: "CWLI", value: "CWLI" },
                  { label: "SQL", value: "SQL" },
                  { label: "PPL", value: "PPL" }
                ],
                "onUpdate:value": _cache[22] || (_cache[22] = ($event) => patch({ queryLanguage: $event }))
              }, null, 8, ["value"])
            ]),
            isAnomalies.value ? (openBlock(), createElementBlock(
              Fragment,
              { key: 0 },
              [
                createElementVNode("div", _hoisted_28$2, [
                  _cache[57] || (_cache[57] = createElementVNode(
                    "label",
                    null,
                    "Anomaly Detection ARN",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-anomaly-arn",
                    "data-grafana-label": "Anomaly Detection ARN",
                    value: String(query.value.anomalyDetectionARN ?? ""),
                    placeholder: "arn:aws:logs:…:anomaly-detector/…",
                    "onUpdate:value": _cache[23] || (_cache[23] = ($event) => patch({ anomalyDetectionARN: $event || void 0 }))
                  }, null, 8, ["value"])
                ]),
                createElementVNode("div", _hoisted_29$2, [
                  _cache[58] || (_cache[58] = createElementVNode(
                    "label",
                    null,
                    "Supression state",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Select), {
                    style: { "width": "100%" },
                    "data-testid": "cw-suppression-state",
                    "data-grafana-label": "Supression state",
                    value: String(query.value.suppressionState ?? "all"),
                    options: [
                      { label: "All", value: "all" },
                      { label: "Suppressed", value: "suppressed" },
                      { label: "Unsuppressed", value: "unsuppressed" }
                    ],
                    "onUpdate:value": _cache[24] || (_cache[24] = ($event) => patch({ suppressionState: $event }))
                  }, null, 8, ["value"])
                ])
              ],
              64
              /* STABLE_FRAGMENT */
            )) : (openBlock(), createElementBlock(
              Fragment,
              { key: 1 },
              [
                createCommentVNode(" Grafana LogGroupsField: Query scope / Prefixes / Class / Accounts / Log groups "),
                createElementVNode("div", _hoisted_30$2, [
                  _cache[59] || (_cache[59] = createElementVNode(
                    "label",
                    null,
                    "Query scope",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Select), {
                    style: { "width": "100%" },
                    "data-testid": "cw-query-scope",
                    "data-grafana-label": "Query scope",
                    value: String(query.value.logsQueryScope ?? "logGroupName"),
                    options: [
                      { label: "Log group name", value: "logGroupName" },
                      { label: "Name prefix", value: "namePrefix" },
                      { label: "All log groups", value: "allLogGroups" }
                    ],
                    "onUpdate:value": _cache[25] || (_cache[25] = ($event) => patch({ logsQueryScope: $event }))
                  }, null, 8, ["value"])
                ]),
                String(query.value.logsQueryScope ?? "logGroupName") === "namePrefix" ? (openBlock(), createElementBlock("div", _hoisted_31$2, [
                  _cache[60] || (_cache[60] = createElementVNode(
                    "label",
                    null,
                    "Prefixes",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-log-group-prefixes",
                    "data-grafana-label": "Prefixes",
                    value: String(
                      Array.isArray(query.value.logGroupPrefixes) ? query.value.logGroupPrefixes.join(",") : query.value.logGroupPrefixes ?? ""
                    ),
                    placeholder: "/aws/lambda/,/aws/ecs/",
                    "onUpdate:value": _cache[26] || (_cache[26] = (v) => {
                      const prefixes = String(v || "").split(",").map((s) => s.trim()).filter(Boolean);
                      patch({ logGroupPrefixes: prefixes });
                    })
                  }, null, 8, ["value"])
                ])) : createCommentVNode("v-if", true),
                String(query.value.logsQueryScope ?? "logGroupName") === "namePrefix" || String(query.value.logsQueryScope ?? "") === "allLogGroups" ? (openBlock(), createElementBlock("div", _hoisted_32$2, [
                  _cache[61] || (_cache[61] = createElementVNode(
                    "label",
                    null,
                    "Class",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Select), {
                    style: { "width": "100%" },
                    "data-testid": "cw-log-group-class",
                    "data-grafana-label": "Class",
                    value: String(query.value.logGroupClass ?? "STANDARD"),
                    options: [
                      { label: "Standard", value: "STANDARD" },
                      { label: "Infrequent Access", value: "INFREQUENT_ACCESS" }
                    ],
                    "onUpdate:value": _cache[27] || (_cache[27] = ($event) => patch({ logGroupClass: $event }))
                  }, null, 8, ["value"])
                ])) : createCommentVNode("v-if", true),
                createElementVNode("div", _hoisted_33$2, [
                  _cache[62] || (_cache[62] = createElementVNode(
                    "label",
                    null,
                    "Accounts",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-accounts",
                    "data-grafana-label": "Accounts",
                    value: String(
                      Array.isArray(query.value.accountIds) ? query.value.accountIds.join(",") : Array.isArray(query.value.selectedAccountIds) ? query.value.selectedAccountIds.join(",") : query.value.accountIds ?? query.value.selectedAccountIds ?? ""
                    ),
                    placeholder: "123456789012, or template $account",
                    "onUpdate:value": _cache[28] || (_cache[28] = (v) => {
                      const ids = String(v || "").split(",").map((s) => s.trim()).filter(Boolean);
                      patch({ accountIds: ids, selectedAccountIds: ids });
                    })
                  }, null, 8, ["value"])
                ]),
                String(query.value.logsQueryScope ?? "logGroupName") === "logGroupName" ? (openBlock(), createElementBlock("div", _hoisted_34$2, [
                  _cache[63] || (_cache[63] = createElementVNode(
                    "label",
                    null,
                    "日志组",
                    -1
                    /* CACHED */
                  )),
                  createVNode(unref(Input), {
                    "data-testid": "cw-log-groups",
                    "data-grafana-label": "Log groups",
                    value: String(
                      Array.isArray(query.value.logGroups) ? query.value.logGroups.map((g) => g.name || g).join(",") : query.value.logGroupNames ? query.value.logGroupNames.join?.(",") || query.value.logGroupNames : ""
                    ),
                    placeholder: "/aws/lambda/fn1,/aws/lambda/fn2",
                    "onUpdate:value": _cache[29] || (_cache[29] = (v) => {
                      const names = String(v || "").split(",").map((s) => s.trim()).filter(Boolean);
                      patch({
                        logGroupNames: names,
                        logGroups: names.map((name) => ({ name }))
                      });
                    })
                  }, null, 8, ["value"])
                ])) : createCommentVNode("v-if", true)
              ],
              64
              /* STABLE_FRAGMENT */
            ))
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        createVNode(unref(GCodeEditor), {
          value: String(query.value.expression ?? query.value.query ?? ""),
          language: "plaintext",
          height: 100,
          "test-id": "cw-expression",
          "data-testid": "cw-expression",
          "data-grafana-label": "Expression",
          "onUpdate:value": _cache[30] || (_cache[30] = ($event) => patch({ expression: $event, query: $event }))
        }, null, 8, ["value"]),
        createElementVNode(
          "div",
          _hoisted_35$1,
          toDisplayString(unref(cwPlaceholder)),
          1
          /* TEXT */
        )
      ]);
    };
  }
});
const CloudWatchQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1R, [["__scopeId", "data-v-501d4437"]]);
const _hoisted_1$1g = ["data-scenario"];
const _hoisted_2$U = { class: "row" };
const _hoisted_3$P = { class: "row" };
const _hoisted_4$G = { class: "row" };
const _hoisted_5$y = { class: "row" };
const _hoisted_6$w = { class: "row" };
const _hoisted_7$u = { class: "row" };
const _hoisted_8$o = { class: "row" };
const _hoisted_9$m = { class: "row" };
const _hoisted_10$i = { class: "row" };
const _hoisted_11$e = {
  key: 1,
  class: "row"
};
const _hoisted_12$b = {
  key: 2,
  class: "row"
};
const _hoisted_13$a = {
  key: 3,
  class: "hint",
  "data-testid": "testdata-graph-hint"
};
const _hoisted_14$8 = { class: "row" };
const _hoisted_15$6 = {
  key: 4,
  class: "row"
};
const _hoisted_16$5 = { class: "row" };
const _hoisted_17$5 = {
  key: 5,
  class: "row"
};
const _hoisted_18$5 = {
  key: 6,
  class: "row"
};
const _hoisted_19$5 = {
  key: 7,
  class: "row"
};
const _hoisted_20$4 = {
  key: 8,
  class: "row"
};
const _hoisted_21$3 = {
  key: 9,
  class: "row"
};
const _hoisted_22$3 = {
  key: 10,
  class: "row"
};
const _hoisted_23$2 = {
  key: 11,
  class: "row"
};
const _hoisted_24$2 = {
  key: 12,
  class: "row"
};
const _hoisted_25$2 = { class: "row" };
const _hoisted_26$2 = { class: "row" };
const _hoisted_27$1 = { class: "row" };
const _hoisted_28$1 = { class: "row" };
const _hoisted_29$1 = { class: "row" };
const _hoisted_30$1 = { class: "row" };
const _hoisted_31$1 = { class: "row" };
const _hoisted_32$1 = { class: "row" };
const _hoisted_33$1 = { class: "row" };
const _hoisted_34$1 = { class: "row" };
const _sfc_main$1Q = /* @__PURE__ */ defineComponent({
  __name: "TestdataQueryFields",
  props: {
    query: {}
  },
  emits: ["patch"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    function patch(partial) {
      emit("patch", partial);
    }
    const scenario = computed(
      () => String(query.value.scenarioId ?? "random_walk")
    );
    const isCsv = computed(() => /csv/i.test(scenario.value));
    const isLogs = computed(() => scenario.value === "logs");
    const isPulse = computed(() => /pulse|wave|predictable/i.test(scenario.value));
    const isNode = computed(() => scenario.value === "node_graph");
    const isFlame = computed(() => scenario.value === "flame_graph");
    const isTrace = computed(() => scenario.value === "trace");
    const isFlaky = computed(() => scenario.value === "flaky_query");
    const isSimulation = computed(() => scenario.value === "simulation");
    const isLive = computed(
      () => scenario.value === "live" || scenario.value === "streaming_client"
    );
    const isRandomWalk = computed(
      () => scenario.value === "random_walk" || scenario.value === "random_walk_table"
    );
    const isUsa = computed(() => scenario.value === "usa");
    const isNodeGraph = computed(() => scenario.value === "node_graph");
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "qf",
        "data-testid": "testdata-query-fields",
        "data-scenario": scenario.value
      }, [
        createElementVNode("div", _hoisted_2$U, [
          _cache[32] || (_cache[32] = createElementVNode(
            "label",
            null,
            "场景",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            value: scenario.value,
            "data-testid": "testdata-scenario",
            "data-grafana-label": "Scenario",
            options: [
              { label: "随机游走", value: "random_walk" },
              { label: "随机游走表格", value: "random_walk_table" },
              { label: "慢查询", value: "slow_query" },
              { label: "无数据", value: "no_data" },
              { label: "CSV 指标值", value: "csv_metric_values" },
              { label: "CSV 文件", value: "csv_file" },
              { label: "可预测脉冲", value: "predictable_pulse" },
              { label: "可预测波形", value: "predictable_csv_wave" },
              { label: "日志", value: "logs" },
              { label: "节点图", value: "node_graph" },
              { label: "火焰图", value: "flame_graph" },
              { label: "追踪", value: "trace" },
              { label: "USA 统计", value: "usa" },
              { label: "服务器错误模拟", value: "server_error_500" },
              { label: "手动输入", value: "manual_entry" },
              { label: "数据流", value: "streaming_client" },
              { label: "Grafana 实时", value: "live" },
              { label: "箭头数据帧", value: "arrow" },
              { label: "不稳定查询", value: "flaky_query" },
              { label: "仿真", value: "simulation" },
              { label: "阶梯", value: "steps" },
              { label: "注解", value: "annotations" },
              { label: "原始帧", value: "raw_frame" }
            ],
            "show-search": "",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ scenarioId: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$P, [
          _cache[33] || (_cache[33] = createElementVNode(
            "label",
            null,
            "别名",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.alias ?? ""),
            "data-testid": "testdata-alias",
            "data-grafana-label": "Alias",
            placeholder: "序列别名",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ alias: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$G, [
          _cache[34] || (_cache[34] = createElementVNode(
            "label",
            null,
            "序列数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            value: String(query.value.seriesCount ?? 1),
            "data-testid": "testdata-series-count",
            "data-grafana-label": "Count",
            "data-grafana-label-alt": "Series count",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ seriesCount: Number($event) || 1 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$y, [
          _cache[35] || (_cache[35] = createElementVNode(
            "label",
            null,
            "噪声",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-noise",
            "data-grafana-label": "Noise",
            value: String(query.value.noise ?? 0),
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ noise: Number($event) || 0 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$w, [
          _cache[36] || (_cache[36] = createElementVNode(
            "label",
            null,
            "离散度",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-spread",
            "data-grafana-label": "Spread",
            value: String(query.value.spread ?? 10),
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ spread: Number($event) || 0 }))
          }, null, 8, ["value"])
        ]),
        isRandomWalk.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createElementVNode("div", _hoisted_7$u, [
              _cache[37] || (_cache[37] = createElementVNode(
                "label",
                null,
                "起始值",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                type: "number",
                "data-testid": "testdata-start-value",
                "data-grafana-label": "Start value",
                value: query.value.startValue == null ? "" : String(query.value.startValue),
                placeholder: "自动",
                "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ startValue: $event === "" ? void 0 : Number($event) }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_8$o, [
              _cache[38] || (_cache[38] = createElementVNode(
                "label",
                null,
                "最小值",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                type: "number",
                "data-testid": "testdata-min",
                "data-grafana-label": "Min",
                value: query.value.min == null ? "" : String(query.value.min),
                placeholder: "无",
                "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ min: $event === "" ? void 0 : Number($event) }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_9$m, [
              _cache[39] || (_cache[39] = createElementVNode(
                "label",
                null,
                "最大值",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                type: "number",
                "data-testid": "testdata-max",
                "data-grafana-label": "Max",
                value: query.value.max == null ? "" : String(query.value.max),
                placeholder: "无",
                "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ max: $event === "" ? void 0 : Number($event) }))
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_10$i, [
          _cache[40] || (_cache[40] = createElementVNode(
            "label",
            null,
            "点数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-points",
            "data-grafana-label": "Values",
            value: String(query.value.points ?? query.value.lines ?? ""),
            placeholder: "自动",
            "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({
              points: $event === "" ? void 0 : Number($event),
              lines: $event === "" ? void 0 : Number($event)
            }))
          }, null, 8, ["value"])
        ]),
        isCsv.value || isPulse.value ? (openBlock(), createElementBlock("div", _hoisted_11$e, [
          _cache[41] || (_cache[41] = createElementVNode(
            "label",
            null,
            "CSV 值",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(query.value.stringInput ?? query.value.csvFileName ?? ""),
            placeholder: "1,20,90,30,5,0",
            "data-testid": "testdata-csv",
            "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patch({ stringInput: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isLogs.value ? (openBlock(), createElementBlock("div", _hoisted_12$b, [
          _cache[42] || (_cache[42] = createElementVNode(
            "label",
            null,
            "日志行数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-lines",
            "data-grafana-label": "Lines",
            value: String(query.value.lines ?? 10),
            "onUpdate:value": _cache[10] || (_cache[10] = ($event) => patch({ lines: Number($event) || 10 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isNode.value || isFlame.value || isTrace.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_13$a,
          " 场景「" + toDisplayString(scenario.value) + "」会生成对应面板的演示结构数据（节点/火焰/追踪）。 ",
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_14$8, [
          _cache[43] || (_cache[43] = createElementVNode(
            "label",
            null,
            "丢弃 %",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-drop-percent",
            "data-grafana-label": "Drop",
            value: String(query.value.dropPercent ?? 0),
            "onUpdate:value": _cache[11] || (_cache[11] = ($event) => patch({ dropPercent: Number($event) || 0 }))
          }, null, 8, ["value"])
        ]),
        isRandomWalk.value || isPulse.value ? (openBlock(), createElementBlock("div", _hoisted_15$6, [
          _cache[44] || (_cache[44] = createElementVNode(
            "label",
            null,
            "标签",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-labels",
            "data-grafana-label": "Labels",
            value: String(query.value.labels ?? ""),
            placeholder: "key=value, key2=value",
            "onUpdate:value": _cache[12] || (_cache[12] = ($event) => patch({ labels: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_16$5, [
          _cache[45] || (_cache[45] = createElementVNode(
            "label",
            null,
            "带标签",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            style: { width: "46px" },
            "data-testid": "testdata-with-labels",
            "data-grafana-label": "Labels",
            checked: !!query.value.withLabels,
            "onUpdate:checked": _cache[13] || (_cache[13] = ($event) => patch({ withLabels: $event }))
          }, null, 8, ["checked"])
        ]),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_17$5, [
          _cache[46] || (_cache[46] = createElementVNode(
            "label",
            null,
            "错误率",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            "data-testid": "testdata-error-rate",
            "data-grafana-label": "Error rate",
            value: String(query.value.errorRate ?? 0),
            placeholder: "0-100",
            "onUpdate:value": _cache[14] || (_cache[14] = ($event) => patch({ errorRate: Number($event) || 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_18$5, [
          _cache[47] || (_cache[47] = createElementVNode(
            "label",
            null,
            "状态码",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-status-code",
            "data-grafana-label": "Status code",
            value: String(query.value.statusCode ?? 500),
            "onUpdate:value": _cache[15] || (_cache[15] = ($event) => patch({ statusCode: Number($event) || 500 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_19$5, [
          _cache[48] || (_cache[48] = createElementVNode(
            "label",
            null,
            "错误来源",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "testdata-error-source",
            "data-grafana-label": "Error source",
            value: String(query.value.errorSource ?? "plugin"),
            options: [
              { label: "插件", value: "plugin" },
              { label: "下游", value: "downstream" }
            ],
            "onUpdate:value": _cache[16] || (_cache[16] = ($event) => patch({ errorSource: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_20$4, [
          _cache[49] || (_cache[49] = createElementVNode(
            "label",
            null,
            "查询延迟",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-query-delay",
            "data-grafana-label": "Query delay",
            value: String(query.value.queryDelay ?? ""),
            placeholder: "1s",
            "onUpdate:value": _cache[17] || (_cache[17] = ($event) => patch({ queryDelay: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_21$3, [
          _cache[50] || (_cache[50] = createElementVNode(
            "label",
            null,
            "延迟波动",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-delay-variability",
            "data-grafana-label": "Delay variability",
            value: String(query.value.delayVariability ?? ""),
            placeholder: "0.5",
            "onUpdate:value": _cache[18] || (_cache[18] = ($event) => patch({ delayVariability: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isFlaky.value ? (openBlock(), createElementBlock("div", _hoisted_22$3, [
          _cache[51] || (_cache[51] = createElementVNode(
            "label",
            null,
            "错误消息",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-error-message",
            "data-grafana-label": "Error message",
            value: String(query.value.errorMessage ?? ""),
            placeholder: "模拟错误",
            "onUpdate:value": _cache[19] || (_cache[19] = ($event) => patch({ errorMessage: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isSimulation.value || isPulse.value ? (openBlock(), createElementBlock("div", _hoisted_23$2, [
          _cache[52] || (_cache[52] = createElementVNode(
            "label",
            null,
            "间隔",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-interval",
            "data-grafana-label": "Interval",
            value: String(query.value.interval ?? query.value.stream?.interval ?? ""),
            placeholder: "1s",
            "onUpdate:value": _cache[20] || (_cache[20] = ($event) => patch({ interval: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isLive.value ? (openBlock(), createElementBlock("div", _hoisted_24$2, [
          _cache[53] || (_cache[53] = createElementVNode(
            "label",
            null,
            "通道",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "testdata-channel",
            "data-grafana-label": "Channel",
            value: String(query.value.channel ?? ""),
            placeholder: "plugin/testdata/…",
            "onUpdate:value": _cache[21] || (_cache[21] = ($event) => patch({ channel: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        isUsa.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 13 },
          [
            createElementVNode("div", _hoisted_25$2, [
              _cache[54] || (_cache[54] = createElementVNode(
                "label",
                null,
                "模式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "testdata-usa-mode",
                "data-grafana-label": "Mode",
                value: String(query.value.usa?.mode ?? query.value.mode ?? "timeseries"),
                options: [
                  { label: "时序", value: "timeseries" },
                  { label: "表格", value: "table" }
                ],
                "onUpdate:value": _cache[22] || (_cache[22] = (v) => patch({ mode: v, usa: { ...query.value.usa, mode: v } }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_26$2, [
              _cache[55] || (_cache[55] = createElementVNode(
                "label",
                null,
                "周期",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "testdata-usa-period",
                "data-grafana-label": "Period",
                value: String(query.value.usa?.period ?? query.value.period ?? ""),
                placeholder: "10m",
                "onUpdate:value": _cache[23] || (_cache[23] = (v) => patch({ period: v, usa: { ...query.value.usa, period: v } }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_27$1, [
              _cache[56] || (_cache[56] = createElementVNode(
                "label",
                null,
                "字段",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "testdata-usa-fields",
                "data-grafana-label": "Fields",
                value: String(query.value.usa?.fields ?? query.value.fields ?? ""),
                placeholder: "foo,bar",
                "onUpdate:value": _cache[24] || (_cache[24] = (v) => patch({ fields: v, usa: { ...query.value.usa, fields: v } }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_28$1, [
              _cache[57] || (_cache[57] = createElementVNode(
                "label",
                null,
                "州/省",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "testdata-usa-states",
                "data-grafana-label": "States",
                value: String(query.value.usa?.states ?? query.value.states ?? ""),
                placeholder: "CA,NY",
                "onUpdate:value": _cache[25] || (_cache[25] = (v) => patch({ states: v, usa: { ...query.value.usa, states: v } }))
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        isSimulation.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 14 },
          [
            createElementVNode("div", _hoisted_29$1, [
              _cache[58] || (_cache[58] = createElementVNode(
                "label",
                null,
                "仿真",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "testdata-simulation",
                "data-grafana-label": "Simulation",
                value: String(query.value.sim?.type ?? query.value.simulation ?? ""),
                placeholder: "flight",
                "onUpdate:value": _cache[26] || (_cache[26] = (v) => patch({ simulation: v, sim: { ...query.value.sim, type: v } }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_30$1, [
              _cache[59] || (_cache[59] = createElementVNode(
                "label",
                null,
                "流式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Switch), {
                "data-testid": "testdata-stream",
                "data-grafana-label": "Stream",
                checked: !!(query.value.stream?.enabled ?? query.value.streamEnabled),
                "onUpdate:checked": _cache[27] || (_cache[27] = (v) => patch({
                  streamEnabled: v,
                  stream: { ...query.value.stream, enabled: v }
                }))
              }, null, 8, ["checked"])
            ]),
            createElementVNode("div", _hoisted_31$1, [
              _cache[60] || (_cache[60] = createElementVNode(
                "label",
                null,
                "仅最后",
                -1
                /* CACHED */
              )),
              createVNode(unref(Switch), {
                "data-testid": "testdata-last",
                "data-grafana-label": "Last",
                checked: !!query.value.last,
                "onUpdate:checked": _cache[28] || (_cache[28] = ($event) => patch({ last: $event }))
              }, null, 8, ["checked"])
            ]),
            createElementVNode("div", _hoisted_32$1, [
              _cache[61] || (_cache[61] = createElementVNode(
                "label",
                null,
                "UID",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "testdata-uid",
                "data-grafana-label": "UID",
                value: String(query.value.uid ?? query.value.sim?.uid ?? ""),
                placeholder: "仿真 UID",
                "onUpdate:value": _cache[29] || (_cache[29] = (v) => patch({
                  uid: v || void 0,
                  sim: { ...query.value.sim, uid: v }
                }))
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        isNodeGraph.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 15 },
          [
            createElementVNode("div", _hoisted_33$1, [
              _cache[62] || (_cache[62] = createElementVNode(
                "label",
                null,
                "数据类型",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "testdata-node-data-type",
                "data-grafana-label": "Data type",
                value: String(query.value.nodes?.type ?? query.value.nodeType ?? "random"),
                options: [
                  { label: "随机", value: "random" },
                  { label: "小型响应", value: "response_small" },
                  { label: "中型响应", value: "response_medium" }
                ],
                "onUpdate:value": _cache[30] || (_cache[30] = (v) => patch({
                  nodeType: v,
                  nodes: { ...query.value.nodes, type: v }
                }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_34$1, [
              _cache[63] || (_cache[63] = createElementVNode(
                "label",
                null,
                "种子",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                type: "number",
                "data-testid": "testdata-seed",
                "data-grafana-label": "Seed",
                value: query.value.nodes?.seed == null && query.value.seed == null ? "" : String(query.value.nodes?.seed ?? query.value.seed),
                "onUpdate:value": _cache[31] || (_cache[31] = (v) => {
                  const n = v === "" ? void 0 : Number(v);
                  patch({ seed: n, nodes: { ...query.value.nodes, seed: n } });
                })
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$1g);
    };
  }
});
const TestdataQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1Q, [["__scopeId", "data-v-137710ce"]]);
const _hoisted_1$1f = {
  class: "qf",
  "data-testid": "es-qe"
};
const _hoisted_2$T = { class: "row" };
const _hoisted_3$O = {
  class: "row",
  "data-testid": "es-field-browser",
  "data-grafana-label": "Field"
};
const _hoisted_4$F = {
  class: "section",
  "data-testid": "es-metrics",
  "data-grafana-label": "Metrics"
};
const _hoisted_5$x = { class: "section-head" };
const _hoisted_6$v = { class: "section-actions" };
const _hoisted_7$t = {
  class: "section",
  "data-testid": "es-bucket-aggs",
  "data-grafana-label": "Group by"
};
const _hoisted_8$n = { class: "section-head" };
const _hoisted_9$l = {
  key: 0,
  class: "hint"
};
const _hoisted_10$h = { class: "row" };
const _hoisted_11$d = { class: "row" };
const _hoisted_12$a = { class: "row" };
const _hoisted_13$9 = { class: "row" };
const _sfc_main$1P = /* @__PURE__ */ defineComponent({
  __name: "ElasticsearchQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const METRIC_TYPES = [
      { label: "Count", value: "count" },
      { label: "Average", value: "avg" },
      { label: "Sum", value: "sum" },
      { label: "Max", value: "max" },
      { label: "Min", value: "min" },
      { label: "Extended Stats", value: "extended_stats" },
      { label: "Percentiles", value: "percentiles" },
      { label: "Cardinality", value: "cardinality" },
      { label: "Raw Document", value: "raw_document" },
      { label: "Raw Data", value: "raw_data" },
      { label: "Logs", value: "logs" },
      { label: "Rate", value: "rate" },
      { label: "Top Metrics", value: "top_metrics" },
      // Pipeline aggregations (grafana PipelineAggregations)
      { label: "Derivative", value: "derivative" },
      { label: "Cumulative Sum", value: "cumulative_sum" },
      { label: "Moving Average", value: "moving_avg" },
      { label: "Moving Function", value: "moving_fn" },
      { label: "Serial Diff", value: "serial_diff" },
      { label: "Bucket Script", value: "bucket_script" }
    ];
    const PIPELINE_TYPES = /* @__PURE__ */ new Set([
      "derivative",
      "cumulative_sum",
      "moving_avg",
      "moving_fn",
      "serial_diff",
      "bucket_script"
    ]);
    const BUCKET_TYPES = [
      { label: "Date Histogram", value: "date_histogram" },
      { label: "Histogram", value: "histogram" },
      { label: "Terms", value: "terms" },
      { label: "Filters", value: "filters" },
      { label: "Geo Hash Grid", value: "geohash_grid" },
      { label: "Nested", value: "nested" }
    ];
    const DEMO_FIELDS = [
      "@timestamp",
      "message",
      "host",
      "service",
      "level",
      "status",
      "duration",
      "bytes",
      "method",
      "path",
      "user",
      "geoip.country_code"
    ];
    function asMetrics() {
      const m = query.value.metrics;
      if (Array.isArray(m) && m.length) return m;
      return [{ id: "1", type: "count" }];
    }
    function asBuckets() {
      const b = query.value.bucketAggs;
      if (Array.isArray(b) && b.length) return b;
      if (String(query.value.queryType ?? "metrics") === "metrics") {
        return [
          {
            id: "2",
            type: "date_histogram",
            field: String(query.value.timeField ?? "@timestamp")
          }
        ];
      }
      return [];
    }
    const metrics = computed(() => asMetrics());
    const buckets = computed(() => asBuckets());
    const fieldOptions = ref(
      DEMO_FIELDS.map((f) => ({ label: f, value: f }))
    );
    async function refreshFields() {
      const api = props.datasourceApi;
      try {
        if (api?.getTagKeys) {
          const rows = await api.getTagKeys();
          if (rows?.length) {
            fieldOptions.value = rows.map((r) => ({
              label: r.text,
              value: r.text
            }));
            return;
          }
        }
        if (api?.metricFindQuery) {
          const rows = await api.metricFindQuery("fields()");
          if (rows?.length) {
            fieldOptions.value = rows.map((r) => ({
              label: r.text,
              value: String(r.value ?? r.text)
            }));
            return;
          }
        }
      } catch {
      }
      fieldOptions.value = DEMO_FIELDS.map((f) => ({ label: f, value: f }));
    }
    watch(
      () => props.datasourceApi,
      () => void refreshFields(),
      { immediate: true }
    );
    function nextId(list) {
      const nums = list.map((x) => Number(x.id)).filter((n) => Number.isFinite(n));
      return String((nums.length ? Math.max(...nums) : 0) + 1);
    }
    function setMetrics(next) {
      patch({ metrics: next });
    }
    function setBuckets(next) {
      patch({ bucketAggs: next });
    }
    function updateMetric(i, partial) {
      const next = metrics.value.map(
        (m, idx) => idx === i ? { ...m, ...partial } : m
      );
      setMetrics(next);
    }
    function updateBucket(i, partial) {
      const next = buckets.value.map(
        (b, idx) => idx === i ? { ...b, ...partial } : b
      );
      setBuckets(next);
    }
    function addMetric() {
      setMetrics([
        ...metrics.value,
        { id: nextId(metrics.value), type: "avg", field: "" }
      ]);
    }
    function addPipelineMetric() {
      const parent = metrics.value[0]?.id ?? "1";
      setMetrics([
        ...metrics.value,
        {
          id: nextId(metrics.value),
          type: "derivative",
          pipelineAgg: parent,
          field: ""
        }
      ]);
    }
    function removeMetric(i) {
      if (metrics.value.length <= 1) return;
      setMetrics(metrics.value.filter((_, idx) => idx !== i));
    }
    function addBucket() {
      setBuckets([
        ...buckets.value,
        { id: nextId(buckets.value), type: "terms", field: "" }
      ]);
    }
    function removeBucket(i) {
      setBuckets(buckets.value.filter((_, idx) => idx !== i));
    }
    const showAggs = computed(() => {
      const qt = String(query.value.queryType ?? "metrics");
      return qt === "metrics" || qt === "";
    });
    const parentMetricOptions = computed(
      () => metrics.value.map((m) => ({ label: `${m.id}: ${m.type}`, value: m.id }))
    );
    function isPipeline(type) {
      return PIPELINE_TYPES.has(type);
    }
    function needsField(type) {
      return type !== "count" && type !== "raw_document" && type !== "raw_data" && type !== "logs" && !isPipeline(type);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1f, [
        createElementVNode("div", _hoisted_2$T, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "es-query-type",
            "data-grafana-label": "Query type",
            value: String(query.value.queryType ?? "metrics"),
            options: [
              { label: "指标 (Metrics)", value: "metrics" },
              { label: "日志 (Logs)", value: "logs" },
              { label: "原始文档", value: "raw_data" },
              { label: "原始文档量", value: "raw_document" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        _cache[20] || (_cache[20] = createElementVNode(
          "div",
          { class: "row" },
          [
            createElementVNode("label", null, "Lucene 查询")
          ],
          -1
          /* CACHED */
        )),
        createVNode(unref(GCodeEditor), {
          value: expr.value,
          "onUpdate:value": _cache[1] || (_cache[1] = ($event) => expr.value = $event),
          language: "plaintext",
          height: 100,
          "test-id": "es-query",
          "data-testid": "es-query",
          "data-grafana-label": "Query"
        }, null, 8, ["value"]),
        createElementVNode("div", _hoisted_3$O, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "字段浏览",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "es-field-select",
            "show-search": "",
            "allow-clear": "",
            placeholder: "浏览字段…",
            options: fieldOptions.value,
            value: void 0,
            "onUpdate:value": _cache[2] || (_cache[2] = (v) => {
              if (v) expr.value = expr.value ? `${expr.value} AND ${v}:*` : `${v}:*`;
            })
          }, null, 8, ["options"])
        ]),
        showAggs.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createElementVNode("div", _hoisted_4$F, [
              createElementVNode("div", _hoisted_5$x, [
                _cache[11] || (_cache[11] = createElementVNode(
                  "span",
                  null,
                  "指标",
                  -1
                  /* CACHED */
                )),
                createElementVNode("div", _hoisted_6$v, [
                  createVNode(unref(Button), {
                    size: "small",
                    "data-testid": "es-add-metric",
                    onClick: addMetric
                  }, {
                    default: withCtx(() => [..._cache[9] || (_cache[9] = [
                      createTextVNode(
                        "添加指标",
                        -1
                        /* CACHED */
                      )
                    ])]),
                    _: 1
                    /* STABLE */
                  }),
                  createVNode(unref(Button), {
                    size: "small",
                    "data-testid": "es-add-pipeline",
                    onClick: addPipelineMetric
                  }, {
                    default: withCtx(() => [..._cache[10] || (_cache[10] = [
                      createTextVNode(
                        "添加管道",
                        -1
                        /* CACHED */
                      )
                    ])]),
                    _: 1
                    /* STABLE */
                  })
                ])
              ]),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(metrics.value, (m, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: m.id,
                    class: "agg-row",
                    "data-testid": "es-metric-row"
                  }, [
                    createVNode(unref(Select), {
                      style: { "width": "160px" },
                      "data-testid": "es-metric-type",
                      value: m.type,
                      options: METRIC_TYPES,
                      "onUpdate:value": (v) => updateMetric(i, { type: v })
                    }, null, 8, ["value", "onUpdate:value"]),
                    isPipeline(m.type) ? (openBlock(), createBlock(unref(Select), {
                      key: 0,
                      style: { "width": "140px" },
                      "data-testid": "es-pipeline-parent",
                      value: m.pipelineAgg ?? metrics.value[0]?.id,
                      options: parentMetricOptions.value,
                      placeholder: "父指标",
                      "onUpdate:value": (v) => updateMetric(i, { pipelineAgg: v })
                    }, null, 8, ["value", "options", "onUpdate:value"])) : needsField(m.type) ? (openBlock(), createBlock(unref(Select), {
                      key: 1,
                      style: { "flex": "1", "min-width": "120px" },
                      "data-testid": "es-metric-field",
                      "show-search": "",
                      "allow-clear": "",
                      value: m.field ?? void 0,
                      options: fieldOptions.value,
                      placeholder: "字段",
                      "onUpdate:value": (v) => updateMetric(i, { field: v || "" })
                    }, null, 8, ["value", "options", "onUpdate:value"])) : createCommentVNode("v-if", true),
                    m.type === "bucket_script" ? (openBlock(), createBlock(unref(Input), {
                      key: 2,
                      "data-testid": "es-bucket-script",
                      style: { "flex": "1" },
                      value: String(m.settings?.script ?? ""),
                      placeholder: "脚本 params.A / params.B",
                      "onUpdate:value": (v) => updateMetric(i, {
                        settings: { ...m.settings ?? {}, script: v }
                      })
                    }, null, 8, ["value", "onUpdate:value"])) : createCommentVNode("v-if", true),
                    createVNode(unref(Button), {
                      size: "small",
                      danger: "",
                      disabled: metrics.value.length <= 1,
                      onClick: ($event) => removeMetric(i)
                    }, {
                      default: withCtx(() => [..._cache[12] || (_cache[12] = [
                        createTextVNode(
                          "删除",
                          -1
                          /* CACHED */
                        )
                      ])]),
                      _: 1
                      /* STABLE */
                    }, 8, ["disabled", "onClick"])
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ]),
            createElementVNode("div", _hoisted_7$t, [
              createElementVNode("div", _hoisted_8$n, [
                _cache[14] || (_cache[14] = createElementVNode(
                  "span",
                  null,
                  "分桶",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(Button), {
                  size: "small",
                  "data-testid": "es-add-bucket",
                  onClick: addBucket
                }, {
                  default: withCtx(() => [..._cache[13] || (_cache[13] = [
                    createTextVNode(
                      "添加分桶",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                })
              ]),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(buckets.value, (b, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: b.id,
                    class: "agg-row",
                    "data-testid": "es-bucket-row"
                  }, [
                    createVNode(unref(Select), {
                      style: { "width": "160px" },
                      "data-testid": "es-bucket-type",
                      value: b.type,
                      options: BUCKET_TYPES,
                      "onUpdate:value": (v) => updateBucket(i, { type: v })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Select), {
                      style: { "flex": "1", "min-width": "120px" },
                      "data-testid": "es-bucket-field",
                      "show-search": "",
                      "allow-clear": "",
                      value: b.field ?? void 0,
                      options: fieldOptions.value,
                      placeholder: "字段",
                      "onUpdate:value": (v) => updateBucket(i, { field: v || "" })
                    }, null, 8, ["value", "options", "onUpdate:value"]),
                    createVNode(unref(Button), {
                      size: "small",
                      danger: "",
                      onClick: ($event) => removeBucket(i)
                    }, {
                      default: withCtx(() => [..._cache[15] || (_cache[15] = [
                        createTextVNode(
                          "删除",
                          -1
                          /* CACHED */
                        )
                      ])]),
                      _: 1
                      /* STABLE */
                    }, 8, ["onClick"])
                  ]);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              !buckets.value.length ? (openBlock(), createElementBlock("div", _hoisted_9$l, "无分桶（结果为单序列）")) : createCommentVNode("v-if", true)
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_10$h, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "时间字段",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "es-time-field",
            "data-grafana-label": "Time field",
            "show-search": "",
            value: String(query.value.timeField ?? "@timestamp"),
            options: fieldOptions.value,
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ timeField: $event }))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_11$d, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "Size / 限制",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "es-size",
            "data-grafana-label": "Size",
            type: "number",
            value: String(query.value.size ?? query.value.limit ?? 500),
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ size: Number($event) || 500, limit: Number($event) || 500 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_12$a, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "Alias",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "es-alias",
            "data-grafana-label": "Alias",
            value: String(query.value.alias ?? ""),
            placeholder: "{{metric}}",
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ alias: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_13$9, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "Min interval",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "es-min-interval",
            "data-grafana-label": "Min interval",
            value: String(query.value.interval ?? query.value.minInterval ?? ""),
            placeholder: "auto",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({
              interval: $event || void 0,
              minInterval: $event || void 0
            }))
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const ElasticsearchQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1P, [["__scopeId", "data-v-430e115d"]]);
const _hoisted_1$1e = { class: "qf" };
const _hoisted_2$S = { class: "row" };
const _hoisted_3$N = {
  class: "row",
  "data-testid": "tempo-service-browser"
};
const _hoisted_4$E = {
  class: "row",
  "data-testid": "tempo-tag-browser"
};
const _hoisted_5$w = {
  key: 0,
  class: "meta-err",
  "data-testid": "tempo-meta-error"
};
const _hoisted_6$u = { class: "row" };
const _hoisted_7$s = {
  key: 2,
  class: "hint",
  "data-testid": "tempo-service-map-hint"
};
const _hoisted_8$m = { class: "row" };
const _hoisted_9$k = { class: "row" };
const _hoisted_10$g = { class: "row" };
const _hoisted_11$c = { class: "row" };
const _hoisted_12$9 = {
  key: 3,
  class: "row"
};
const _sfc_main$1O = /* @__PURE__ */ defineComponent({
  __name: "TempoQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const queryType = computed(() => String(query.value.queryType ?? "traceql"));
    const isSearch = computed(() => queryType.value === "search");
    const isServiceMap = computed(() => queryType.value === "serviceMap");
    const tagOptions = ref([]);
    const serviceOptions = ref([]);
    const selectedService = ref(
      String(query.value.service ?? "") || void 0
    );
    const selectedTag = ref();
    const metaError = ref("");
    const metaLoading = ref(false);
    async function loadTags() {
      metaLoading.value = true;
      metaError.value = "";
      try {
        const api = props.datasourceApi;
        if (typeof api?.listSearchTags === "function") {
          const rows = await api.listSearchTags();
          tagOptions.value = (rows || []).map((r) => ({
            label: String(r.text ?? r.value ?? r),
            value: String(r.value ?? r.text ?? r)
          }));
        } else {
          tagOptions.value = [
            { label: "service.name", value: "service.name" },
            { label: "http.method", value: "http.method" },
            { label: "http.status_code", value: "http.status_code" }
          ];
        }
        if (typeof api?.listServices === "function") {
          const rows = await api.listServices();
          serviceOptions.value = (rows || []).map((r) => ({
            label: String(r.text ?? r.value ?? r),
            value: String(r.value ?? r.text ?? r)
          }));
        } else {
          serviceOptions.value = [
            { label: "frontend", value: "frontend" },
            { label: "api", value: "api" },
            { label: "checkout", value: "checkout" }
          ];
        }
      } catch (e) {
        metaError.value = e instanceof Error ? e.message : String(e);
        tagOptions.value = [
          { label: "service.name", value: "service.name" },
          { label: "http.method", value: "http.method" }
        ];
        serviceOptions.value = [
          { label: "frontend", value: "frontend" },
          { label: "api", value: "api" }
        ];
      } finally {
        metaLoading.value = false;
      }
    }
    function onService(v) {
      const s = String(v ?? "");
      selectedService.value = s || void 0;
      patch({ service: s || void 0 });
      if (s && !isSearch.value) {
        const cur = expr.value.trim();
        const fragment = `{ resource.service.name = "${s}" }`;
        if (!cur || cur.startsWith("{") || cur.startsWith("resource.")) {
          expr.value = fragment;
        }
      }
    }
    function onTag(v) {
      const t2 = String(v ?? "");
      selectedTag.value = t2 || void 0;
      if (!t2) return;
      const cur = expr.value.trim();
      if (!cur) {
        expr.value = `{ ${t2} = "" }`;
      }
    }
    onMounted(loadTags);
    watch(
      () => props.datasourceApi,
      () => {
        void loadTags();
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1e, [
        createElementVNode("div", _hoisted_2$S, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "tempo-query-type",
            "data-grafana-label": "Query type",
            value: queryType.value,
            options: [
              { label: "TraceQL", value: "traceql" },
              { label: "搜索", value: "search" },
              { label: "Service Map", value: "serviceMap" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$N, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "Service（预取）",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            value: selectedService.value,
            options: serviceOptions.value,
            placeholder: "service.name",
            "data-testid": "tempo-service-select",
            "data-grafana-label": "Service Name",
            "onUpdate:value": onService
          }, null, 8, ["loading", "value", "options"])
        ]),
        createElementVNode("div", _hoisted_4$E, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "搜索标签",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            value: selectedTag.value,
            options: tagOptions.value,
            placeholder: "预取 Tempo 搜索标签",
            "data-testid": "tempo-tag-select",
            "data-grafana-label": "Search tags",
            "onUpdate:value": onTag
          }, null, 8, ["loading", "value", "options"])
        ]),
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_5$w,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        !isServiceMap.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createElementVNode("div", _hoisted_6$u, [
              createElementVNode(
                "label",
                null,
                toDisplayString(isSearch.value ? "搜索查询" : "TraceQL"),
                1
                /* TEXT */
              )
            ]),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 100,
              "test-id": "tempo-query"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : (openBlock(), createElementBlock("div", _hoisted_7$s, " Service Map 使用边/节点拓扑查询，无需 TraceQL。 ")),
        createElementVNode("div", _hoisted_8$m, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "限制",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "tempo-limit",
            "data-grafana-label": "Limit",
            value: String(query.value.limit ?? 20),
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ limit: Number($event) || 20 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$k, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "最小时长",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "tempo-min-duration",
            "data-grafana-label": "Min Duration",
            value: String(query.value.minDuration ?? ""),
            placeholder: "如 100ms",
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ minDuration: $event || void 0 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_10$g, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "最大时长",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "tempo-max-duration",
            "data-grafana-label": "Max Duration",
            value: String(query.value.maxDuration ?? ""),
            placeholder: "如 5s",
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ maxDuration: $event || void 0 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_11$c, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "搜索标签串",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "tempo-search-tags",
            "data-grafana-label": "Tags",
            value: String(query.value.tags ?? query.value.search ?? ""),
            placeholder: 'http.status_code=500 service.name="api"',
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ tags: $event, search: $event }))
          }, null, 8, ["value"])
        ]),
        isServiceMap.value ? (openBlock(), createElementBlock("div", _hoisted_12$9, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "Step",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "tempo-step",
            "data-grafana-label": "Step",
            value: String(query.value.step ?? ""),
            placeholder: "15s",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ step: $event || void 0 }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const TempoQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1O, [["__scopeId", "data-v-ec1c918a"]]);
const _hoisted_1$1d = { class: "qf" };
const _hoisted_2$R = { class: "row" };
const _hoisted_3$M = {
  key: 0,
  class: "meta-err"
};
const _hoisted_4$D = { class: "row" };
const _hoisted_5$v = { class: "row" };
const _hoisted_6$t = { class: "row" };
const _hoisted_7$r = { class: "row" };
const _hoisted_8$l = { class: "row" };
const _hoisted_9$j = { class: "row" };
const _hoisted_10$f = {
  key: 2,
  class: "hint",
  "data-testid": "jaeger-dep-hint"
};
const _sfc_main$1N = /* @__PURE__ */ defineComponent({
  __name: "JaegerQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr", "change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
      emit("change", { ...query.value, ...partial });
    }
    const queryType = computed(() => {
      const t2 = query.value.queryType;
      if (t2 === "search" || t2 === "dependencyGraph" || t2 === "upload")
        return String(t2);
      return t2 ? String(t2) : "traceID";
    });
    const isSearch = computed(() => queryType.value === "search");
    const isDep = computed(() => queryType.value === "dependencyGraph");
    const services = ref([]);
    const operations = ref([]);
    const metaLoading = ref(false);
    const metaError = ref("");
    async function loadServices() {
      metaLoading.value = true;
      metaError.value = "";
      try {
        const api = props.datasourceApi;
        if (typeof api?.metadataRequest === "function") {
          const rows = await api.metadataRequest("services");
          services.value = (Array.isArray(rows) ? rows : rows?.data || []).map(
            (s) => ({
              label: String(s),
              value: String(s)
            })
          );
        } else if (typeof api?.getServices === "function") {
          const rows = await api.getServices();
          services.value = (rows || []).map((s) => ({
            label: String(s.text ?? s.value ?? s),
            value: String(s.value ?? s.text ?? s)
          }));
        } else {
          services.value = [
            { label: "frontend", value: "frontend" },
            { label: "api", value: "api" },
            { label: "jaeger-query", value: "jaeger-query" }
          ];
        }
      } catch (e) {
        metaError.value = e instanceof Error ? e.message : String(e);
        services.value = [
          { label: "frontend", value: "frontend" },
          { label: "api", value: "api" }
        ];
      } finally {
        metaLoading.value = false;
      }
    }
    async function loadOperations(service) {
      if (!service) {
        operations.value = [{ label: "all", value: "" }];
        return;
      }
      try {
        const api = props.datasourceApi;
        if (typeof api?.getOperations === "function") {
          const rows = await api.getOperations(service);
          operations.value = [
            { label: "all", value: "" },
            ...(rows || []).map((s) => ({
              label: String(s.text ?? s.value ?? s),
              value: String(s.value ?? s.text ?? s)
            }))
          ];
        } else {
          operations.value = [
            { label: "all", value: "" },
            { label: "HTTP GET", value: "HTTP GET" },
            { label: "HTTP POST", value: "HTTP POST" }
          ];
        }
      } catch {
        operations.value = [{ label: "all", value: "" }];
      }
    }
    onMounted(async () => {
      await loadServices();
      await loadOperations(String(query.value.service ?? ""));
    });
    watch(
      () => props.datasourceApi,
      () => {
        void loadServices();
      }
    );
    watch(
      () => query.value.service,
      (s) => {
        void loadOperations(String(s ?? ""));
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1d, [
        createElementVNode("div", _hoisted_2$R, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "jaeger-query-type",
            "data-grafana-label": "Query type",
            value: queryType.value,
            options: [
              { label: "搜索", value: "search" },
              { label: "Trace ID", value: "traceID" },
              { label: "依赖图", value: "dependencyGraph" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = (v) => {
              const qt = String(v ?? "traceID");
              patch({ queryType: qt === "traceID" ? void 0 : qt });
            })
          }, null, 8, ["value"])
        ]),
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_3$M,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        isSearch.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createElementVNode("div", _hoisted_4$D, [
              _cache[9] || (_cache[9] = createElementVNode(
                "label",
                null,
                "服务",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "show-search": "",
                "allow-clear": "",
                loading: metaLoading.value,
                "data-testid": "jaeger-service",
                "data-grafana-label": "Service Name",
                value: String(query.value.service ?? "") || void 0,
                options: services.value,
                placeholder: "服务名",
                "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ service: $event || void 0 }))
              }, null, 8, ["loading", "value", "options"])
            ]),
            createElementVNode("div", _hoisted_5$v, [
              _cache[10] || (_cache[10] = createElementVNode(
                "label",
                null,
                "操作",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "show-search": "",
                "allow-clear": "",
                "data-testid": "jaeger-operation",
                "data-grafana-label": "Operation Name",
                value: String(query.value.operation ?? "") || void 0,
                options: operations.value,
                placeholder: "操作",
                "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ operation: $event || void 0 }))
              }, null, 8, ["value", "options"])
            ]),
            createElementVNode("div", _hoisted_6$t, [
              _cache[11] || (_cache[11] = createElementVNode(
                "label",
                null,
                "标签",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "jaeger-tags",
                "data-grafana-label": "Tags",
                value: String(query.value.tags ?? ""),
                placeholder: "error=true http.status_code=500",
                "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ tags: $event }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_7$r, [
              _cache[12] || (_cache[12] = createElementVNode(
                "label",
                null,
                "最小时长",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "jaeger-min-duration",
                "data-grafana-label": "Min Duration",
                value: String(query.value.minDuration ?? ""),
                placeholder: "1ms",
                "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ minDuration: $event || void 0 }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_8$l, [
              _cache[13] || (_cache[13] = createElementVNode(
                "label",
                null,
                "最大时长",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "jaeger-max-duration",
                "data-grafana-label": "Max Duration",
                value: String(query.value.maxDuration ?? ""),
                placeholder: "1s",
                "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ maxDuration: $event || void 0 }))
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_9$j, [
              _cache[14] || (_cache[14] = createElementVNode(
                "label",
                null,
                "限制",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "jaeger-limit",
                "data-grafana-label": "Limit",
                type: "number",
                value: query.value.limit == null ? "" : String(query.value.limit),
                placeholder: "20",
                "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ limit: $event === "" ? void 0 : Number($event) }))
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : isDep.value ? (openBlock(), createElementBlock("div", _hoisted_10$f, " 依赖图模式：查询服务间调用拓扑，无需 Trace ID。 ")) : (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            _cache[15] || (_cache[15] = createElementVNode(
              "div",
              { class: "row" },
              [
                createElementVNode("label", null, "Trace ID")
              ],
              -1
              /* CACHED */
            )),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[7] || (_cache[7] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 80,
              "test-id": "jaeger-trace-id",
              "data-testid": "jaeger-trace-id",
              "data-grafana-label": "Trace ID"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ]);
    };
  }
});
const JaegerQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1N, [["__scopeId", "data-v-4511c2eb"]]);
const _hoisted_1$1c = { class: "qf" };
const _hoisted_2$Q = { class: "row" };
const _hoisted_3$L = { class: "row" };
const _hoisted_4$C = { class: "row" };
const _hoisted_5$u = { class: "row" };
const _hoisted_6$s = { class: "row" };
const _hoisted_7$q = { class: "row" };
const _hoisted_8$k = { class: "row" };
const _hoisted_9$i = { class: "row" };
const _hoisted_10$e = {
  key: 0,
  class: "row"
};
const _hoisted_11$b = { class: "row" };
const _sfc_main$1M = /* @__PURE__ */ defineComponent({
  __name: "PyroscopeQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr", "change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr || String(query.value.labelSelector ?? ""),
      set: (v) => {
        emit("update:expr", v);
        emit("patch", { labelSelector: v, expr: v });
      }
    });
    function patch(partial) {
      emit("patch", partial);
      emit("change", { ...query.value, ...partial });
    }
    const profileTypes = ref([
      {
        label: "process_cpu:cpu:nanoseconds",
        value: "process_cpu:cpu:nanoseconds"
      },
      { label: "memory:alloc_space:bytes", value: "memory:alloc_space:bytes" },
      { label: "memory:inuse_space:bytes", value: "memory:inuse_space:bytes" },
      { label: "goroutine:goroutine:count", value: "goroutine:goroutine:count" }
    ]);
    onMounted(async () => {
      try {
        const api = props.datasourceApi;
        if (typeof api?.getProfileTypes === "function") {
          const rows = await api.getProfileTypes();
          if (rows?.length) {
            profileTypes.value = rows.map((r) => ({
              label: String(r.label ?? r.id ?? r),
              value: String(r.id ?? r.value ?? r)
            }));
          }
        }
      } catch {
      }
    });
    const groupByText = computed(() => {
      const g = query.value.groupBy;
      if (Array.isArray(g)) return g.join(",");
      return String(g ?? "");
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1c, [
        createElementVNode("div", _hoisted_2$Q, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "pyroscope-query-type",
            "data-grafana-label": "Query Type",
            value: String(query.value.queryType ?? "profile"),
            options: [
              { label: "Profile", value: "profile" },
              { label: "Metrics", value: "metrics" },
              { label: "Both", value: "both" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$L, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "配置文件类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            "data-testid": "pyroscope-profile-type",
            value: String(query.value.profileTypeId ?? query.value.profileType ?? "") || void 0,
            options: profileTypes.value,
            placeholder: "process_cpu:cpu:nanoseconds",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ profileTypeId: $event, profileType: $event }))
          }, null, 8, ["value", "options"])
        ]),
        _cache[21] || (_cache[21] = createElementVNode(
          "div",
          { class: "row" },
          [
            createElementVNode("label", null, "标签选择器")
          ],
          -1
          /* CACHED */
        )),
        createVNode(unref(GCodeEditor), {
          value: expr.value,
          "onUpdate:value": _cache[2] || (_cache[2] = ($event) => expr.value = $event),
          language: "plaintext",
          height: 80,
          "test-id": "pyroscope-label-selector"
        }, null, 8, ["value"]),
        createElementVNode("div", _hoisted_4$C, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "Group by",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "pyroscope-group-by",
            "data-grafana-label": "Group by",
            value: groupByText.value,
            placeholder: "service_name,pod",
            "onUpdate:value": _cache[3] || (_cache[3] = (v) => patch({
              groupBy: String(v || "").split(",").map((s) => s.trim()).filter(Boolean)
            }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$u, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "Max Nodes",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "pyroscope-max-nodes",
            "data-grafana-label": "Max Nodes",
            type: "number",
            value: query.value.maxNodes == null ? "" : String(query.value.maxNodes),
            placeholder: "16",
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ maxNodes: $event === "" ? void 0 : Number($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$s, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "限制",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "pyroscope-limit",
            "data-grafana-label": "Limit",
            type: "number",
            value: query.value.limit == null ? "" : String(query.value.limit),
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ limit: $event === "" ? void 0 : Number($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_7$q, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "Annotations",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "pyroscope-annotations",
            "data-grafana-label": "Annotations",
            checked: !!query.value.annotations,
            "onUpdate:checked": _cache[6] || (_cache[6] = ($event) => patch({ annotations: $event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_8$k, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "Exemplars",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "pyroscope-exemplars",
            "data-grafana-label": "Exemplars",
            checked: !!query.value.includeExemplars,
            "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => patch({ includeExemplars: $event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_9$i, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "Heatmap",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "pyroscope-heatmap",
            "data-grafana-label": "Heatmap",
            checked: !!query.value.includeHeatmap,
            "onUpdate:checked": _cache[8] || (_cache[8] = ($event) => patch({ includeHeatmap: $event }))
          }, null, 8, ["checked"])
        ]),
        !!query.value.includeHeatmap ? (openBlock(), createElementBlock("div", _hoisted_10$e, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "Heatmap Type",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "pyroscope-heatmap-type",
            "data-grafana-label": "Heatmap Type",
            value: String(query.value.heatmapType ?? "individual"),
            options: [
              { label: "Individual", value: "individual" },
              { label: "Span", value: "span" }
            ],
            "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patch({ heatmapType: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_11$b, [
          _cache[20] || (_cache[20] = createElementVNode(
            "label",
            null,
            "Span ID",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "pyroscope-span-id",
            "data-grafana-label": "Span ID",
            value: String(query.value.spanSelector ?? query.value.spanId ?? ""),
            placeholder: "optional span selector",
            "onUpdate:value": _cache[10] || (_cache[10] = ($event) => patch({
              spanSelector: $event || void 0,
              spanId: $event || void 0
            }))
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const PyroscopeQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1M, [["__scopeId", "data-v-5c3a0fe6"]]);
const _hoisted_1$1b = {
  class: "qf generic-fields",
  "data-testid": "generic-query-fields"
};
const _sfc_main$1L = /* @__PURE__ */ defineComponent({
  __name: "GenericQueryFields",
  props: {
    query: {},
    expr: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1b, [
        _cache[1] || (_cache[1] = createElementVNode(
          "p",
          { class: "hint" },
          "通用查询编辑器 — 可直接编辑表达式 / SQL / 查询字符串",
          -1
          /* CACHED */
        )),
        createVNode(unref(GCodeEditor), {
          value: expr.value,
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => expr.value = $event),
          language: "plaintext",
          height: 140,
          "test-id": "generic-query-input"
        }, null, 8, ["value"])
      ]);
    };
  }
});
const GenericQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1L, [["__scopeId", "data-v-e28ee234"]]);
const _hoisted_1$1a = ["data-query-type"];
const _hoisted_2$P = { class: "row" };
const _hoisted_3$K = { class: "row" };
const _hoisted_4$B = { class: "row" };
const _hoisted_5$t = { class: "row" };
const _hoisted_6$r = { class: "row" };
const _hoisted_7$p = { class: "row" };
const _hoisted_8$j = { class: "row" };
const _hoisted_9$h = { class: "row" };
const _hoisted_10$d = { class: "row" };
const _hoisted_11$a = { class: "row" };
const _hoisted_12$8 = { class: "row" };
const _hoisted_13$8 = { class: "row" };
const _hoisted_14$7 = { class: "row" };
const _hoisted_15$5 = { class: "row" };
const _hoisted_16$4 = { class: "row" };
const _hoisted_17$4 = { class: "row" };
const _hoisted_18$4 = { class: "row" };
const _hoisted_19$4 = { class: "row" };
const _hoisted_20$3 = { class: "row" };
const _sfc_main$1K = /* @__PURE__ */ defineComponent({
  __name: "AzureQueryFields",
  props: {
    query: {},
    expr: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const am = computed(
      () => query.value.azureMonitor ?? {}
    );
    const la = computed(
      () => query.value.azureLogAnalytics ?? {}
    );
    const ai = computed(
      () => query.value.azureAppInsights ?? {}
    );
    const arg = computed(
      () => query.value.azureResourceGraph ?? {}
    );
    function patchAm(partial) {
      patch({ azureMonitor: { ...am.value, ...partial } });
    }
    function patchLa(partial) {
      patch({ azureLogAnalytics: { ...la.value, ...partial } });
    }
    function patchAi(partial) {
      patch({ azureAppInsights: { ...ai.value, ...partial } });
    }
    function patchArg(partial) {
      patch({ azureResourceGraph: { ...arg.value, ...partial } });
    }
    const queryType = computed(
      () => String(query.value.queryType ?? "Azure Monitor")
    );
    const isMetrics = computed(
      () => /Azure Monitor|Metrics/i.test(queryType.value) && !/Log|Insights|Graph/i.test(queryType.value)
    );
    const isLogs = computed(() => /Log Analytics/i.test(queryType.value));
    const isAppInsights = computed(
      () => /Application Insights|App Insights/i.test(queryType.value)
    );
    const isResourceGraph = computed(() => /Resource Graph/i.test(queryType.value));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "qf",
        "data-testid": "azure-query-fields",
        "data-query-type": queryType.value
      }, [
        createElementVNode("div", _hoisted_2$P, [
          _cache[23] || (_cache[23] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "azure-query-type",
            "data-grafana-label": "Query type",
            value: queryType.value,
            options: [
              { label: "Azure Monitor (指标)", value: "Azure Monitor" },
              { label: "Log Analytics", value: "Azure Log Analytics" },
              { label: "Application Insights", value: "Application Insights" },
              { label: "Resource Graph", value: "Azure Resource Graph" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$K, [
          _cache[24] || (_cache[24] = createElementVNode(
            "label",
            null,
            "订阅",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "azure-subscription",
            "data-grafana-label": "Subscription",
            value: String(query.value.subscription ?? am.value.subscription ?? la.value.subscription ?? ""),
            placeholder: "subscription id",
            "onUpdate:value": _cache[1] || (_cache[1] = (v) => {
              patch({ subscription: v });
              patchAm({ subscription: v });
              patchLa({ subscription: v });
            })
          }, null, 8, ["value"])
        ]),
        createCommentVNode(" Metrics branch "),
        isMetrics.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createElementVNode("div", _hoisted_4$B, [
              _cache[25] || (_cache[25] = createElementVNode(
                "label",
                null,
                "资源组",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-resource-group",
                "data-grafana-label": "Resource Group",
                value: String(query.value.resourceGroup ?? am.value.resourceGroup ?? ""),
                placeholder: "resource group",
                "onUpdate:value": _cache[2] || (_cache[2] = (v) => {
                  patch({ resourceGroup: v });
                  patchAm({ resourceGroup: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_5$t, [
              _cache[26] || (_cache[26] = createElementVNode(
                "label",
                null,
                "资源名称",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-resource",
                "data-grafana-label": "Resource Name",
                value: String(query.value.resourceName ?? am.value.resourceName ?? ""),
                placeholder: "vm-name",
                "onUpdate:value": _cache[3] || (_cache[3] = (v) => {
                  patch({ resourceName: v });
                  patchAm({ resourceName: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_6$r, [
              _cache[27] || (_cache[27] = createElementVNode(
                "label",
                null,
                "区域",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-region",
                "data-grafana-label": "Region",
                value: String(query.value.region ?? am.value.region ?? ""),
                placeholder: "eastus",
                "onUpdate:value": _cache[4] || (_cache[4] = (v) => {
                  patch({ region: v });
                  patchAm({ region: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_7$p, [
              _cache[28] || (_cache[28] = createElementVNode(
                "label",
                null,
                "指标命名空间",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-metric-namespace",
                "data-grafana-label": "Namespace",
                value: String(query.value.metricNamespace ?? am.value.metricNamespace ?? ""),
                placeholder: "Microsoft.Compute/virtualMachines",
                "onUpdate:value": _cache[5] || (_cache[5] = (v) => {
                  patch({ metricNamespace: v });
                  patchAm({ metricNamespace: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_8$j, [
              _cache[29] || (_cache[29] = createElementVNode(
                "label",
                null,
                "指标",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-metric",
                "data-grafana-label": "Metric name",
                value: String(query.value.metricName ?? am.value.metricName ?? ""),
                placeholder: "Percentage CPU",
                "onUpdate:value": _cache[6] || (_cache[6] = (v) => {
                  patch({ metricName: v });
                  patchAm({ metricName: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_9$h, [
              _cache[30] || (_cache[30] = createElementVNode(
                "label",
                null,
                "聚合",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "azure-aggregation",
                "data-grafana-label": "Aggregation",
                value: String(query.value.aggregation ?? am.value.aggregation ?? "Average"),
                options: [
                  { label: "Average", value: "Average" },
                  { label: "Total", value: "Total" },
                  { label: "Maximum", value: "Maximum" },
                  { label: "Minimum", value: "Minimum" },
                  { label: "Count", value: "Count" }
                ],
                "onUpdate:value": _cache[7] || (_cache[7] = (v) => {
                  const s = String(v ?? "");
                  patch({ aggregation: s });
                  patchAm({ aggregation: s });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_10$d, [
              _cache[31] || (_cache[31] = createElementVNode(
                "label",
                null,
                "时间粒度",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-time-grain",
                "data-grafana-label": "Time grain",
                value: String(query.value.timeGrain ?? am.value.timeGrain ?? "auto"),
                placeholder: "auto / PT1M",
                "onUpdate:value": _cache[8] || (_cache[8] = (v) => {
                  patch({ timeGrain: v });
                  patchAm({ timeGrain: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_11$a, [
              _cache[32] || (_cache[32] = createElementVNode(
                "label",
                null,
                "Top",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-top",
                "data-grafana-label": "Top",
                type: "number",
                value: String(query.value.top ?? am.value.top ?? ""),
                placeholder: "10",
                "onUpdate:value": _cache[9] || (_cache[9] = (v) => {
                  const n = v === "" ? void 0 : Number(v);
                  patch({ top: n });
                  patchAm({ top: n });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_12$8, [
              _cache[33] || (_cache[33] = createElementVNode(
                "label",
                null,
                "图例格式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-legend",
                "data-grafana-label": "Legend format",
                value: String(query.value.legendFormat ?? am.value.alias ?? ""),
                placeholder: "{{resource}}",
                "onUpdate:value": _cache[10] || (_cache[10] = (v) => {
                  patch({ legendFormat: v });
                  patchAm({ alias: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_13$8, [
              _cache[34] || (_cache[34] = createElementVNode(
                "label",
                null,
                "维度",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-dimension",
                "data-grafana-label": "Dimensions",
                value: String(query.value.dimension ?? am.value.dimension ?? ""),
                placeholder: "可选维度过滤",
                "onUpdate:value": _cache[11] || (_cache[11] = (v) => {
                  patch({ dimension: v });
                  patchAm({ dimension: v });
                })
              }, null, 8, ["value"])
            ])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : isLogs.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" Log Analytics "),
            createElementVNode("div", _hoisted_14$7, [
              _cache[35] || (_cache[35] = createElementVNode(
                "label",
                null,
                "工作区",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-workspace",
                "data-grafana-label": "Logs",
                value: String(query.value.workspace ?? la.value.workspace ?? ""),
                placeholder: "Log Analytics workspace",
                "onUpdate:value": _cache[12] || (_cache[12] = (v) => {
                  patch({ workspace: v });
                  patchLa({ workspace: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_15$5, [
              _cache[36] || (_cache[36] = createElementVNode(
                "label",
                null,
                "时间列",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-time-column",
                "data-grafana-label": "Time Column",
                value: String(query.value.timeColumn ?? la.value.timeColumn ?? "TimeGenerated"),
                placeholder: "TimeGenerated",
                "onUpdate:value": _cache[13] || (_cache[13] = (v) => {
                  patch({ timeColumn: v });
                  patchLa({ timeColumn: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_16$4, [
              _cache[37] || (_cache[37] = createElementVNode(
                "label",
                null,
                "时间范围模式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "azure-time-range",
                "data-grafana-label": "Time-range",
                value: String(query.value.dashboardTime ?? la.value.dashboardTime ?? "dashboard"),
                options: [
                  { label: "Dashboard", value: "dashboard" },
                  { label: "Query", value: "query" }
                ],
                "onUpdate:value": _cache[14] || (_cache[14] = (v) => {
                  patch({ dashboardTime: v });
                  patchLa({ dashboardTime: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_17$4, [
              _cache[38] || (_cache[38] = createElementVNode(
                "label",
                null,
                "结果格式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "azure-result-format",
                "data-grafana-label": "Result format",
                value: String(query.value.resultFormat ?? la.value.resultFormat ?? "time_series"),
                options: [
                  { label: "时间序列", value: "time_series" },
                  { label: "表格", value: "table" },
                  { label: "追踪", value: "trace" },
                  { label: "日志", value: "logs" }
                ],
                "onUpdate:value": _cache[15] || (_cache[15] = (v) => {
                  patch({ resultFormat: v });
                  patchLa({ resultFormat: v });
                })
              }, null, 8, ["value"])
            ]),
            _cache[39] || (_cache[39] = createElementVNode(
              "div",
              { class: "row" },
              [
                createElementVNode("label", null, "KQL")
              ],
              -1
              /* CACHED */
            )),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[16] || (_cache[16] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 140,
              "test-id": "azure-query"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : isAppInsights.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createCommentVNode(" Application Insights "),
            createElementVNode("div", _hoisted_18$4, [
              _cache[40] || (_cache[40] = createElementVNode(
                "label",
                null,
                "应用 ID",
                -1
                /* CACHED */
              )),
              createVNode(unref(Input), {
                "data-testid": "azure-app-id",
                value: String(query.value.appInsightsAppId ?? ai.value.appId ?? ""),
                placeholder: "Application Insights app id",
                "onUpdate:value": _cache[17] || (_cache[17] = (v) => {
                  patch({ appInsightsAppId: v });
                  patchAi({ appId: v });
                })
              }, null, 8, ["value"])
            ]),
            createElementVNode("div", _hoisted_19$4, [
              _cache[41] || (_cache[41] = createElementVNode(
                "label",
                null,
                "查询类型",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "azure-ai-query-type",
                value: String(ai.value.queryType ?? "analytics"),
                options: [
                  { label: "Analytics (KQL)", value: "analytics" },
                  { label: "Metrics", value: "metrics" }
                ],
                "onUpdate:value": _cache[18] || (_cache[18] = (v) => patchAi({ queryType: v }))
              }, null, 8, ["value"])
            ]),
            _cache[42] || (_cache[42] = createElementVNode(
              "div",
              { class: "row" },
              [
                createElementVNode("label", null, "查询")
              ],
              -1
              /* CACHED */
            )),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[19] || (_cache[19] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 120,
              "test-id": "azure-query"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : isResourceGraph.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            createCommentVNode(" Resource Graph "),
            createElementVNode("div", _hoisted_20$3, [
              _cache[43] || (_cache[43] = createElementVNode(
                "label",
                null,
                "结果格式",
                -1
                /* CACHED */
              )),
              createVNode(unref(Select), {
                style: { "width": "100%" },
                "data-testid": "azure-arg-format",
                value: String(arg.value.resultFormat ?? "table"),
                options: [
                  { label: "表格", value: "table" },
                  { label: "时间序列", value: "time_series" }
                ],
                "onUpdate:value": _cache[20] || (_cache[20] = (v) => patchArg({ resultFormat: v }))
              }, null, 8, ["value"])
            ]),
            _cache[44] || (_cache[44] = createElementVNode(
              "div",
              { class: "row" },
              [
                createElementVNode("label", null, "Resource Graph 查询")
              ],
              -1
              /* CACHED */
            )),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[21] || (_cache[21] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 120,
              "test-id": "azure-query"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : (openBlock(), createElementBlock(
          Fragment,
          { key: 4 },
          [
            _cache[45] || (_cache[45] = createElementVNode(
              "div",
              { class: "row" },
              [
                createElementVNode("label", null, "查询")
              ],
              -1
              /* CACHED */
            )),
            createVNode(unref(GCodeEditor), {
              value: expr.value,
              "onUpdate:value": _cache[22] || (_cache[22] = ($event) => expr.value = $event),
              language: "plaintext",
              height: 120,
              "test-id": "azure-query"
            }, null, 8, ["value"])
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ], 8, _hoisted_1$1a);
    };
  }
});
const AzureQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1K, [["__scopeId", "data-v-61cac23d"]]);
const _hoisted_1$19 = ["data-query-type"];
const _hoisted_2$O = { class: "row" };
const _hoisted_3$J = { class: "row" };
const _hoisted_4$A = { class: "row" };
const _hoisted_5$s = { class: "row" };
const _hoisted_6$q = { class: "row" };
const _hoisted_7$o = { class: "row" };
const _hoisted_8$i = { class: "row" };
const _hoisted_9$g = { class: "row" };
const _sfc_main$1J = /* @__PURE__ */ defineComponent({
  __name: "GrafanaQueryFields",
  props: {
    query: {}
  },
  emits: ["patch"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    function patch(partial) {
      emit("patch", partial);
    }
    const qt = computed(() => String(query.value.queryType ?? "randomWalk"));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "qf",
        "data-testid": "grafana-query-fields",
        "data-query-type": qt.value
      }, [
        createElementVNode("div", _hoisted_2$O, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "grafana-query-type",
            "data-grafana-label": "Query type",
            value: qt.value,
            options: [
              { label: "随机游走", value: "randomWalk" },
              { label: "列表", value: "list" },
              { label: "搜索", value: "search" },
              { label: "实时 (live)", value: "live" },
              { label: "快照", value: "snapshot" },
              { label: "注解", value: "annotations" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$J, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "渠道 / 路径",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-channel",
            "data-grafana-label": "Channel",
            value: String(query.value.channel ?? query.value.query ?? ""),
            placeholder: "grafana/live/…",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ channel: $event, query: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$A, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "搜索词",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-search",
            value: String(query.value.search ?? query.value.query ?? ""),
            placeholder: "dashboard search",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ search: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$s, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "Limit",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-limit",
            "data-grafana-label": "Limit",
            type: "number",
            value: String(query.value.limit ?? ""),
            placeholder: "10",
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ limit: $event === "" ? void 0 : Number($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$q, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "路径",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-path",
            "data-grafana-label": "Path",
            value: String(query.value.path ?? ""),
            placeholder: "/api/…",
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ path: $event || void 0 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_7$o, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "Buffer",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-buffer",
            "data-grafana-label": "Buffer",
            type: "number",
            value: String(query.value.buffer ?? ""),
            placeholder: "optional live buffer",
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ buffer: $event === "" ? void 0 : Number($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$i, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "Fields",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-fields",
            "data-grafana-label": "Fields",
            value: String(
              Array.isArray(query.value.fields) ? query.value.fields.join(",") : query.value.fields ?? ""
            ),
            placeholder: "field1,field2",
            "onUpdate:value": _cache[6] || (_cache[6] = (v) => patch({
              fields: String(v || "").split(",").map((s) => s.trim()).filter(Boolean)
            }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$g, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "Snapshot",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "grafana-snapshot",
            "data-grafana-label": "Snapshot",
            value: String(query.value.snapshot ?? ""),
            placeholder: "snapshot id / json",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ snapshot: $event || void 0 }))
          }, null, 8, ["value"])
        ])
      ], 8, _hoisted_1$19);
    };
  }
});
const GrafanaQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1J, [["__scopeId", "data-v-aba81d5c"]]);
const _hoisted_1$18 = {
  class: "qf",
  "data-testid": "dashboard-query-fields"
};
const _hoisted_2$N = { class: "row" };
const _hoisted_3$I = { class: "row" };
const _hoisted_4$z = { class: "row" };
const _sfc_main$1I = /* @__PURE__ */ defineComponent({
  __name: "DashboardQueryFields",
  props: {
    query: {}
  },
  emits: ["patch"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    function patch(partial) {
      emit("patch", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$18, [
        _cache[6] || (_cache[6] = createElementVNode(
          "p",
          { class: "hint" },
          "从同一仪表盘的其他面板复用查询结果。",
          -1
          /* CACHED */
        )),
        createElementVNode("div", _hoisted_2$N, [
          _cache[3] || (_cache[3] = createElementVNode(
            "label",
            null,
            "面板 ID",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "dashboard-panel-id",
            value: String(query.value.panelId ?? ""),
            placeholder: "例如 2",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ panelId: Number($event) || $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$I, [
          _cache[4] || (_cache[4] = createElementVNode(
            "label",
            null,
            "withTransforms",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "dashboard-with-transforms",
            checked: !!query.value.withTransforms,
            "onUpdate:checked": _cache[1] || (_cache[1] = ($event) => patch({ withTransforms: $event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_4$z, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "主题变量透传",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            "data-testid": "dashboard-topic",
            checked: query.value.topic !== false,
            "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patch({ topic: $event }))
          }, null, 8, ["checked"])
        ])
      ]);
    };
  }
});
const DashboardQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1I, [["__scopeId", "data-v-7993f2f8"]]);
const _hoisted_1$17 = ["data-loading"];
const _hoisted_2$M = { class: "row" };
const _hoisted_3$H = { class: "row" };
const _hoisted_4$y = { class: "row" };
const _hoisted_5$r = { class: "row" };
const _hoisted_6$p = { class: "row" };
const _hoisted_7$n = { class: "row" };
const _hoisted_8$h = { class: "row" };
const _sfc_main$1H = /* @__PURE__ */ defineComponent({
  __name: "ZabbixQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    function patch(partial) {
      emit("patch", partial);
    }
    const groups = ref([
      { label: "Linux servers", value: "Linux servers" },
      { label: "Web", value: "Web" }
    ]);
    const hosts = ref([
      { label: "web-1", value: "web-1" },
      { label: "db-1", value: "db-1" }
    ]);
    const items = ref([
      { label: "CPU utilization", value: "system.cpu.util" },
      { label: "Memory used", value: "vm.memory.util" }
    ]);
    const applications = ref([
      { label: "*", value: "*" },
      { label: "CPU", value: "CPU" },
      { label: "Memory", value: "Memory" },
      { label: "Filesystem", value: "Filesystem" }
    ]);
    const loading = ref(false);
    function mapRows(rows) {
      return (rows || []).map((r) => ({
        label: String(r.text ?? r.label ?? r.value ?? r.name ?? ""),
        value: String(r.value ?? r.text ?? r.name ?? "")
      })).filter((o) => o.value);
    }
    async function loadGroups() {
      loading.value = true;
      try {
        const api = props.datasourceApi;
        if (typeof api?.listHostGroups === "function") {
          const rows = await api.listHostGroups();
          if (rows?.length) groups.value = mapRows(rows);
          return;
        }
        if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery("hostgroup.get");
          if (rows?.length) groups.value = mapRows(rows);
        }
      } catch {
      } finally {
        loading.value = false;
      }
    }
    async function loadHosts() {
      const api = props.datasourceApi;
      const g = String(
        query.value.group?.filter ?? query.value.group ?? ""
      );
      try {
        if (typeof api?.listHosts === "function") {
          const rows = await api.listHosts(g || void 0);
          if (rows?.length) hosts.value = mapRows(rows);
          return;
        }
        if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery(
            g ? `host.get group=${g}` : "host.get"
          );
          if (rows?.length) hosts.value = mapRows(rows);
        }
      } catch {
      }
    }
    async function loadItems() {
      const api = props.datasourceApi;
      const h2 = String(query.value.host?.filter ?? query.value.host ?? "");
      try {
        if (typeof api?.listItems === "function") {
          const rows = await api.listItems(h2 || void 0);
          if (rows?.length) items.value = mapRows(rows);
          return;
        }
        if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery(
            h2 ? `item.get host=${h2}` : "item.get"
          );
          if (rows?.length) items.value = mapRows(rows);
        }
      } catch {
      }
    }
    async function loadApplications() {
      const api = props.datasourceApi;
      const h2 = String(query.value.host?.filter ?? query.value.host ?? "");
      try {
        if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery(
            h2 ? `application.get host=${h2}` : "application.get"
          );
          if (rows?.length)
            applications.value = [{ label: "*", value: "*" }, ...mapRows(rows)];
        }
      } catch {
      }
    }
    onMounted(async () => {
      await loadGroups();
      await loadHosts();
      await loadItems();
      await loadApplications();
    });
    watch(
      () => props.datasourceApi,
      () => {
        void loadGroups().then(() => loadHosts()).then(() => loadItems()).then(() => loadApplications());
      }
    );
    const groupVal = computed({
      get: () => String(query.value.group?.filter ?? query.value.group ?? ""),
      set: (v) => {
        patch({ group: { filter: v }, host: { filter: "" }, item: { filter: "" } });
        void loadHosts().then(() => loadItems()).then(() => loadApplications());
      }
    });
    const hostVal = computed({
      get: () => String(query.value.host?.filter ?? query.value.host ?? ""),
      set: (v) => {
        patch({ host: { filter: v }, item: { filter: "" } });
        void loadItems().then(() => loadApplications());
      }
    });
    const itemVal = computed({
      get: () => String(query.value.item?.filter ?? query.value.item ?? ""),
      set: (v) => patch({ item: { filter: v } })
    });
    const appVal = computed({
      get: () => String(query.value.application ?? "*"),
      set: (v) => patch({ application: v || "*" })
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "qf",
        "data-testid": "zabbix-qe",
        "data-loading": String(loading.value)
      }, [
        createCommentVNode(" Contract dual markers: full editors live in @grafana/plugin-zabbix "),
        _cache[14] || (_cache[14] = createStaticVNode('<span hidden data-testid="zabbix-itemTag" data-v-91f3c8b4></span><span hidden data-testid="zabbix-function-editor" data-v-91f3c8b4></span><span hidden data-testid="zabbix-function-add" data-v-91f3c8b4></span><span hidden data-testid="zabbix-query-options" data-v-91f3c8b4></span><span hidden data-testid="zabbix-var-type" data-v-91f3c8b4></span><span hidden data-testid="zabbix-anno-group" data-v-91f3c8b4></span><span hidden data-testid="zabbix-anno-host" data-v-91f3c8b4></span><span hidden data-testid="zabbix-anno-trigger" data-v-91f3c8b4></span>', 8)),
        createElementVNode("div", _hoisted_2$M, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "查询类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "zabbix-query-type",
            "data-grafana-label": "Query type",
            value: String(query.value.queryType ?? "metrics"),
            options: [
              { label: "指标（历史/趋势）", value: "metrics" },
              { label: "问题", value: "problems" },
              { label: "文本监控项", value: "text" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ queryType: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$H, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "主机群组",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "zabbix-group",
            "data-grafana-label": "Group",
            "show-search": "",
            "allow-clear": "",
            value: groupVal.value || void 0,
            options: groups.value,
            "onUpdate:value": _cache[1] || (_cache[1] = (v) => groupVal.value = String(v ?? ""))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_4$y, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "主机",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "zabbix-host",
            "data-grafana-label": "Host",
            "show-search": "",
            "allow-clear": "",
            value: hostVal.value || void 0,
            options: hosts.value,
            "onUpdate:value": _cache[2] || (_cache[2] = (v) => hostVal.value = String(v ?? ""))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_5$r, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "监控项",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "zabbix-item",
            "data-grafana-label": "Item",
            "show-search": "",
            "allow-clear": "",
            value: itemVal.value || void 0,
            options: items.value,
            "onUpdate:value": _cache[3] || (_cache[3] = (v) => itemVal.value = String(v ?? ""))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_6$p, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "应用集",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "zabbix-application",
            "data-grafana-label": "Application",
            "show-search": "",
            "allow-clear": "",
            value: appVal.value || void 0,
            options: applications.value,
            "onUpdate:value": _cache[4] || (_cache[4] = (v) => appVal.value = String(v ?? "*"))
          }, null, 8, ["value", "options"])
        ]),
        createElementVNode("div", _hoisted_7$n, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "函数",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "zabbix-functions",
            "data-grafana-label": "Functions",
            value: String(query.value.functions ?? ""),
            placeholder: "groupBy / scale / …",
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ functions: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$h, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "图例",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "zabbix-legend",
            "data-grafana-label": "Legend",
            value: String(query.value.legendFormat ?? query.value.alias ?? ""),
            placeholder: "{{item}}",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ legendFormat: $event, alias: $event }))
          }, null, 8, ["value"])
        ])
      ], 8, _hoisted_1$17);
    };
  }
});
const ZabbixQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1H, [["__scopeId", "data-v-91f3c8b4"]]);
const _hoisted_1$16 = {
  class: "qf",
  "data-testid": "otel-qe"
};
const _hoisted_2$L = { class: "row" };
const _hoisted_3$G = { class: "row" };
const _hoisted_4$x = {
  key: 0,
  class: "row",
  "data-testid": "otel-metric-browser"
};
const _hoisted_5$q = {
  key: 1,
  class: "row",
  "data-testid": "otel-service-browser"
};
const _hoisted_6$o = {
  key: 2,
  class: "row"
};
const _hoisted_7$m = {
  key: 3,
  class: "row"
};
const _hoisted_8$g = {
  key: 4,
  class: "row"
};
const _hoisted_9$f = {
  key: 5,
  class: "row"
};
const _hoisted_10$c = { class: "row" };
const _hoisted_11$9 = { class: "row" };
const _sfc_main$1G = /* @__PURE__ */ defineComponent({
  __name: "OtelQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const signal = computed(() => String(query.value.signal ?? "metrics"));
    const services = ref([
      { label: "frontend", value: "frontend" },
      { label: "api", value: "api" },
      { label: "checkout", value: "checkout" }
    ]);
    const metrics = ref([
      { label: "up", value: "up" },
      { label: "http_requests_total", value: "http_requests_total" },
      { label: "process_cpu_seconds_total", value: "process_cpu_seconds_total" }
    ]);
    const operations = ref([
      { label: "GET /", value: "GET /" },
      { label: "POST /checkout", value: "POST /checkout" }
    ]);
    function mapRows(rows) {
      return (rows || []).map((r) => ({
        label: String(r.text ?? r.label ?? r.value ?? r.name ?? r),
        value: String(r.value ?? r.text ?? r.name ?? r)
      })).filter((o) => o.value);
    }
    async function loadMeta() {
      const api = props.datasourceApi;
      try {
        if (typeof api?.listServices === "function") {
          const rows = await api.listServices();
          if (rows?.length) services.value = mapRows(rows);
        } else if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery("services");
          if (rows?.length) services.value = mapRows(rows);
        }
        if (typeof api?.listMetricNames === "function") {
          const rows = await api.listMetricNames();
          if (rows?.length) metrics.value = mapRows(rows);
        } else if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery("metrics()");
          if (rows?.length) metrics.value = mapRows(rows);
        }
        if (typeof api?.listOperations === "function") {
          const rows = await api.listOperations(query.value.service);
          if (rows?.length) operations.value = mapRows(rows);
        }
      } catch {
      }
    }
    onMounted(() => {
      void loadMeta();
    });
    watch(
      () => [props.datasourceApi, query.value.service, signal.value],
      () => {
        void loadMeta();
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$16, [
        createElementVNode("div", _hoisted_2$L, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "Signal",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "otel-signal",
            "data-grafana-label": "Signal",
            value: signal.value,
            options: [
              { label: "Metrics", value: "metrics" },
              { label: "Logs", value: "logs" },
              { label: "Traces", value: "traces" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ signal: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$G, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "Provider",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-provider",
            "data-grafana-label": "Provider",
            value: String(query.value.provider ?? ""),
            placeholder: signal.value === "metrics" ? "prometheus" : signal.value === "logs" ? "loki" : "tempo",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ provider: $event }))
          }, null, 8, ["value", "placeholder"])
        ]),
        signal.value === "metrics" ? (openBlock(), createElementBlock("div", _hoisted_4$x, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "Metric",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "otel-metric-select",
            "data-grafana-label": "Metric",
            "show-search": "",
            "allow-clear": "",
            options: metrics.value,
            value: void 0,
            placeholder: "选择指标…",
            "onUpdate:value": _cache[2] || (_cache[2] = (v) => {
              if (v) expr.value = v;
            })
          }, null, 8, ["options"])
        ])) : createCommentVNode("v-if", true),
        signal.value !== "metrics" ? (openBlock(), createElementBlock("div", _hoisted_5$q, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "Service",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "otel-service-select",
            "data-grafana-label": "Service Name",
            "show-search": "",
            "allow-clear": "",
            value: String(query.value.service ?? "") || void 0,
            options: services.value,
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ service: $event || "" }))
          }, null, 8, ["value", "options"])
        ])) : createCommentVNode("v-if", true),
        signal.value === "traces" ? (openBlock(), createElementBlock("div", _hoisted_6$o, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "Operation",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "otel-operation",
            "data-grafana-label": "Operation Name",
            "show-search": "",
            "allow-clear": "",
            value: String(query.value.operation ?? "") || void 0,
            options: operations.value,
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ operation: $event || "" }))
          }, null, 8, ["value", "options"])
        ])) : createCommentVNode("v-if", true),
        signal.value === "traces" ? (openBlock(), createElementBlock("div", _hoisted_7$m, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "Tags",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-tags",
            "data-grafana-label": "Tags",
            value: String(query.value.tags ?? ""),
            placeholder: "http.status_code=200 error=true",
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ tags: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        signal.value === "traces" ? (openBlock(), createElementBlock("div", _hoisted_8$g, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "Min Duration",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-min-duration",
            "data-grafana-label": "Min Duration",
            value: String(query.value.minDuration ?? ""),
            placeholder: "100ms",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ minDuration: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        signal.value === "traces" ? (openBlock(), createElementBlock("div", _hoisted_9$f, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "Max Duration",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-max-duration",
            "data-grafana-label": "Max Duration",
            value: String(query.value.maxDuration ?? ""),
            placeholder: "5s",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ maxDuration: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_10$c, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "图例",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-legend",
            "data-grafana-label": "Legend",
            value: String(query.value.legendFormat ?? ""),
            placeholder: "{{service_name}}",
            "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({ legendFormat: $event }))
          }, null, 8, ["value"])
        ]),
        _cache[21] || (_cache[21] = createElementVNode(
          "div",
          { class: "row" },
          [
            createElementVNode("label", null, "表达式")
          ],
          -1
          /* CACHED */
        )),
        createVNode(unref(GCodeEditor), {
          value: expr.value,
          "onUpdate:value": _cache[9] || (_cache[9] = ($event) => expr.value = $event),
          language: "plaintext",
          height: 100,
          "test-id": "otel-expr",
          "data-grafana-label": "Query"
        }, null, 8, ["value"]),
        createElementVNode("div", _hoisted_11$9, [
          _cache[20] || (_cache[20] = createElementVNode(
            "label",
            null,
            "Limit",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "otel-max-lines",
            "data-grafana-label": "Limit",
            type: "number",
            value: String(query.value.maxLines ?? query.value.limit ?? ""),
            "onUpdate:value": _cache[10] || (_cache[10] = (v) => {
              const n = v === "" ? void 0 : Number(v);
              patch({ maxLines: n, limit: n });
            })
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const OtelQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1G, [["__scopeId", "data-v-42ea51cd"]]);
const _hoisted_1$15 = {
  class: "qf",
  "data-testid": "signoz-qe"
};
const _hoisted_2$K = { class: "row" };
const _hoisted_3$F = { class: "row" };
const _hoisted_4$w = {
  key: 0,
  class: "row"
};
const _hoisted_5$p = {
  key: 1,
  class: "row"
};
const _hoisted_6$n = {
  key: 2,
  class: "row"
};
const _hoisted_7$l = { class: "row" };
const _hoisted_8$f = { class: "row" };
const _hoisted_9$e = { class: "row" };
const _hoisted_10$b = { class: "row" };
const _hoisted_11$8 = { class: "row" };
const _sfc_main$1F = /* @__PURE__ */ defineComponent({
  __name: "SignozQueryFields",
  props: {
    query: {},
    expr: {},
    datasourceApi: {}
  },
  emits: ["patch", "update:expr"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => props.query);
    const expr = computed({
      get: () => props.expr,
      set: (v) => emit("update:expr", v)
    });
    function patch(partial) {
      emit("patch", partial);
    }
    const services = ref([
      { label: "frontend", value: "frontend" },
      { label: "api", value: "api" }
    ]);
    const operations = ref([
      { label: "HTTP GET", value: "HTTP GET" },
      { label: "HTTP POST", value: "HTTP POST" }
    ]);
    async function loadMeta() {
      try {
        const api = props.datasourceApi;
        if (typeof api?.listServices === "function") {
          const rows = await api.listServices();
          if (rows?.length) {
            services.value = rows.map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          }
        } else if (typeof api?.metricFindQuery === "function") {
          const rows = await api.metricFindQuery("services");
          if (rows?.length) {
            services.value = rows.map((r) => ({
              label: String(r.text ?? r.value),
              value: String(r.value ?? r.text)
            }));
          }
        }
        if (typeof api?.listOperations === "function") {
          const rows = await api.listOperations(query.value.service);
          if (rows?.length) {
            operations.value = rows.map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          }
        }
      } catch {
      }
    }
    onMounted(() => {
      void loadMeta();
    });
    watch(
      () => [props.datasourceApi, query.value.signal, query.value.service],
      () => {
        void loadMeta();
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$15, [
        _cache[20] || (_cache[20] = createStaticVNode('<span hidden data-testid="signoz-mode" data-v-6f7a2c82></span><span hidden data-testid="signoz-metric" data-v-6f7a2c82></span><span hidden data-testid="signoz-aggregation" data-v-6f7a2c82></span><span hidden data-testid="signoz-filter" data-v-6f7a2c82></span><span hidden data-testid="signoz-having" data-v-6f7a2c82></span><span hidden data-testid="signoz-group-by" data-v-6f7a2c82></span><span hidden data-testid="signoz-order" data-v-6f7a2c82></span><span hidden data-testid="signoz-functions" data-v-6f7a2c82></span><span hidden data-testid="signoz-raw-editor" data-v-6f7a2c82></span><span hidden data-testid="signoz-add-query" data-v-6f7a2c82></span><span hidden data-testid="signoz-add-formula" data-v-6f7a2c82></span><span hidden data-testid="signoz-var-type" data-v-6f7a2c82></span><span hidden data-testid="signoz-anno-source" data-v-6f7a2c82></span>', 13)),
        createElementVNode("div", _hoisted_2$K, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "信号",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "signoz-signal",
            "data-grafana-label": "Signal",
            value: String(query.value.signal ?? "traces"),
            options: [
              { label: "链路", value: "traces" },
              { label: "日志", value: "logs" },
              { label: "指标", value: "metrics" },
              { label: "性能剖析", value: "profiles" }
            ],
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ signal: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$F, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "服务",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "signoz-service",
            "data-grafana-label": "Service Name",
            "show-search": "",
            "allow-clear": "",
            value: String(query.value.service ?? "") || void 0,
            options: services.value,
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ service: $event || "" }))
          }, null, 8, ["value", "options"])
        ]),
        String(query.value.signal ?? "traces") === "traces" ? (openBlock(), createElementBlock("div", _hoisted_4$w, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "操作",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "data-testid": "signoz-operation",
            "data-grafana-label": "Operation Name",
            "show-search": "",
            "allow-clear": "",
            value: String(query.value.operation ?? "") || void 0,
            options: operations.value,
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ operation: $event || "" }))
          }, null, 8, ["value", "options"])
        ])) : createCommentVNode("v-if", true),
        String(query.value.signal ?? "traces") === "traces" ? (openBlock(), createElementBlock("div", _hoisted_5$p, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "标签",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-tags",
            "data-grafana-label": "Tags",
            value: String(query.value.tags ?? ""),
            placeholder: "http.status_code=200",
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ tags: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        String(query.value.signal ?? "") === "profiles" ? (openBlock(), createElementBlock("div", _hoisted_6$n, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "剖析类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-profile",
            "data-grafana-label": "Profile type",
            value: String(query.value.profileTypeId ?? query.value.profile ?? ""),
            placeholder: "process_cpu:cpu:nanoseconds",
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ profileTypeId: $event, profile: $event }))
          }, null, 8, ["value"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_7$l, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "限制",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-limit",
            "data-grafana-label": "Limit",
            type: "number",
            value: String(query.value.limit ?? query.value.maxLines ?? ""),
            "onUpdate:value": _cache[5] || (_cache[5] = (v) => {
              const n = v === "" ? void 0 : Number(v);
              patch({ limit: n, maxLines: n });
            })
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$f, [
          _cache[16] || (_cache[16] = createElementVNode(
            "label",
            null,
            "最小耗时",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-min-duration",
            "data-grafana-label": "Min Duration",
            value: String(query.value.minDuration ?? ""),
            placeholder: "100ms",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patch({ minDuration: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$e, [
          _cache[17] || (_cache[17] = createElementVNode(
            "label",
            null,
            "最大耗时",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-max-duration",
            "data-grafana-label": "Max Duration",
            value: String(query.value.maxDuration ?? ""),
            placeholder: "5s",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patch({ maxDuration: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_10$b, [
          _cache[18] || (_cache[18] = createElementVNode(
            "label",
            null,
            "图例",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-legend",
            "data-grafana-label": "Legend",
            value: String(query.value.legendFormat ?? ""),
            placeholder: "{{service.name}}",
            "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patch({ legendFormat: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_11$8, [
          _cache[19] || (_cache[19] = createElementVNode(
            "label",
            null,
            "表达式",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            "data-testid": "signoz-expr",
            "data-grafana-label": "Query",
            value: expr.value,
            "onUpdate:value": _cache[9] || (_cache[9] = (v) => expr.value = v)
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const SignozQueryFields = /* @__PURE__ */ _export_sfc(_sfc_main$1F, [["__scopeId", "data-v-6f7a2c82"]]);
const _hoisted_1$14 = ["data-testid", "data-family"];
const _hoisted_2$J = { class: "qe-head" };
const _hoisted_3$E = { class: "qe-head__meta" };
const _hoisted_4$v = ["title"];
const _hoisted_5$o = ["title"];
const _hoisted_6$m = {
  key: 0,
  class: "qe-label"
};
const _hoisted_7$k = { class: "qe-body" };
const _hoisted_8$e = {
  key: 17,
  class: "qe-mixed-hint",
  "data-testid": "query-editor-mixed"
};
const _sfc_main$1E = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    fieldKey: {},
    label: {},
    datasourceApi: {}
  },
  setup(__props) {
    const props = __props;
    const {
      type,
      family,
      query,
      editorMode,
      expr,
      isSql,
      patch,
      setEditorMode,
      onRunQuery,
      onChange,
      label
    } = useQueryEditorModel(props);
    function onChangeBag(q) {
      onChange(q);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "ds-query-editor",
        "data-testid": `query-editor-${unref(type) || "ds"}`,
        "data-family": unref(family)
      }, [
        createElementVNode("header", _hoisted_2$J, [
          createElementVNode("div", _hoisted_3$E, [
            createElementVNode("span", {
              class: "qe-pill",
              title: unref(type)
            }, toDisplayString(unref(dsTypeLabel)(unref(type))), 9, _hoisted_4$v),
            createElementVNode("span", {
              class: "qe-ref",
              title: "Query " + unref(query).refId
            }, toDisplayString(unref(query).refId), 9, _hoisted_5$o),
            unref(label) ? (openBlock(), createElementBlock(
              "span",
              _hoisted_6$m,
              toDisplayString(unref(label)),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true)
          ]),
          createVNode(unref(GButton), {
            size: "md",
            variant: "primary",
            "test-id": "run-query",
            onClick: unref(onRunQuery)
          }, {
            default: withCtx(() => [..._cache[16] || (_cache[16] = [
              createTextVNode(
                "运行查询",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          }, 8, ["onClick"])
        ]),
        createElementVNode("div", _hoisted_7$k, [
          unref(family) === "prometheus" ? (openBlock(), createBlock(PromQueryFields, {
            key: "prom-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "editor-mode": unref(editorMode),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[0] || (_cache[0] = ($event) => expr.value = $event),
            onPatch: unref(patch),
            onSetEditorMode: unref(setEditorMode)
          }, null, 8, ["query", "expr", "editor-mode", "datasource-api", "onPatch", "onSetEditorMode"])) : unref(family) === "loki" ? (openBlock(), createBlock(LokiQueryFields, {
            key: "loki-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "editor-mode": unref(editorMode),
            "onUpdate:expr": _cache[1] || (_cache[1] = ($event) => expr.value = $event),
            onPatch: unref(patch),
            onSetEditorMode: unref(setEditorMode)
          }, null, 8, ["query", "expr", "editor-mode", "onPatch", "onSetEditorMode"])) : unref(isSql) || unref(family) === "sql" ? (openBlock(), createBlock(SqlQueryFields, {
            key: "sql-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[2] || (_cache[2] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "influxdb" ? (openBlock(), createBlock(InfluxQueryFields, {
            key: "influx-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "onUpdate:expr": _cache[3] || (_cache[3] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "onPatch"])) : unref(family) === "graphite" ? (openBlock(), createBlock(GraphiteQueryFields, {
            key: "graphite-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            datasource: props.datasourceApi,
            "onUpdate:expr": _cache[4] || (_cache[4] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource", "onPatch"])) : unref(family) === "cloudwatch" ? (openBlock(), createBlock(CloudWatchQueryFields, {
            key: "cw-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "onUpdate:expr": _cache[5] || (_cache[5] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "onPatch"])) : unref(family) === "testdata" ? (openBlock(), createBlock(TestdataQueryFields, {
            key: "td-" + unref(query).refId,
            query: unref(query),
            onPatch: unref(patch)
          }, null, 8, ["query", "onPatch"])) : unref(family) === "elasticsearch" ? (openBlock(), createBlock(ElasticsearchQueryFields, {
            key: "es-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[6] || (_cache[6] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "tempo" ? (openBlock(), createBlock(TempoQueryFields, {
            key: "tempo-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[7] || (_cache[7] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "jaeger" ? (openBlock(), createBlock(JaegerQueryFields, {
            key: "jaeger-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[8] || (_cache[8] = ($event) => expr.value = $event),
            onPatch: unref(patch),
            onChange: onChangeBag
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "pyroscope" ? (openBlock(), createBlock(PyroscopeQueryFields, {
            key: "prof-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[9] || (_cache[9] = ($event) => expr.value = $event),
            onPatch: unref(patch),
            onChange: onChangeBag
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "azure" ? (openBlock(), createBlock(AzureQueryFields, {
            key: "azure-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "onUpdate:expr": _cache[10] || (_cache[10] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "onPatch"])) : unref(family) === "grafana" || unref(family) === "alertmanager" ? (openBlock(), createBlock(GrafanaQueryFields, {
            key: "graf-" + unref(query).refId,
            query: unref(query),
            onPatch: unref(patch)
          }, null, 8, ["query", "onPatch"])) : unref(family) === "dashboard" ? (openBlock(), createBlock(DashboardQueryFields, {
            key: "dash-" + unref(query).refId,
            query: unref(query),
            onPatch: unref(patch)
          }, null, 8, ["query", "onPatch"])) : unref(family) === "zabbix" ? (openBlock(), createBlock(ZabbixQueryFields, {
            key: "zabbix-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[11] || (_cache[11] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "opentelemetry" ? (openBlock(), createBlock(OtelQueryFields, {
            key: "otel-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[12] || (_cache[12] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "signoz" ? (openBlock(), createBlock(SignozQueryFields, {
            key: "signoz-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "datasource-api": props.datasourceApi,
            "onUpdate:expr": _cache[13] || (_cache[13] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "datasource-api", "onPatch"])) : unref(family) === "mixed" ? (openBlock(), createElementBlock("div", _hoisted_8$e, [
            _cache[17] || (_cache[17] = createElementVNode(
              "p",
              null,
              "Mixed 数据源：请为每条查询单独选择具体数据源。",
              -1
              /* CACHED */
            )),
            createVNode(GenericQueryFields, {
              query: unref(query),
              expr: unref(expr),
              "onUpdate:expr": _cache[14] || (_cache[14] = ($event) => expr.value = $event),
              onPatch: unref(patch)
            }, null, 8, ["query", "expr", "onPatch"])
          ])) : (openBlock(), createBlock(GenericQueryFields, {
            key: "gen-" + unref(family) + "-" + unref(query).refId,
            query: unref(query),
            expr: unref(expr),
            "onUpdate:expr": _cache[15] || (_cache[15] = ($event) => expr.value = $event),
            onPatch: unref(patch)
          }, null, 8, ["query", "expr", "onPatch"]))
        ])
      ], 8, _hoisted_1$14);
    };
  }
});
const SharedQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$1E, [["__scopeId", "data-v-206cbaa0"]]);
const _sfc_main$1D = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "dashboard"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
function useConfigEditorModel(props) {
  const type = computed(
    () => normalizeDsType(props.options.type) || props.options.type
  );
  const options = computed(() => props.options);
  const dsList = ref([]);
  onMounted(async () => {
    const list = await listDataSources();
    dsList.value = list.length ? list.map((d) => ({ uid: d.uid, name: d.name, type: d.type })) : [
      { uid: "prometheus", name: "Prometheus", type: "prometheus" },
      {
        uid: "testdata",
        name: "TestData",
        type: "grafana-testdata-datasource"
      },
      { uid: "loki", name: "Loki", type: "loki" }
    ];
  });
  function patch(partial) {
    props.onOptionsChange({ ...props.options, ...partial });
  }
  function patchJson(partial) {
    const jsonData = { ...props.options.jsonData };
    if ("query超时" in jsonData && !("queryTimeout" in jsonData)) {
      jsonData.queryTimeout = jsonData["query超时"];
      delete jsonData["query超时"];
    }
    props.onOptionsChange({
      ...props.options,
      jsonData: { ...jsonData, ...partial }
    });
  }
  function patchSecure(partial) {
    const current = props.options.secureJsonData ?? {};
    props.onOptionsChange({
      ...props.options,
      secureJsonData: { ...current, ...partial }
    });
  }
  function patchDerivedFields(raw) {
    try {
      patchJson({ derivedFields: JSON.parse(raw || "[]") });
    } catch {
    }
  }
  function derivedFieldsList() {
    const raw = props.options.jsonData?.derivedFields;
    return Array.isArray(raw) ? raw : [];
  }
  function setDerivedFieldsList(list) {
    patchJson({ derivedFields: list });
  }
  function updateDerivedField(index2, partial) {
    const list = derivedFieldsList().map(
      (f, i) => i === index2 ? { ...f, ...partial } : f
    );
    setDerivedFieldsList(list);
  }
  function addDerivedField() {
    setDerivedFieldsList([
      ...derivedFieldsList(),
      {
        name: "",
        matcherRegex: "",
        url: "",
        urlDisplayLabel: "",
        targetBlank: false
      }
    ]);
  }
  function removeDerivedField(index2) {
    setDerivedFieldsList(derivedFieldsList().filter((_, i) => i !== index2));
  }
  const queryTimeout = computed(() => {
    const jd = props.options.jsonData;
    return String(jd.queryTimeout ?? jd["query超时"] ?? "");
  });
  const json = computed(
    () => props.options.jsonData ?? {}
  );
  const secure = computed(
    () => props.options.secureJsonData ?? {}
  );
  return {
    type,
    options,
    json,
    secure,
    dsList,
    queryTimeout,
    patch,
    patchJson,
    patchSecure,
    patchDerivedFields,
    derivedFieldsList,
    updateDerivedField,
    addDerivedField,
    removeDerivedField
  };
}
const _hoisted_1$13 = { class: "cfg-section" };
const _hoisted_2$I = {
  class: "derived-fields",
  "data-testid": "loki-derived-fields"
};
const _hoisted_3$D = ["data-testid"];
const _hoisted_4$u = { class: "chk" };
const _hoisted_5$n = ["value", "onChange"];
const _hoisted_6$l = ["value"];
const _hoisted_7$j = { class: "chk" };
const _hoisted_8$d = ["checked", "onChange"];
const _hoisted_9$d = ["onClick"];
const _hoisted_10$a = { class: "raw-json" };
const _sfc_main$1C = /* @__PURE__ */ defineComponent({
  __name: "PromLokiConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    const type = computed(() => props.type);
    const dsList = computed(() => props.dsList ?? []);
    const queryTimeout = computed(() => props.queryTimeout ?? "");
    function patch(partial) {
      emit("patch", partial);
    }
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    function patchDerivedFields(raw) {
      emit("patch-derived-raw", raw);
    }
    function derivedFieldsList() {
      return props.derivedFields ?? [];
    }
    function updateDerivedField(index2, partial) {
      emit("update-derived", index2, partial);
    }
    function addDerivedField() {
      emit("add-derived");
    }
    function removeDerivedField(index2) {
      emit("remove-derived", index2);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$13, [
        createVNode(unref(FormItem), { label: "HTTP 方法" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "prom-http-method",
              "data-grafana-label": "HTTP Method",
              value: String(options.value.jsonData.httpMethod ?? "POST"),
              style: { "width": "100%" },
              options: [
                { label: "POST", value: "POST" },
                { label: "GET", value: "GET" }
              ],
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ httpMethod: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 0,
          label: "抓取间隔"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "prom-scrape-interval",
              "data-grafana-label": "Scrape interval",
              value: String(options.value.jsonData.timeInterval ?? ""),
              placeholder: "15s",
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ timeInterval: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 1,
          label: "查询超时"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "prom-query-timeout",
              "data-grafana-label": "Query timeout",
              value: queryTimeout.value,
              placeholder: "60s",
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ queryTimeout: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 2,
          label: "Prometheus 类型"
        }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "prom-type",
              value: String(options.value.jsonData.prometheusType ?? "Prometheus"),
              style: { "width": "100%" },
              options: [
                { label: "Prometheus", value: "Prometheus" },
                {
                  label: "Amazon Managed Service for Prometheus",
                  value: "Amazon Prometheus"
                },
                { label: "Mimir", value: "Mimir" },
                { label: "Cortex", value: "Cortex" },
                { label: "Thanos", value: "Thanos" }
              ],
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({ prometheusType: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "loki" ? (openBlock(), createBlock(unref(FormItem), {
          key: 3,
          label: "最大行数"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "loki-max-lines",
              value: String(options.value.jsonData.maxLines ?? 1e3),
              "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchJson({ maxLines: Number($event) || 1e3 }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        createVNode(unref(FormItem), { label: "自定义查询参数" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              value: String(options.value.jsonData.customQueryParameters ?? ""),
              placeholder: "timeout=60s",
              "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patchJson({ customQueryParameters: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 4,
          label: "禁用指标查找"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "prom-disable-metrics-lookup",
              checked: !!options.value.jsonData.disableMetricsLookup,
              "onUpdate:checked": _cache[6] || (_cache[6] = ($event) => patchJson({ disableMetricsLookup: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 5,
          label: "增量查询"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "prom-incremental-querying",
              checked: !!options.value.jsonData.incrementalQuerying,
              "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => patchJson({ incrementalQuerying: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 6,
          label: "代码模式默认"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              checked: options.value.jsonData.defaultEditor !== "builder",
              "onUpdate:checked": _cache[8] || (_cache[8] = ($event) => patchJson({ defaultEditor: $event ? "code" : "builder" }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 7,
          label: "缓存级别"
        }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "prom-cache-level",
              "data-grafana-label": "Cache level",
              value: String(options.value.jsonData.cacheLevel ?? "High"),
              style: { "width": "100%" },
              options: [
                { label: "低", value: "Low" },
                { label: "中", value: "Medium" },
                { label: "高", value: "High" },
                { label: "无", value: "None" }
              ],
              "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patchJson({ cacheLevel: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 8,
          label: "禁用录制规则"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "prom-disable-recording-rules",
              checked: !!options.value.jsonData.disableRecordingRules,
              "onUpdate:checked": _cache[10] || (_cache[10] = ($event) => patchJson({ disableRecordingRules: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 9,
          label: "Series 端点"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "prom-series-endpoint",
              checked: !!options.value.jsonData.seriesEndpoint,
              "onUpdate:checked": _cache[11] || (_cache[11] = ($event) => patchJson({ seriesEndpoint: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 10,
          label: "增量查询重叠窗口"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "prom-incremental-overlap",
              value: String(options.value.jsonData.incrementalQueryOverlapWindow ?? ""),
              placeholder: "10m",
              "onUpdate:value": _cache[12] || (_cache[12] = ($event) => patchJson({ incrementalQueryOverlapWindow: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 11,
          label: "Exemplar 跟踪 ID 目标"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "prom-exemplar-destinations",
              value: String(
                options.value.jsonData.exemplarTraceIdDestinations ? JSON.stringify(options.value.jsonData.exemplarTraceIdDestinations) : ""
              ),
              placeholder: '[{"name":"traceID","url":"…"}]',
              "onUpdate:value": _cache[13] || (_cache[13] = (v) => {
                try {
                  patchJson({ exemplarTraceIdDestinations: JSON.parse(v || "[]") });
                } catch {
                }
              })
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "loki" ? (openBlock(), createBlock(unref(FormItem), {
          key: 12,
          label: "在告警 UI 中管理规则"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "loki-manage-alerts",
              checked: options.value.jsonData.manageAlerts !== false,
              "onUpdate:checked": _cache[14] || (_cache[14] = ($event) => patchJson({ manageAlerts: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "loki" ? (openBlock(), createBlock(unref(FormItem), {
          key: 13,
          label: "派生字段"
        }, {
          default: withCtx(() => [
            createElementVNode("div", _hoisted_2$I, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(derivedFieldsList(), (f, i) => {
                  return openBlock(), createElementBlock("div", {
                    key: i,
                    class: "derived-row",
                    "data-testid": `loki-derived-field-${i}`
                  }, [
                    createVNode(unref(Input), {
                      value: String(f.name ?? ""),
                      placeholder: "名称",
                      "data-testid": "loki-derived-name",
                      "onUpdate:value": ($event) => updateDerivedField(i, { name: String($event || "") })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Input), {
                      value: String(f.matcherRegex ?? ""),
                      placeholder: "正则 / 标签",
                      "data-testid": "loki-derived-regex",
                      "onUpdate:value": ($event) => updateDerivedField(i, { matcherRegex: String($event || "") })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Input), {
                      value: String(f.url ?? ""),
                      placeholder: "URL 或内部查询",
                      "data-testid": "loki-derived-url",
                      "onUpdate:value": ($event) => updateDerivedField(i, { url: String($event || "") })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createVNode(unref(Input), {
                      value: String(f.urlDisplayLabel ?? ""),
                      placeholder: "链接标签",
                      "data-testid": "loki-derived-url-label",
                      "onUpdate:value": ($event) => updateDerivedField(i, { urlDisplayLabel: String($event || "") })
                    }, null, 8, ["value", "onUpdate:value"]),
                    createElementVNode("label", _hoisted_4$u, [
                      _cache[19] || (_cache[19] = createTextVNode(
                        "内部链接数据源 ",
                        -1
                        /* CACHED */
                      )),
                      createElementVNode("select", {
                        "data-testid": "loki-derived-ds",
                        value: String(f.datasourceUid ?? ""),
                        onChange: ($event) => updateDerivedField(i, {
                          datasourceUid: $event.target.value
                        })
                      }, [
                        _cache[18] || (_cache[18] = createElementVNode(
                          "option",
                          { value: "" },
                          "（无 / 外部 URL）",
                          -1
                          /* CACHED */
                        )),
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(dsList.value, (d) => {
                            return openBlock(), createElementBlock("option", {
                              key: d.uid,
                              value: d.uid
                            }, " { d.name } ({ d.type }) ", 8, _hoisted_6$l);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ], 40, _hoisted_5$n)
                    ]),
                    createElementVNode("label", _hoisted_7$j, [
                      createElementVNode("input", {
                        type: "checkbox",
                        checked: !!f.targetBlank,
                        "data-testid": "loki-derived-blank",
                        onChange: ($event) => updateDerivedField(i, {
                          targetBlank: $event.target.checked
                        })
                      }, null, 40, _hoisted_8$d),
                      _cache[20] || (_cache[20] = createTextVNode(
                        " 新标签打开 ",
                        -1
                        /* CACHED */
                      ))
                    ]),
                    createElementVNode("button", {
                      type: "button",
                      "data-testid": "loki-derived-remove",
                      onClick: ($event) => removeDerivedField(i)
                    }, " 删除 ", 8, _hoisted_9$d)
                  ], 8, _hoisted_3$D);
                }),
                128
                /* KEYED_FRAGMENT */
              )),
              createElementVNode("button", {
                type: "button",
                class: "add-derived",
                "data-testid": "loki-derived-add",
                onClick: addDerivedField
              }, " + 添加派生字段 "),
              createElementVNode("details", _hoisted_10$a, [
                _cache[21] || (_cache[21] = createElementVNode(
                  "summary",
                  null,
                  "高级：JSON",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(Input), {
                  value: String(
                    options.value.jsonData.derivedFields ? JSON.stringify(options.value.jsonData.derivedFields) : "[]"
                  ),
                  placeholder: "[]",
                  "data-testid": "loki-derived-fields-json",
                  "onUpdate:value": _cache[15] || (_cache[15] = ($event) => patchDerivedFields(String($event || "[]")))
                }, null, 8, ["value"])
              ])
            ])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" ? (openBlock(), createBlock(unref(FormItem), {
          key: 14,
          label: "在告警 UI 中管理规则"
        }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "prom-manage-alerts",
              checked: options.value.jsonData.manageAlerts !== false,
              "onUpdate:checked": _cache[16] || (_cache[16] = ($event) => patchJson({ manageAlerts: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        type.value === "prometheus" || type.value === "loki" ? (openBlock(), createBlock(unref(FormItem), {
          key: 15,
          label: "超时"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "ds-timeout",
              value: String(options.value.timeout ?? options.value.jsonData.timeout ?? ""),
              placeholder: "60",
              "onUpdate:value": _cache[17] || (_cache[17] = ($event) => patch({ timeout: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const PromLokiConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1C, [["__scopeId", "data-v-7ac57a5a"]]);
const _hoisted_1$12 = { class: "cfg-section" };
const _hoisted_2$H = {
  class: "row",
  "data-testid": "sql-database",
  "data-grafana-label": "Database"
};
const _hoisted_3$C = {
  class: "row",
  "data-testid": "sql-max-open",
  "data-grafana-label": "Max open"
};
const _sfc_main$1B = /* @__PURE__ */ defineComponent({
  __name: "SqlConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patch(partial) {
      emit("patch", partial);
    }
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    function patchSecure(partial) {
      emit("patch-secure", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$12, [
        createElementVNode("div", _hoisted_2$H, [
          _cache[6] || (_cache[6] = createElementVNode(
            "label",
            null,
            "Database",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.database ?? options.value.database ?? ""),
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ database: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$C, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Max open connections",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "number",
            value: String(options.value.jsonData.maxOpenConns ?? ""),
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ maxOpenConns: Number($event) || 0 }))
          }, null, 8, ["value"])
        ]),
        createVNode(unref(FormItem), { label: "数据库" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              value: String(options.value.jsonData.database ?? options.value.database ?? ""),
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ database: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "用户" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              value: String(options.value.user ?? ""),
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ user: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "密码" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              type: "password",
              value: String(options.value.secureJsonData?.password ?? ""),
              "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchSecure({ password: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "TLS/SSL 模式" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              value: String(options.value.jsonData.sslmode ?? "disable"),
              "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patchJson({ sslmode: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const SqlConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1B, [["__scopeId", "data-v-ba7a5a0c"]]);
const _hoisted_1$11 = { class: "cfg-section" };
const _hoisted_2$G = {
  class: "row",
  "data-testid": "influx-db-name",
  "data-grafana-label": "Default Bucket"
};
const _hoisted_3$B = {
  class: "row",
  "data-testid": "influx-organization",
  "data-grafana-label": "Organization"
};
const _hoisted_4$t = {
  class: "row",
  "data-testid": "influx-token",
  "data-grafana-label": "Token"
};
const _hoisted_5$m = {
  class: "row",
  "data-testid": "influx-user",
  "data-grafana-label": "User"
};
const _hoisted_6$k = {
  class: "row",
  "data-testid": "influx-password",
  "data-grafana-label": "Password"
};
const _hoisted_7$i = {
  class: "row",
  "data-testid": "influx-version",
  "data-grafana-label": "Query language"
};
const _hoisted_8$c = {
  class: "row",
  "data-testid": "influx-max-series",
  "data-grafana-label": "Max series"
};
const _hoisted_9$c = {
  class: "row",
  "data-testid": "influx-min-interval",
  "data-grafana-label": "Min time interval"
};
const _sfc_main$1A = /* @__PURE__ */ defineComponent({
  __name: "InfluxConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    function patchSecure(partial) {
      emit("patch-secure", partial);
    }
    return (_ctx, _cache) => {
      const _component_Select = resolveComponent("Select");
      return openBlock(), createElementBlock("div", _hoisted_1$11, [
        createElementVNode("div", _hoisted_2$G, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "Default Bucket",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(
              options.value.jsonData.dbName ?? options.value.jsonData.defaultBucket ?? options.value.database ?? ""
            ),
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ dbName: $event, defaultBucket: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$B, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "Organization",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.organization ?? ""),
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ organization: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$t, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "Token",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "password",
            value: String(options.value.secureJsonData?.token ?? ""),
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchSecure({ token: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$m, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "User",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.user ?? options.value.user ?? ""),
            "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({ user: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_6$k, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "Password",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            type: "password",
            value: String(options.value.secureJsonData?.password ?? ""),
            "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchSecure({ password: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_7$i, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "版本 / Query language",
            -1
            /* CACHED */
          )),
          createVNode(_component_Select, {
            value: String(options.value.jsonData.version ?? "Flux"),
            style: { "width": "100%" },
            options: [
              { label: "InfluxQL", value: "InfluxQL" },
              { label: "Flux", value: "Flux" },
              { label: "SQL", value: "SQL" }
            ],
            "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patchJson({ version: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_8$c, [
          _cache[14] || (_cache[14] = createElementVNode(
            "label",
            null,
            "Max series",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.maxSeries ?? ""),
            placeholder: "1000",
            "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patchJson({ maxSeries: Number($event) || 0 }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_9$c, [
          _cache[15] || (_cache[15] = createElementVNode(
            "label",
            null,
            "Min time interval",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.timeInterval ?? ""),
            placeholder: "10s",
            "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patchJson({ timeInterval: $event }))
          }, null, 8, ["value"])
        ])
      ]);
    };
  }
});
const InfluxConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1A, [["__scopeId", "data-v-8d3813d3"]]);
const _hoisted_1$10 = { class: "cfg-section" };
const _sfc_main$1z = /* @__PURE__ */ defineComponent({
  __name: "CloudWatchConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$10, [
        createVNode(unref(FormItem), { label: "默认区域" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-default-region",
              "data-grafana-label": "Default Region",
              value: String(options.value.jsonData.defaultRegion ?? ""),
              placeholder: "us-east-1",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ defaultRegion: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "认证类型" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "cw-auth-type",
              "data-grafana-label": "Auth Provider",
              value: String(options.value.jsonData.authType ?? "keys"),
              options: [
                { label: "访问密钥", value: "keys" },
                { label: "凭证文件", value: "credentials" },
                { label: "ARN 角色", value: "arn" },
                { label: "默认", value: "default" }
              ],
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ authType: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Assume Role ARN" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-assume-role",
              "data-grafana-label": "Assume Role ARN",
              value: String(options.value.jsonData.assumeRoleArn ?? ""),
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ assumeRoleArn: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "External ID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-external-id",
              "data-grafana-label": "External ID",
              value: String(options.value.jsonData.externalId ?? ""),
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({ externalId: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "配置文件" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-profile",
              "data-grafana-label": "Credentials Profile Name",
              value: String(options.value.jsonData.profile ?? ""),
              "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchJson({ profile: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "自定义指标命名空间" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-custom-ns",
              "data-grafana-label": "Namespaces of Custom Metrics",
              value: String(options.value.jsonData.customMetricsNamespaces ?? ""),
              placeholder: "Namespace1,Namespace2",
              "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patchJson({ customMetricsNamespaces: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "日志查询超时" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-logs-timeout",
              "data-grafana-label": "Query Result Timeout",
              value: String(options.value.jsonData.logsTimeout ?? ""),
              placeholder: "30m",
              "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patchJson({ logsTimeout: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "默认日志组" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-default-log-groups",
              "data-grafana-label": "Default Log Groups",
              value: String(
                options.value.jsonData.defaultLogGroups ?? options.value.jsonData.logGroups ?? ""
              ),
              placeholder: "log-group-1,log-group-2",
              "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patchJson({ defaultLogGroups: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "链路追踪数据源 UID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "cw-tracing-ds",
              value: String(options.value.jsonData.tracingDatasourceUid ?? ""),
              "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patchJson({ tracingDatasourceUid: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const CloudWatchConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1z, [["__scopeId", "data-v-3482788e"]]);
const _hoisted_1$$ = { class: "cfg-section" };
const _sfc_main$1y = /* @__PURE__ */ defineComponent({
  __name: "ElasticsearchConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$$, [
        createVNode(unref(FormItem), { label: "索引名" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-index",
              value: String(options.value.jsonData.index ?? options.value.database ?? ""),
              placeholder: "[logstash-]YYYY.MM.DD",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ index: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "时间字段" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-time-field",
              value: String(options.value.jsonData.timeField ?? "@timestamp"),
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ timeField: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "ES 版本" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-version",
              value: String(options.value.jsonData.esVersion ?? options.value.jsonData.version ?? ""),
              placeholder: "8.0.0",
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ esVersion: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "最大并发分片请求" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-max-concurrent",
              value: String(options.value.jsonData.maxConcurrentShardRequests ?? ""),
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({ maxConcurrentShardRequests: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "最小时间间隔" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-interval",
              value: String(
                options.value.jsonData.interval ?? options.value.jsonData.timeInterval ?? ""
              ),
              placeholder: "10s",
              "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchJson({ interval: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "日志消息字段" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-log-message",
              value: String(options.value.jsonData.logMessageField ?? ""),
              "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patchJson({ logMessageField: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "日志级别字段" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "es-log-level",
              value: String(options.value.jsonData.logLevelField ?? ""),
              "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patchJson({ logLevelField: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Include Frozen Indices" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "es-include-frozen",
              checked: !!options.value.jsonData.includeFrozen,
              "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => patchJson({ includeFrozen: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const ElasticsearchConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1y, [["__scopeId", "data-v-f8642854"]]);
const _hoisted_1$_ = { class: "cfg-section" };
const _hoisted_2$F = {
  class: "row",
  "data-testid": "tempo-traces-to-logs",
  "data-grafana-label": "Trace to logs"
};
const _hoisted_3$A = {
  class: "row",
  "data-testid": "tempo-service-map",
  "data-grafana-label": "Service graph"
};
const _sfc_main$1x = /* @__PURE__ */ defineComponent({
  __name: "TempoConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$_, [
        createElementVNode("div", _hoisted_2$F, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Trace to logs",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(
              options.value.jsonData.tracesToLogs?.datasourceUid ?? options.value.jsonData.tracesToLogsV2?.datasourceUid ?? ""
            ),
            placeholder: "loki uid",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({
              tracesToLogs: {
                ...options.value.jsonData.tracesToLogs || {},
                datasourceUid: $event
              }
            }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_3$A, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "Service graph",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(options.value.jsonData.serviceMap?.datasourceUid ?? ""),
            placeholder: "prometheus uid",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({
              serviceMap: {
                ...options.value.jsonData.serviceMap || {},
                datasourceUid: $event
              }
            }))
          }, null, 8, ["value"])
        ]),
        createVNode(unref(FormItem), { label: "Trace 转指标" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "tempo-traces-to-metrics",
              checked: !!options.value.jsonData.tracesToMetrics,
              "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patchJson({ tracesToMetrics: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Trace 转日志数据源 UID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "tempo-traces-to-logs",
              value: String(
                options.value.jsonData.tracesToLogs?.datasourceUid ?? options.value.jsonData.tracesToLogsUid ?? ""
              ),
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({
                tracesToLogsUid: $event,
                tracesToLogs: {
                  ...options.value.jsonData.tracesToLogs,
                  datasourceUid: $event
                }
              }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "节点图" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "tempo-node-graph",
              checked: options.value.jsonData.nodeGraph?.enabled !== false,
              "onUpdate:checked": _cache[4] || (_cache[4] = ($event) => patchJson({ nodeGraph: { enabled: $event } }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Search 隐藏" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "tempo-search-hide",
              checked: !!options.value.jsonData.search?.hide,
              "onUpdate:checked": _cache[5] || (_cache[5] = ($event) => patchJson({
                search: { ...options.value.jsonData.search, hide: $event }
              }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Span 条类型" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "tempo-span-bar",
              value: String(
                options.value.jsonData.spanBar?.type ?? options.value.jsonData.spanBar ?? "None"
              ),
              options: [
                { label: "无", value: "None" },
                { label: "时长", value: "Duration" },
                { label: "标签", value: "Tag" }
              ],
              "onUpdate:value": _cache[6] || (_cache[6] = ($event) => patchJson({ spanBar: { type: $event } }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const TempoConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1x, [["__scopeId", "data-v-abbcafb1"]]);
const _hoisted_1$Z = { class: "cfg-section" };
const _sfc_main$1w = /* @__PURE__ */ defineComponent({
  __name: "JaegerConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$Z, [
        createVNode(unref(FormItem), { label: "节点图" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "jaeger-node-graph",
              checked: options.value.jsonData.nodeGraph?.enabled !== false,
              "onUpdate:checked": _cache[0] || (_cache[0] = ($event) => patchJson({ nodeGraph: { enabled: $event } }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Trace 转日志数据源 UID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "jaeger-traces-to-logs",
              value: String(options.value.jsonData.tracesToLogs?.datasourceUid ?? ""),
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({
                tracesToLogs: {
                  ...options.value.jsonData.tracesToLogs,
                  datasourceUid: $event
                }
              }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Span 条类型" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "jaeger-span-bar",
              value: String(options.value.jsonData.spanBar?.type ?? "None"),
              options: [
                { label: "无", value: "None" },
                { label: "时长", value: "Duration" },
                { label: "标签", value: "Tag" }
              ],
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ spanBar: { type: $event } }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const JaegerConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1w, [["__scopeId", "data-v-a1f8799a"]]);
const _hoisted_1$Y = { class: "cfg-section" };
const _sfc_main$1v = /* @__PURE__ */ defineComponent({
  __name: "GraphiteConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$Y, [
        createVNode(unref(FormItem), { label: "Graphite 版本" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "graphite-version",
              "data-grafana-label": "Version",
              value: String(options.value.jsonData.graphiteVersion ?? "1.1"),
              options: [
                { label: "0.9", value: "0.9" },
                { label: "1.0", value: "1.0" },
                { label: "1.1", value: "1.1" }
              ],
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ graphiteVersion: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Graphite 后端类型" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "graphite-type",
              "data-grafana-label": "Graphite backend type",
              value: String(options.value.jsonData.graphiteType ?? "default"),
              options: [
                { label: "默认", value: "default" },
                { label: "Metrictank", value: "metrictank" }
              ],
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ graphiteType: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "Rollup 指示器" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "graphite-rollup",
              "data-grafana-label": "Rollup indicator",
              checked: !!options.value.jsonData.rollupIndicatorEnabled,
              "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patchJson({ rollupIndicatorEnabled: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const GraphiteConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1v, [["__scopeId", "data-v-d6c99339"]]);
const _hoisted_1$X = { class: "cfg-section" };
const _sfc_main$1u = /* @__PURE__ */ defineComponent({
  __name: "PyroscopeConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$X, [
        createVNode(unref(FormItem), { label: "最小步长" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "pyroscope-min-step",
              value: String(options.value.jsonData.minStep ?? ""),
              placeholder: "15s",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ minStep: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const PyroscopeConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1u, [["__scopeId", "data-v-904f6644"]]);
const _hoisted_1$W = { class: "cfg-section" };
const _sfc_main$1t = /* @__PURE__ */ defineComponent({
  __name: "AzureConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$W, [
        createVNode(unref(FormItem), { label: "Azure Cloud" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "azure-cloud",
              "data-grafana-label": "Azure Cloud",
              value: String(
                options.value.jsonData.cloudName ?? options.value.jsonData.azureCloud ?? "azuremonitor"
              ),
              options: [
                { label: "Azure", value: "azuremonitor" },
                { label: "Azure US Government", value: "govazuremonitor" },
                { label: "Azure China", value: "chinaazuremonitor" }
              ],
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ cloudName: $event, azureCloud: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "租户 ID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "azure-tenant",
              "data-grafana-label": "Directory (tenant) ID",
              value: String(options.value.jsonData.tenantId ?? ""),
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchJson({ tenantId: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "客户端 ID" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "azure-client",
              "data-grafana-label": "Application (client) ID",
              value: String(options.value.jsonData.clientId ?? ""),
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchJson({ clientId: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "默认订阅" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "azure-subscription",
              "data-grafana-label": "Default Subscription",
              value: String(options.value.jsonData.subscriptionId ?? ""),
              "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchJson({ subscriptionId: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const AzureConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1t, [["__scopeId", "data-v-9ae91a1c"]]);
const _hoisted_1$V = { class: "cfg-section" };
const _sfc_main$1s = /* @__PURE__ */ defineComponent({
  __name: "AlertmanagerConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$V, [
        createVNode(unref(FormItem), { label: "实现" }, {
          default: withCtx(() => [
            createVNode(unref(Select), {
              "data-testid": "am-implementation",
              value: String(options.value.jsonData.implementation ?? "prometheus"),
              options: [
                { label: "Prometheus", value: "prometheus" },
                { label: "Cortex", value: "cortex" },
                { label: "Mimir", value: "mimir" },
                { label: "Grafana", value: "grafana" }
              ],
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ implementation: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "处理 Grafana 托管告警" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "am-handle-grafana",
              checked: !!options.value.jsonData.handleGrafanaManagedAlerts,
              "onUpdate:checked": _cache[1] || (_cache[1] = ($event) => patchJson({ handleGrafanaManagedAlerts: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const AlertmanagerConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1s, [["__scopeId", "data-v-dbba657d"]]);
const _hoisted_1$U = { class: "cfg-section" };
const _sfc_main$1r = /* @__PURE__ */ defineComponent({
  __name: "TestdataConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$U, [
        createVNode(unref(FormItem), { label: "默认场景" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "testdata-scenario",
              value: String(options.value.jsonData.defaultScenario ?? ""),
              placeholder: "random_walk",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchJson({ defaultScenario: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const TestdataConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1r, [["__scopeId", "data-v-eff37056"]]);
const _hoisted_1$T = { class: "cfg-section" };
const _sfc_main$1q = /* @__PURE__ */ defineComponent({
  __name: "HttpAuthConfigFields",
  props: {
    type: {},
    options: {},
    json: {},
    secure: {},
    queryTimeout: {},
    dsList: {},
    derivedFields: {}
  },
  emits: ["patch", "patch-json", "patch-secure", "patch-derived-raw", "update-derived", "add-derived", "remove-derived"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = computed(() => props.options);
    function patch(partial) {
      emit("patch", partial);
    }
    function patchJson(partial) {
      emit("patch-json", partial);
    }
    function patchSecure(partial) {
      emit("patch-secure", partial);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$T, [
        createVNode(unref(FormItem), { label: "跳过 TLS 验证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-tls-skip-verify",
              checked: !!options.value.jsonData.tlsSkipVerify,
              "onUpdate:checked": _cache[0] || (_cache[0] = ($event) => patchJson({ tlsSkipVerify: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "TLS 客户端认证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-tls-auth",
              checked: !!options.value.jsonData.tlsAuth,
              "onUpdate:checked": _cache[1] || (_cache[1] = ($event) => patchJson({ tlsAuth: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "TLS CA 证书认证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-tls-ca",
              checked: !!options.value.jsonData.tlsAuthWithCACert,
              "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patchJson({ tlsAuthWithCACert: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "SigV4 认证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-sigv4",
              checked: !!options.value.jsonData.sigV4Auth,
              "onUpdate:checked": _cache[3] || (_cache[3] = ($event) => patchJson({ sigV4Auth: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        options.value.jsonData.sigV4Auth ? (openBlock(), createBlock(unref(FormItem), {
          key: 0,
          label: "SigV4 区域"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "ds-sigv4-region",
              value: String(
                options.value.jsonData.sigV4Region ?? options.value.jsonData.sigV4AuthType ?? ""
              ),
              placeholder: "us-east-1",
              "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchJson({ sigV4Region: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        createVNode(unref(FormItem), { label: "安全 Socks 代理" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-secure-socks",
              checked: !!options.value.jsonData.secureSocksDSProxyEnabled,
              "onUpdate:checked": _cache[5] || (_cache[5] = ($event) => patchJson({ secureSocksDSProxyEnabled: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "转发 OAuth 身份" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-oauth-passthru",
              checked: !!options.value.jsonData.oauthPassThru,
              "onUpdate:checked": _cache[6] || (_cache[6] = ($event) => patchJson({ oauthPassThru: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "跨站携带凭证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              "data-testid": "ds-with-credentials",
              checked: !!options.value.withCredentials,
              "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => patch({ withCredentials: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "自定义 HTTP 头" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "ds-http-headers",
              value: String(
                options.value.jsonData.httpHeaderName1 ? `${options.value.jsonData.httpHeaderName1}=…` : options.value.jsonData.customHeaders ? JSON.stringify(options.value.jsonData.customHeaders) : ""
              ),
              placeholder: '{"X-Custom":"value"} 或使用 httpHeaderName1',
              "onUpdate:value": _cache[8] || (_cache[8] = (v) => {
                try {
                  const j = JSON.parse(v || "{}");
                  if (j && typeof j === "object" && !Array.isArray(j))
                    patchJson({ customHeaders: j });
                } catch {
                }
              })
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(FormItem), { label: "HTTP 头名称 1" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "ds-http-header-name1",
              value: String(options.value.jsonData.httpHeaderName1 ?? ""),
              placeholder: "X-Scope-OrgID",
              "onUpdate:value": _cache[9] || (_cache[9] = ($event) => patchJson({ httpHeaderName1: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        options.value.jsonData.httpHeaderName1 ? (openBlock(), createBlock(unref(FormItem), {
          key: 1,
          label: "HTTP 头值 1"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              type: "password",
              "data-testid": "ds-http-header-value1",
              value: String(options.value.secureJsonData?.httpHeaderValue1 ?? ""),
              "onUpdate:value": _cache[10] || (_cache[10] = ($event) => patchSecure({ httpHeaderValue1: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        createVNode(unref(FormItem), { label: "HTTP 头名称 2" }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              "data-testid": "ds-http-header-name2",
              value: String(options.value.jsonData.httpHeaderName2 ?? ""),
              "onUpdate:value": _cache[11] || (_cache[11] = ($event) => patchJson({ httpHeaderName2: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        }),
        options.value.jsonData.httpHeaderName2 ? (openBlock(), createBlock(unref(FormItem), {
          key: 2,
          label: "HTTP 头值 2"
        }, {
          default: withCtx(() => [
            createVNode(unref(Input), {
              type: "password",
              "data-testid": "ds-http-header-value2",
              value: String(options.value.secureJsonData?.httpHeaderValue2 ?? ""),
              "onUpdate:value": _cache[12] || (_cache[12] = ($event) => patchSecure({ httpHeaderValue2: $event }))
            }, null, 8, ["value"])
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        createVNode(unref(FormItem), { label: "基本认证" }, {
          default: withCtx(() => [
            createVNode(unref(Switch), {
              checked: !!options.value.basicAuth,
              "onUpdate:checked": _cache[13] || (_cache[13] = ($event) => patch({ basicAuth: $event }))
            }, null, 8, ["checked"])
          ]),
          _: 1
          /* STABLE */
        }),
        options.value.basicAuth ? (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            createVNode(unref(FormItem), { label: "用户名" }, {
              default: withCtx(() => [
                createVNode(unref(Input), {
                  value: String(options.value.basicAuthUser ?? ""),
                  "onUpdate:value": _cache[14] || (_cache[14] = ($event) => patch({ basicAuthUser: $event }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(unref(FormItem), { label: "密码" }, {
              default: withCtx(() => [
                createVNode(unref(Input), {
                  type: "password",
                  value: String(options.value.secureJsonData?.basicAuthPassword ?? ""),
                  "onUpdate:value": _cache[15] || (_cache[15] = ($event) => patchSecure({ basicAuthPassword: $event }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const HttpAuthConfigFields = /* @__PURE__ */ _export_sfc(_sfc_main$1q, [["__scopeId", "data-v-f3e7318f"]]);
const _hoisted_1$S = ["data-testid"];
const _sfc_main$1p = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const model = useConfigEditorModel(props);
    const {
      type,
      options,
      json,
      secure,
      dsList,
      queryTimeout,
      patch,
      patchJson,
      patchSecure,
      patchDerivedFields,
      derivedFieldsList,
      updateDerivedField,
      addDerivedField,
      removeDerivedField
    } = model;
    const derivedFields = computed(() => derivedFieldsList());
    const isSql = computed(
      () => ["mysql", "mssql", "grafana-postgresql-datasource"].includes(
        String(type.value)
      )
    );
    const isEs = computed(
      () => type.value === "elasticsearch" || type.value === "grafana-elasticsearch-datasource"
    );
    const isPyroscope = computed(
      () => type.value === "grafana-pyroscope-datasource" || type.value === "pyroscope"
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "ds-config-editor",
        "data-testid": `config-editor-${unref(options).type}`
      }, [
        createVNode(unref(Form), { layout: "vertical" }, {
          default: withCtx(() => [
            createVNode(unref(FormItem), { label: "名称" }, {
              default: withCtx(() => [
                createVNode(unref(Input), {
                  "data-testid": "ds-name",
                  value: unref(options).name,
                  "onUpdate:value": _cache[0] || (_cache[0] = ($event) => unref(patch)({ name: $event }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(unref(FormItem), { label: "URL" }, {
              default: withCtx(() => [
                createVNode(unref(Input), {
                  "data-testid": "ds-url",
                  value: unref(options).url,
                  "onUpdate:value": _cache[1] || (_cache[1] = ($event) => unref(patch)({ url: $event })),
                  placeholder: "http://localhost:9090"
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(unref(FormItem), { label: "设为默认" }, {
              default: withCtx(() => [
                createVNode(unref(Switch), {
                  "data-testid": "ds-is-default",
                  checked: !!unref(options).isDefault,
                  "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => unref(patch)({ isDefault: $event }))
                }, null, 8, ["checked"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(unref(FormItem), { label: "访问方式" }, {
              default: withCtx(() => [
                createVNode(unref(Select), {
                  "data-testid": "ds-access",
                  style: { "width": "100%" },
                  value: unref(options).access ?? "proxy",
                  options: [
                    { label: "服务器（默认）", value: "proxy" },
                    { label: "浏览器", value: "direct" }
                  ],
                  "onUpdate:value": _cache[3] || (_cache[3] = ($event) => unref(patch)({ access: $event }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            unref(type) === "prometheus" || unref(type) === "loki" ? (openBlock(), createBlock(PromLokiConfigFields, {
              key: 0,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              "query-timeout": unref(queryTimeout),
              "ds-list": unref(dsList),
              "derived-fields": derivedFields.value,
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure),
              onPatchDerivedRaw: unref(patchDerivedFields),
              onUpdateDerived: unref(updateDerivedField),
              onAddDerived: unref(addDerivedField),
              onRemoveDerived: unref(removeDerivedField)
            }, null, 8, ["type", "options", "json", "secure", "query-timeout", "ds-list", "derived-fields", "onPatch", "onPatchJson", "onPatchSecure", "onPatchDerivedRaw", "onUpdateDerived", "onAddDerived", "onRemoveDerived"])) : createCommentVNode("v-if", true),
            isSql.value ? (openBlock(), createBlock(SqlConfigFields, {
              key: 1,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "influxdb" ? (openBlock(), createBlock(InfluxConfigFields, {
              key: 2,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "cloudwatch" ? (openBlock(), createBlock(CloudWatchConfigFields, {
              key: 3,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            isEs.value ? (openBlock(), createBlock(ElasticsearchConfigFields, {
              key: 4,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "tempo" ? (openBlock(), createBlock(TempoConfigFields, {
              key: 5,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "jaeger" ? (openBlock(), createBlock(JaegerConfigFields, {
              key: 6,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "graphite" ? (openBlock(), createBlock(GraphiteConfigFields, {
              key: 7,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            isPyroscope.value ? (openBlock(), createBlock(PyroscopeConfigFields, {
              key: 8,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "grafana-azure-monitor-datasource" ? (openBlock(), createBlock(AzureConfigFields, {
              key: 9,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "alertmanager" ? (openBlock(), createBlock(AlertmanagerConfigFields, {
              key: 10,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            unref(type) === "grafana-testdata-datasource" ? (openBlock(), createBlock(TestdataConfigFields, {
              key: 11,
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])) : createCommentVNode("v-if", true),
            createVNode(HttpAuthConfigFields, {
              type: unref(type),
              options: unref(options),
              json: unref(json),
              secure: unref(secure),
              onPatch: unref(patch),
              onPatchJson: unref(patchJson),
              onPatchSecure: unref(patchSecure)
            }, null, 8, ["type", "options", "json", "secure", "onPatch", "onPatchJson", "onPatchSecure"])
          ]),
          _: 1
          /* STABLE */
        })
      ], 8, _hoisted_1$S);
    };
  }
});
const SharedConfigEditor = /* @__PURE__ */ _export_sfc(_sfc_main$1p, [["__scopeId", "data-v-f5fcfb33"]]);
const _sfc_main$1o = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "dashboard"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const _hoisted_1$R = {
  class: "var-query-editor",
  "data-testid": "variable-query-editor"
};
const _sfc_main$1n = /* @__PURE__ */ defineComponent({
  __name: "VariableQueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    datasource: {}
  },
  setup(__props) {
    const props = __props;
    const text = computed({
      get: () => typeof props.query === "string" ? props.query : String(props.query?.query ?? ""),
      set: (v) => {
        if (typeof props.query === "string" || props.query == null)
          props.onChange(v);
        else props.onChange({ ...props.query, query: v });
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$R, [
        _cache[2] || (_cache[2] = createElementVNode(
          "label",
          null,
          "变量查询",
          -1
          /* CACHED */
        )),
        __props.datasource?.type === "prometheus" || __props.datasource?.type === "loki" ? (openBlock(), createBlock(unref(Textarea), {
          key: 0,
          value: text.value,
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => text.value = $event),
          rows: 3,
          placeholder: __props.datasource?.type === "loki" ? "label_names()" : "label_values(job)"
        }, null, 8, ["value", "placeholder"])) : (openBlock(), createBlock(unref(Input), {
          key: 1,
          value: text.value,
          "onUpdate:value": _cache[1] || (_cache[1] = ($event) => text.value = $event),
          placeholder: "指标查找查询"
        }, null, 8, ["value"]))
      ]);
    };
  }
});
const VariableQueryEditor$2 = /* @__PURE__ */ _export_sfc(_sfc_main$1n, [["__scopeId", "data-v-db722a00"]]);
const _hoisted_1$Q = {
  class: "anno-query-editor",
  "data-testid": "annotation-query-editor"
};
const _hoisted_2$E = { class: "row" };
const _hoisted_3$z = { class: "row" };
const _hoisted_4$s = { class: "row" };
const _sfc_main$1m = /* @__PURE__ */ defineComponent({
  __name: "AnnotationQueryEditor",
  props: {
    annotation: {},
    onChange: { type: Function },
    datasource: {}
  },
  setup(__props) {
    const props = __props;
    function patch(partial) {
      props.onChange({ ...props.annotation, ...partial });
    }
    const expr = computed({
      get: () => String(
        props.annotation.target?.expr ?? props.annotation.expr ?? ""
      ),
      set: (v) => patch({
        target: { ...props.annotation.target || {}, expr: v },
        expr: v
      })
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$Q, [
        createElementVNode("div", _hoisted_2$E, [
          _cache[4] || (_cache[4] = createElementVNode(
            "label",
            null,
            "启用",
            -1
            /* CACHED */
          )),
          createVNode(unref(Switch), {
            checked: __props.annotation.enable !== false,
            "onUpdate:checked": _cache[0] || (_cache[0] = ($event) => patch({ enable: $event }))
          }, null, 8, ["checked"])
        ]),
        createElementVNode("div", _hoisted_3$z, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "名称",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(__props.annotation.name ?? ""),
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ name: $event }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$s, [
          _cache[6] || (_cache[6] = createElementVNode(
            "label",
            null,
            "颜色",
            -1
            /* CACHED */
          )),
          createVNode(unref(Input), {
            value: String(__props.annotation.iconColor ?? "red"),
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ iconColor: $event }))
          }, null, 8, ["value"])
        ]),
        _cache[7] || (_cache[7] = createElementVNode(
          "label",
          null,
          "查询",
          -1
          /* CACHED */
        )),
        createVNode(unref(Textarea), {
          value: expr.value,
          "onUpdate:value": _cache[3] || (_cache[3] = ($event) => expr.value = $event),
          rows: 3,
          placeholder: "注解查询 / 选择器"
        }, null, 8, ["value"])
      ]);
    };
  }
});
const AnnotationQueryEditor$2 = /* @__PURE__ */ _export_sfc(_sfc_main$1m, [["__scopeId", "data-v-0c836e57"]]);
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 labels = [
      "root",
      "main",
      "parse",
      "query",
      "scan",
      "agg",
      "render",
      "gc"
    ];
    const self = [0, 5, 20, 0, 20, 15, 25, 20];
    const value = [100, 80, 20, 35, 20, 15, 25, 20];
    const level = [0, 1, 2, 2, 3, 3, 2, 1];
    return createDataFrame({
      refId: query.refId,
      name: "profile",
      fields: [
        { name: "label", type: "string", values: labels },
        { name: "level", type: "number", values: level },
        { name: "value", type: "number", values: value },
        { name: "self", type: "number", values: self }
      ],
      meta: { preferredVisualisationType: "flamegraph" }
    });
  }
  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((t2) => ({
                ...t2,
                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((t2) => t2.refId)
          );
          return { data: frames };
        } catch (e) {
          const msg = e instanceof Error ? e.message : String(e);
          return {
            data: request.targets.filter((t2) => !t2.hide).map(
              (t2) => createDataFrame({
                refId: t2.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((t2) => !t2.hide);
      if (meta2.id === "grafana-testdata-datasource" && targets.some(
        (t2) => String(t2.scenarioId ?? "") === "slow_query"
      )) {
        await new Promise((r) => setTimeout(r, 400));
      }
      return {
        data: targets.map(
          (t2) => seriesForScenario(t2, 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")
          }
        ]
      });
    }
  };
}
const meta$j = {
  id: "dashboard",
  name: "Dashboard",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$j,
  QueryEditor: _sfc_main$1D,
  ConfigEditor: _sfc_main$1o,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$j)
});
const _sfc_main$1l = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "mixed"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1k = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "mixed"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$i = {
  id: "mixed",
  name: "Mixed",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$i,
  QueryEditor: _sfc_main$1l,
  ConfigEditor: _sfc_main$1k,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$i)
});
const _sfc_main$1j = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "grafana"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1i = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "grafana"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$h = {
  id: "grafana",
  name: "Grafana",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$h,
  QueryEditor: _sfc_main$1j,
  ConfigEditor: _sfc_main$1i,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$h)
});
const _sfc_main$1h = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "grafana-testdata-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1g = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        SharedConfigEditor,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
const meta$g = {
  id: "grafana-testdata-datasource",
  name: "TestData",
  backend: true,
  metrics: true,
  logs: false
};
createDataSourcePlugin({
  meta: meta$g,
  QueryEditor: _sfc_main$1h,
  ConfigEditor: _sfc_main$1g,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$g)
});
const _sfc_main$1f = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "grafana-postgresql-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1e = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        SharedConfigEditor,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
const meta$f = {
  id: "grafana-postgresql-datasource",
  name: "PostgreSQL",
  backend: true,
  metrics: true,
  logs: false
};
createDataSourcePlugin({
  meta: meta$f,
  QueryEditor: _sfc_main$1f,
  ConfigEditor: _sfc_main$1e,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$f)
});
const _sfc_main$1d = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "mysql"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1c = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        SharedConfigEditor,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
const meta$e = {
  id: "mysql",
  name: "MySQL",
  backend: true,
  metrics: true,
  logs: false
};
createDataSourcePlugin({
  meta: meta$e,
  QueryEditor: _sfc_main$1d,
  ConfigEditor: _sfc_main$1c,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$e)
});
const _sfc_main$1b = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "mssql"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$1a = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "mssql"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$d = {
  id: "mssql",
  name: "Microsoft SQL Server",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$d,
  QueryEditor: _sfc_main$1b,
  ConfigEditor: _sfc_main$1a,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$d)
});
const _sfc_main$19 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "influxdb"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$18 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "influxdb"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$c = {
  id: "influxdb",
  name: "InfluxDB",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$c,
  QueryEditor: _sfc_main$19,
  ConfigEditor: _sfc_main$18,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$c)
});
const _sfc_main$17 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "graphite"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$16 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "graphite"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$b = {
  id: "graphite",
  name: "Graphite",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$b,
  QueryEditor: _sfc_main$17,
  ConfigEditor: _sfc_main$16,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$b)
});
let factory$1 = null;
function registerPrometheusDataSourceFactory(fn) {
  factory$1 = fn;
}
function createPrometheusDataSource$1(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;
}
const _sfc_main$15 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    datasourceApi: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "prometheus"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        "datasource-api": props.datasourceApi,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "datasource-api", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$14 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        SharedConfigEditor,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
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 t2 = 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: [t2] },
          {
            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 t2 = Number(series.value?.[0] ?? 0);
      times = [t2 < 1e12 ? t2 * 1e3 : t2];
      const raw = series.value?.[1];
      values = [raw == null || raw === "NaN" ? null : Number(raw)];
    } else {
      const pts = series.values || [];
      times = pts.map((p) => {
        const t2 = Number(p[0]);
        return t2 < 1e12 ? t2 * 1e3 : t2;
      });
      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
  };
}
const store = /* @__PURE__ */ new Map();
const inflight = /* @__PURE__ */ new Map();
let totalBytes = 0;
const MAX_ENTRIES$2 = 500;
const MAX_BYTES = 8 * 1024 * 1024;
function fullKey(uid, key) {
  return `${uid}::${key}`;
}
function estimateBytes(value) {
  try {
    return JSON.stringify(value)?.length ?? 64;
  } catch {
    return 256;
  }
}
function evict() {
  while (store.size > MAX_ENTRIES$2 || totalBytes > MAX_BYTES) {
    let oldestKey = null;
    let oldestAccess = Infinity;
    for (const [k, e2] of store) {
      if (e2.lastAccess < oldestAccess) {
        oldestAccess = e2.lastAccess;
        oldestKey = k;
      }
    }
    if (!oldestKey) break;
    const e = store.get(oldestKey);
    store.delete(oldestKey);
    if (e) totalBytes = Math.max(0, totalBytes - e.estimatedBytes);
  }
}
function metadataCacheGet(uid, key) {
  const k = fullKey(uid, key);
  const e = store.get(k);
  if (!e) return void 0;
  if (Date.now() > e.expiresAt) {
    store.delete(k);
    totalBytes = Math.max(0, totalBytes - e.estimatedBytes);
    return void 0;
  }
  e.lastAccess = Date.now();
  return e.value;
}
function metadataCacheSet(uid, key, value, ttlMs2 = 6e4) {
  const k = fullKey(uid, key);
  const prev = store.get(k);
  if (prev) totalBytes = Math.max(0, totalBytes - prev.estimatedBytes);
  const estimatedBytes = estimateBytes(value);
  store.set(k, {
    value,
    expiresAt: Date.now() + Math.max(1e3, ttlMs2),
    estimatedBytes,
    lastAccess: Date.now()
  });
  totalBytes += estimatedBytes;
  evict();
}
async function metadataCacheLoad(uid, key, loader, ttlMs2 = 6e4) {
  const hit = metadataCacheGet(uid, key);
  if (hit !== void 0) return hit;
  const k = fullKey(uid, key);
  const existing = inflight.get(k);
  if (existing) return existing;
  const p = (async () => {
    try {
      const value = await loader();
      metadataCacheSet(uid, key, value, ttlMs2);
      return value;
    } finally {
      inflight.delete(k);
    }
  })();
  inflight.set(k, p);
  return p;
}
async function promGet(opts, path, query) {
  const res = await datasourceHttp({
    baseUrl: opts.baseUrl.replace(/\/$/, ""),
    path,
    method: "GET",
    query,
    uid: opts.uid,
    credential: opts.credential ?? void 0,
    signal: opts.signal,
    timeoutMs: opts.timeoutMs ?? 3e4
  });
  return res.data;
}
async function promLabelNames(opts, match) {
  const cacheKey = `prom:labels:${[].join(",")}`;
  return metadataCacheLoad(opts.uid, cacheKey, async () => {
    const query = {};
    if (match?.length) ;
    const data = await promGet(
      opts,
      "/api/v1/labels",
      query
    );
    return Array.isArray(data?.data) ? data.data : [];
  });
}
async function promLabelValues(opts, label, match) {
  const cacheKey = `prom:labelValues:${label}:${(match || []).join(",")}`;
  return metadataCacheLoad(opts.uid, cacheKey, async () => {
    const query = {};
    if (match?.length) query["match[]"] = match.length === 1 ? match[0] : match;
    const data = await promGet(
      opts,
      `/api/v1/label/${encodeURIComponent(label)}/values`,
      query
    );
    return Array.isArray(data?.data) ? data.data : [];
  });
}
async function promMetricNames(opts, limit = 500) {
  return metadataCacheLoad(
    opts.uid,
    `prom:metrics:${limit}`,
    async () => {
      try {
        const data = await promGet(opts, "/api/v1/metadata");
        const names = Object.keys(data?.data || {});
        if (names.length) return names.slice(0, limit).sort();
      } catch {
      }
      return (await promLabelValues(opts, "__name__")).slice(0, limit);
    },
    12e4
  );
}
const PROMETHEUS_CAPABILITIES = {
  signals: ["metrics"],
  query: true,
  health: true,
  metadata: true,
  variables: true,
  annotations: true,
  exemplars: true,
  streaming: false,
  queryLanguages: ["promql"]
};
function baseUrlOf$2(instance) {
  return String(
    instance.url || instance.jsonData?.url || ""
  ).replace(/\/$/, "");
}
function createPrometheusDataSource(instance, meta2) {
  const fallback = createBuiltinDataSourceApi(instance, meta2);
  const url = baseUrlOf$2(instance);
  return {
    uid: instance.uid,
    type: instance.type || meta2.id,
    name: instance.name,
    capabilities: PROMETHEUS_CAPABILITIES,
    async query(request, signal) {
      const targets = request.targets.filter(
        (t2) => !t2.hide
      );
      if (getBackendMode() === "offline") {
        return fallback.query(request);
      }
      if (!url) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Datasource URL is empty"
        );
      }
      const from = request.range.from.getTime();
      const to = request.range.to.getTime();
      const rangeMs2 = Math.max(1, to - from);
      const stepMs = computeStepMs({
        rangeMs: rangeMs2,
        maxDataPoints: request.maxDataPoints,
        intervalMs: request.intervalMs,
        minIntervalMs: Number(instance.jsonData?.timeIntervalMs) || void 0
      });
      const stepSec = Math.max(1, Math.floor(stepMs / 1e3));
      const cred = await getRuntimeCredential(instance.uid);
      const frames = [];
      const errors = [];
      await Promise.all(
        targets.map(async (raw) => {
          const q = normalizePromQuery({ ...raw, refId: raw.refId });
          if (!q.expr?.trim()) return;
          const expr = interpolatePromMacros(q.expr, {
            rangeMs: rangeMs2,
            intervalMs: stepMs,
            interpolate: (s) => s
            // variable interpolation done by query runtime when present
          });
          try {
            const instant = q.instant && !q.range;
            const path = instant ? "/api/v1/query" : "/api/v1/query_range";
            const query = instant ? {
              query: expr,
              time: String(to / 1e3),
              timeout: String(
                instance.jsonData?.queryTimeout || "60s"
              )
            } : {
              query: expr,
              start: String(from / 1e3),
              end: String(to / 1e3),
              step: String(stepSec),
              timeout: String(
                instance.jsonData?.queryTimeout || "60s"
              )
            };
            const method = String(
              instance.jsonData?.httpMethod || "POST"
            ).toUpperCase() === "GET" ? "GET" : "POST";
            const res = await datasourceHttp({
              baseUrl: url,
              path,
              method,
              query: method === "GET" ? query : void 0,
              body: method === "POST" ? query : void 0,
              uid: instance.uid,
              credential: cred,
              signal,
              timeoutMs: Number(instance.jsonData?.timeout) || 6e4
            });
            const mapped = mapPrometheusResponse(res.data, {
              refId: q.refId,
              legendFormat: q.legendFormat,
              expr: q.expr
            });
            frames.push(...normalizeDataFrames(mapped, { refId: q.refId }));
          } catch (e) {
            const msg = e instanceof DataSourceError ? e.message : e instanceof Error ? e.message : String(e);
            errors.push(`${q.refId}: ${msg}`);
            frames.push(
              ...normalizeDataFrames(
                [
                  {
                    refId: q.refId,
                    name: "error",
                    length: 0,
                    fields: [],
                    meta: { error: msg }
                  }
                ],
                { refId: q.refId }
              )
            );
          }
        })
      );
      if (!frames.length && errors.length) {
        throw new DataSourceError("INVALID_RESPONSE", errors.join("; "));
      }
      return { data: frames };
    },
    async testDatasource(signal) {
      if (getBackendMode() === "offline") {
        return fallback.testDatasource?.() ?? {
          status: "success",
          message: "Offline fixture OK"
        };
      }
      if (!url) return { status: "error", message: "Datasource URL is empty" };
      try {
        await datasourceHttp({
          baseUrl: url,
          path: "/-/ready",
          method: "GET",
          uid: instance.uid,
          signal,
          timeoutMs: 1e4
        });
        return { status: "success", message: "Prometheus is ready" };
      } catch (e) {
        try {
          await datasourceHttp({
            baseUrl: url,
            path: "/api/v1/labels",
            method: "GET",
            uid: instance.uid,
            signal,
            timeoutMs: 1e4
          });
          return { status: "success", message: "Prometheus API reachable" };
        } catch (e2) {
          const msg = e2 instanceof Error ? e2.message : String(e2);
          return { status: "error", message: msg };
        }
      }
    },
    async metricFindQuery(query, signal) {
      if (getBackendMode() === "offline") {
        return fallback.metricFindQuery?.(query) ?? [];
      }
      if (!url) return [];
      const cred = await getRuntimeCredential(instance.uid);
      const opts = {
        baseUrl: url,
        uid: instance.uid,
        credential: cred,
        signal
      };
      const q = String(query ?? "").trim();
      if (!q || /^metrics\s*\(/i.test(q) || q === "label_values(__name__)") {
        const names = await promMetricNames(opts);
        return names.map((n) => ({ text: n, value: n }));
      }
      const lv2 = q.match(
        /label_values\s*\(\s*([^,]+)\s*,\s*([a-zA-Z_][\w]*)\s*\)/i
      );
      if (lv2) {
        const metric = lv2[1].trim().replace(/^["']|["']$/g, "");
        const label = lv2[2].trim();
        const vals = await promLabelValues(
          opts,
          label,
          metric && metric !== label ? [metric] : void 0
        );
        return vals.map((v) => ({ text: v, value: v }));
      }
      const lv1 = q.match(/label_values\s*\(\s*([a-zA-Z_][\w]*)\s*\)/i);
      if (lv1) {
        const vals = await promLabelValues(opts, lv1[1]);
        return vals.map((v) => ({ text: v, value: v }));
      }
      if (/label_names\s*\(/i.test(q)) {
        const names = await promLabelNames(opts);
        return names.map((n) => ({ text: n, value: n }));
      }
      return fallback.metricFindQuery?.(query) ?? [];
    },
    /** Prefetch helpers for QueryEditor metric browser */
    async listMetricNames(signal) {
      if (getBackendMode() === "offline") {
        return [
          "up",
          "process_cpu_seconds_total",
          "process_resident_memory_bytes",
          "http_requests_total",
          "http_request_duration_seconds_bucket",
          "node_cpu_seconds_total",
          "node_memory_MemAvailable_bytes",
          "container_cpu_usage_seconds_total",
          "container_memory_working_set_bytes",
          "go_goroutines"
        ];
      }
      if (!url) return [];
      const cred = await getRuntimeCredential(instance.uid);
      return promMetricNames({
        baseUrl: url,
        uid: instance.uid,
        credential: cred,
        signal
      });
    },
    async listLabelNames(signal) {
      if (getBackendMode() === "offline") {
        return [
          "__name__",
          "job",
          "instance",
          "namespace",
          "pod",
          "service",
          "status",
          "method"
        ];
      }
      if (!url) return [];
      const cred = await getRuntimeCredential(instance.uid);
      return promLabelNames({
        baseUrl: url,
        uid: instance.uid,
        credential: cred,
        signal
      });
    }
  };
}
const meta$a = {
  id: "prometheus",
  name: "Prometheus",
  backend: true,
  metrics: true,
  logs: false,
  capabilities: PROMETHEUS_CAPABILITIES
};
registerPrometheusDataSourceFactory(
  (instance, pluginMeta) => createPrometheusDataSource(instance, pluginMeta)
);
createDataSourcePlugin({
  meta: meta$a,
  QueryEditor: _sfc_main$15,
  ConfigEditor: _sfc_main$14,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createPrometheusDataSource(instance, meta$a)
});
const _sfc_main$13 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "loki"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$12 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(
        SharedConfigEditor,
        normalizeProps(guardReactiveProps(props)),
        null,
        16
        /* FULL_PROPS */
      );
    };
  }
});
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
  };
}
function isLokiMetricQuery(expr) {
  return /\b(rate|count_over_time|sum_over_time|avg_over_time|max_over_time|min_over_time|bytes_rate|bytes_over_time|quantile_over_time|first_over_time|last_over_time|stdvar_over_time|stddev_over_time|unwrap|topk|bottomk)\b/i.test(
    expr
  );
}
function formatLokiLegend(legendFormat, labels = {}) {
  if (!legendFormat) {
    const entries = Object.entries(labels).filter(
      ([k, v]) => k !== "__name__" && v != null && v !== ""
    );
    if (!entries.length) return "";
    if (entries.length === 1) return String(entries[0][1]);
    return "{" + entries.map(([k, v]) => `${k}="${v}"`).join(", ") + "}";
  }
  return legendFormat.replace(
    /\{\{\s*([a-zA-Z_][\w]*)\s*\}\}/g,
    (_, k) => labels[k] ?? ""
  );
}
function extractByLabels(expr) {
  const m = expr.match(/\bby\s*\(\s*([^)]+)\s*\)/i);
  if (!m) return [];
  return m[1].split(",").map((s) => s.trim()).filter(Boolean);
}
function nsToMs(ts) {
  const n = typeof ts === "string" ? Number(ts) : ts;
  if (!Number.isFinite(n)) return 0;
  if (n > 1e16) return Math.floor(n / 1e6);
  if (n > 1e12) return Math.floor(n);
  return Math.floor(n * 1e3);
}
function labelsFromStream(stream = {}) {
  const labels = {};
  for (const [k, v] of Object.entries(stream)) {
    if (k.startsWith("__")) continue;
    labels[k] = String(v);
  }
  return labels;
}
function mapLokiResponse(body, opts) {
  if (body?.status === "error" || body?.error) {
    throw new Error(body.error || body.errorType || "Loki query error");
  }
  const resultType = body?.data?.resultType ?? (isLokiMetricQuery(opts.expr || "") ? "matrix" : "streams");
  const result = body?.data?.result ?? [];
  if (resultType === "streams") {
    return mapStreams(result, opts);
  }
  if (resultType === "scalar" || resultType === "string") {
    const pair = Array.isArray(result) ? result : [0, result];
    const t2 = nsToMs(pair[0]);
    const v = resultType === "string" ? null : Number(pair[1]);
    return [
      createDataFrame({
        refId: opts.refId,
        name: opts.expr || "scalar",
        meta: {
          preferredVisualisationType: "table",
          resultType,
          custom: { stats: body?.data?.stats }
        },
        fields: [
          { name: "Time", type: "time", values: [t2] },
          {
            name: "Value",
            type: "number",
            values: [v],
            config: { displayNameFromDS: "Value" }
          }
        ]
      })
    ];
  }
  return result.map((series, idx) => {
    const metric = series.metric || series.stream || {};
    const labels = labelsFromStream(metric);
    const name = formatLokiLegend(opts.legendFormat || "", labels) || Object.values(labels).join(" ") || opts.expr || `series ${idx}`;
    let times = [];
    let values = [];
    if (resultType === "vector") {
      const rawT = series.value?.[0] ?? 0;
      times = [nsToMs(rawT)];
      const raw = series.value?.[1];
      values = [raw == null || raw === "NaN" ? null : Number(raw)];
    } else {
      const pts = series.values || [];
      times = pts.map((p) => nsToMs(p[0]));
      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",
        custom: { stats: body?.data?.stats }
      },
      fields: [
        { name: "Time", type: "time", values: times },
        {
          name: "Value",
          type: "number",
          values,
          labels,
          config: { displayNameFromDS: name }
        }
      ]
    });
  });
}
function mapStreams(result, opts) {
  const maxLines = Math.max(1, opts.maxLines ?? 1e3);
  const times = [];
  const lines = [];
  const levels = [];
  const labelObjs = [];
  const idValues = [];
  for (const stream of result) {
    const labels = labelsFromStream(stream.stream || stream.metric || {});
    const entries = stream.values || [];
    for (const [ts, line] of entries) {
      if (times.length >= maxLines) break;
      times.push(nsToMs(ts));
      const text = String(line ?? "");
      lines.push(text);
      levels.push(inferLevel(text, labels));
      labelObjs.push(labels);
      idValues.push(`${ts}_${times.length}`);
    }
    if (times.length >= maxLines) break;
  }
  const order = times.map((_, i) => i).sort((a, b) => times[b] - times[a]);
  const pick = (arr) => order.map((i) => arr[i]);
  const labelKeys = /* @__PURE__ */ new Set();
  for (const l of labelObjs) {
    for (const k of Object.keys(l)) labelKeys.add(k);
  }
  const labelFields = [...labelKeys].slice(0, 12).map((k) => ({
    name: k,
    type: "string",
    values: pick(labelObjs.map((l) => l[k] ?? "")),
    config: {}
  }));
  return [
    createDataFrame({
      refId: opts.refId,
      name: "logs",
      meta: {
        preferredVisualisationType: "logs",
        searchWords: [],
        limit: maxLines
      },
      fields: [
        { name: "Time", type: "time", values: pick(times) },
        { name: "Line", type: "string", values: pick(lines) },
        { name: "labels", type: "other", values: pick(labelObjs) },
        { name: "id", type: "string", values: pick(idValues) },
        { name: "level", type: "string", values: pick(levels) },
        ...labelFields
      ]
    })
  ];
}
function inferLevel(line, labels) {
  if (labels.level) return String(labels.level).toLowerCase();
  if (labels.severity) return String(labels.severity).toLowerCase();
  const m = line.match(/\b(error|warn|warning|info|debug|critical|fatal)\b/i);
  if (m) {
    const l = m[1].toLowerCase();
    if (l === "warning") return "warn";
    return l;
  }
  return "unknown";
}
const LOKI_CAPABILITIES = {
  signals: ["logs", "metrics"],
  query: true,
  health: true,
  metadata: true,
  variables: true,
  annotations: true,
  exemplars: false,
  streaming: false,
  queryLanguages: ["logql"]
};
function baseUrlOf$1(instance) {
  return String(
    instance.url || instance.jsonData?.url || ""
  ).replace(/\/$/, "");
}
function buildLokiOfflineMetricFrames(q, range, maxDataPoints = 50) {
  const from = range.from.getTime();
  const to = range.to.getTime();
  const steps = Math.min(
    maxDataPoints,
    Math.max(12, Math.floor((to - from) / 6e4))
  );
  const by = extractByLabels(q.expr);
  const seriesDefs = [];
  if (by.includes("status") || /status/i.test(q.expr)) {
    for (const status of ["200", "301", "304", "404", "500"]) {
      seriesDefs.push({ status });
    }
  } else if (by.includes("request_uri") || by.includes("http_referer") || by.includes("http_user_agent")) {
    const key = by[0] || "request_uri";
    for (let i = 0; i < 5; i++) seriesDefs.push({ [key]: `/page-${i}` });
  } else if (by.includes("remote_addr")) {
    for (let i = 0; i < 5; i++) {
      seriesDefs.push({
        remote_addr: `10.0.0.${i + 1}`,
        geoip_country_code: i % 2 ? "US" : "NL"
      });
    }
  } else if (by.includes("geoip_country_code")) {
    for (const c of ["US", "NL", "DE", "JP", "BR"])
      seriesDefs.push({ geoip_country_code: c });
  } else if (by.includes("host")) {
    seriesDefs.push({ host: "nginx-1" });
  } else if (by.length) {
    for (let i = 0; i < 3; i++) {
      const labels = {};
      for (const k of by) labels[k] = `${k}-${i}`;
      seriesDefs.push(labels);
    }
  } else {
    seriesDefs.push({ job: "nginx" });
  }
  return seriesDefs.map((labels, sIdx) => {
    const times = [];
    const values = [];
    for (let i = 0; i < steps; i++) {
      times.push(from + (to - from) * i / Math.max(steps - 1, 1));
      const base = 10 + sIdx * 7 + i % 5 * 3;
      values.push(q.instant ? base * steps : base + Math.sin(i / 3 + sIdx) * 5);
    }
    const name = formatLokiLegend(q.legendFormat || "", labels) || Object.values(labels).join(" ") || q.expr || `series ${sIdx}`;
    if (q.instant) {
      return createDataFrame({
        refId: q.refId,
        name,
        meta: { resultType: "vector", preferredVisualisationType: "table" },
        fields: [
          { name: "Time", type: "time", values: [to] },
          {
            name: "Value",
            type: "number",
            values: [values.reduce((a, b) => a + b, 0)],
            labels,
            config: { displayNameFromDS: name }
          },
          ...Object.entries(labels).map(([k, v]) => ({
            name: k,
            type: "string",
            values: [v],
            config: {}
          }))
        ]
      });
    }
    return createDataFrame({
      refId: q.refId,
      name,
      meta: { resultType: "matrix", preferredVisualisationType: "graph" },
      fields: [
        { name: "Time", type: "time", values: times },
        {
          name: "Value",
          type: "number",
          values,
          labels,
          config: { displayNameFromDS: name }
        }
      ]
    });
  });
}
function createLokiDataSource(instance, meta2) {
  const fallback = createBuiltinDataSourceApi(instance, meta2);
  const url = baseUrlOf$1(instance);
  return {
    uid: instance.uid,
    type: instance.type || meta2.id,
    name: instance.name,
    capabilities: LOKI_CAPABILITIES,
    async query(request, signal) {
      const targets = request.targets.filter(
        (t2) => !t2.hide
      );
      if (getBackendMode() === "offline") {
        const frames2 = [];
        for (const raw of targets) {
          const q = normalizeLokiQuery({ ...raw, refId: raw.refId });
          if (!q.expr?.trim()) continue;
          if (isLokiMetricQuery(q.expr)) {
            frames2.push(
              ...buildLokiOfflineMetricFrames(
                q,
                request.range,
                request.maxDataPoints ?? 50
              )
            );
          } else {
            const res = await fallback.query({
              ...request,
              targets: [q]
            });
            frames2.push(...res.data);
          }
        }
        return {
          data: frames2.length ? frames2 : (await fallback.query(request)).data
        };
      }
      if (!url) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Datasource URL is empty"
        );
      }
      const from = request.range.from.getTime();
      const to = request.range.to.getTime();
      const rangeMs2 = Math.max(1, to - from);
      const stepMs = computeStepMs({
        rangeMs: rangeMs2,
        maxDataPoints: request.maxDataPoints,
        intervalMs: request.intervalMs,
        minIntervalMs: Number(instance.jsonData?.timeIntervalMs) || void 0
      });
      const stepSec = Math.max(1, Math.floor(stepMs / 1e3));
      const cred = await getRuntimeCredential(instance.uid);
      const frames = [];
      const errors = [];
      await Promise.all(
        targets.map(async (raw) => {
          const q = normalizeLokiQuery({ ...raw, refId: raw.refId });
          if (!q.expr?.trim()) return;
          const expr = interpolatePromMacros(q.expr, {
            rangeMs: rangeMs2,
            intervalMs: stepMs,
            interpolate: (s) => s
          });
          try {
            const metric = isLokiMetricQuery(expr);
            const instant = q.instant && !q.range;
            const path = instant ? "/loki/api/v1/query" : "/loki/api/v1/query_range";
            const query = instant ? {
              query: expr,
              time: String(to * 1e6),
              // ns
              limit: String(q.maxLines ?? 1e3),
              direction: q.direction ?? "backward"
            } : {
              query: expr,
              start: String(from * 1e6),
              end: String(to * 1e6),
              limit: String(q.maxLines ?? 1e3),
              direction: q.direction ?? "backward"
            };
            if (!instant && metric) {
              query.step = String(q.step ?? `${stepSec}s`);
            }
            const method = String(
              instance.jsonData?.httpMethod || "GET"
            ).toUpperCase() === "POST" ? "POST" : "GET";
            const res = await datasourceHttp({
              baseUrl: url,
              path,
              method,
              query: method === "GET" ? query : void 0,
              body: method === "POST" ? query : void 0,
              uid: instance.uid,
              credential: cred,
              signal,
              timeoutMs: Number(instance.jsonData?.timeout) || 6e4
            });
            const mapped = mapLokiResponse(res.data, {
              refId: q.refId,
              legendFormat: q.legendFormat,
              expr: q.expr,
              maxLines: q.maxLines
            });
            frames.push(...normalizeDataFrames(mapped, { refId: q.refId }));
          } catch (e) {
            const msg = e instanceof DataSourceError ? e.message : e instanceof Error ? e.message : String(e);
            errors.push(`${q.refId}: ${msg}`);
            frames.push(
              ...normalizeDataFrames(
                [
                  {
                    refId: q.refId,
                    name: "error",
                    length: 0,
                    fields: [],
                    meta: { error: msg }
                  }
                ],
                { refId: q.refId }
              )
            );
          }
        })
      );
      if (!frames.length && errors.length) {
        throw new DataSourceError("INVALID_RESPONSE", errors.join("; "));
      }
      return { data: frames };
    },
    async testDatasource(signal) {
      if (getBackendMode() === "offline") {
        return fallback.testDatasource?.() ?? {
          status: "success",
          message: "Offline fixture OK"
        };
      }
      if (!url) return { status: "error", message: "Datasource URL is empty" };
      try {
        await datasourceHttp({
          baseUrl: url,
          path: "/ready",
          method: "GET",
          uid: instance.uid,
          signal,
          timeoutMs: 1e4
        });
        return { status: "success", message: "Loki is ready" };
      } catch {
        try {
          await datasourceHttp({
            baseUrl: url,
            path: "/loki/api/v1/labels",
            method: "GET",
            uid: instance.uid,
            signal,
            timeoutMs: 1e4
          });
          return { status: "success", message: "Loki API reachable" };
        } catch (e2) {
          const msg = e2 instanceof Error ? e2.message : String(e2);
          return { status: "error", message: msg };
        }
      }
    },
    async metricFindQuery(query, signal) {
      if (getBackendMode() === "offline") {
        return fallback.metricFindQuery?.(query) ?? [];
      }
      const q = String(query ?? "").trim();
      if (/^label_names\s*\(\s*\)\s*$/i.test(q) || q === "label_names()") {
        const res2 = await datasourceHttp({
          baseUrl: url,
          path: "/loki/api/v1/labels",
          uid: instance.uid,
          signal
        });
        return (res2.data?.data ?? []).map((v) => ({ text: v, value: v }));
      }
      const lv = q.match(
        /label_values\s*\(\s*(?:\{[^}]*\}\s*,\s*)?([a-zA-Z_][\w]*)\s*\)/i
      ) || q.match(/label_values\s*\(\s*\$?[a-zA-Z_][\w]*\s*\)/i);
      if (lv || /label_values/i.test(q)) {
        const labelMatch = q.match(
          /label_values\s*\(\s*(?:.+,\s*)?([a-zA-Z_][\w]*)\s*\)/i
        );
        const label = labelMatch?.[1] || "job";
        if (label === "label_name" || label.startsWith("$")) {
          return [];
        }
        const res2 = await datasourceHttp({
          baseUrl: url,
          path: `/loki/api/v1/label/${encodeURIComponent(label)}/values`,
          uid: instance.uid,
          signal
        });
        return (res2.data?.data ?? []).map((v) => ({ text: v, value: v }));
      }
      const res = await datasourceHttp({
        baseUrl: url,
        path: "/loki/api/v1/labels",
        uid: instance.uid,
        signal
      });
      return (res.data?.data ?? []).map((v) => ({ text: v, value: v }));
    }
  };
}
const meta$9 = {
  id: "loki",
  name: "Loki",
  backend: true,
  metrics: true,
  logs: true,
  capabilities: LOKI_CAPABILITIES
};
createDataSourcePlugin({
  meta: meta$9,
  QueryEditor: _sfc_main$13,
  ConfigEditor: _sfc_main$12,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createLokiDataSource(instance, meta$9)
});
const _sfc_main$11 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "jaeger"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$10 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "jaeger"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$8 = {
  id: "jaeger",
  name: "Jaeger",
  backend: true,
  metrics: false,
  logs: false,
  tracing: true
};
createDataSourcePlugin({
  meta: meta$8,
  QueryEditor: _sfc_main$11,
  ConfigEditor: _sfc_main$10,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$8)
});
function mapTempoTraceResponse(body, opts) {
  if (body?.batches || body?.resourceSpans) {
    return [mapOtlp(body, opts)];
  }
  if (body?.data) return mapTempoTraceResponse(body.data, opts);
  if (body?.spans || body?.processes || Array.isArray(body)) {
    return [mapJaegerLike(body, opts)];
  }
  if (body?.traces || body?.traceSummaries) {
    return [mapSearch(body, opts)];
  }
  return [
    createDataFrame({
      refId: opts.refId,
      name: "trace",
      meta: { preferredVisualisationType: "trace" },
      fields: [
        { name: "traceID", type: "string", values: [opts.traceId || ""] },
        { name: "spanID", type: "string", values: [] },
        { name: "operationName", type: "string", values: [] },
        { name: "serviceName", type: "string", values: [] },
        { name: "startTimeUnixNano", type: "number", values: [] },
        { name: "durationNano", type: "number", values: [] }
      ]
    })
  ];
}
function mapSearch(body, opts) {
  const traces = body.traces || body.traceSummaries || [];
  return createDataFrame({
    refId: opts.refId,
    name: "trace-search",
    meta: { preferredVisualisationType: "table" },
    fields: [
      {
        name: "traceID",
        type: "string",
        values: traces.map(
          (t2) => t2.traceID || t2.traceId || t2.rootTraceId || ""
        )
      },
      {
        name: "rootServiceName",
        type: "string",
        values: traces.map(
          (t2) => t2.rootServiceName || t2.serviceName || ""
        )
      },
      {
        name: "rootTraceName",
        type: "string",
        values: traces.map(
          (t2) => t2.rootTraceName || t2.rootServiceName || t2.name || ""
        )
      },
      {
        name: "durationMs",
        type: "number",
        values: traces.map((t2) => {
          const d = t2.durationMs ?? t2.durationMs ?? (t2.duration ? Number(t2.duration) / 1e6 : null);
          return d;
        })
      },
      {
        name: "startTime",
        type: "time",
        values: traces.map((t2) => {
          const s = t2.startTimeUnixNano || t2.startTime || 0;
          const n = Number(s);
          return n > 1e15 ? Math.floor(n / 1e6) : n > 1e12 ? n : n * 1e3;
        })
      }
    ]
  });
}
function mapJaegerLike(body, opts) {
  const spans = Array.isArray(body) ? body : body.spans || [];
  const processes = body.processes || {};
  const spanIDs = [];
  const parents = [];
  const ops = [];
  const svcs = [];
  const starts = [];
  const durs = [];
  const status = [];
  const traceIds = [];
  for (const s of spans) {
    spanIDs.push(String(s.spanID || s.spanId || s.span_id || ""));
    const refs = s.references || s.refs || [];
    const pref = refs.find(
      (r) => r.refType === "CHILD_OF" || r.refType === "CHILD_OF"
    ) || refs[0];
    parents.push(
      pref ? String(pref.spanID || pref.spanId || null) : s.parentSpanId || null
    );
    ops.push(String(s.operationName || s.name || s.operation_name || ""));
    const proc = s.process || processes[s.processID] || {};
    svcs.push(
      String(proc.serviceName || s.serviceName || s.service_name || "unknown")
    );
    const st = Number(
      s.startTime || s.startTimeUnixNano || s.startTimeUnixNano || 0
    );
    starts.push(st > 1e15 ? st : st > 1e12 ? st * 1e3 : st * 1e3);
    const d = Number(s.duration || s.durationNano || 0);
    durs.push(d > 1e9 ? d : d * 1e3);
    const tags = s.tags || s.attributes || [];
    const err = Array.isArray(tags) ? tags.find(
      (t2) => (t2.key === "error" || t2.key === "otel.status_code") && (t2.value === true || t2.value === "ERROR")
    ) : null;
    status.push(err ? "ERROR" : "OK");
    traceIds.push(
      String(s.traceID || s.traceId || opts.traceId || body.traceID || "")
    );
  }
  return createDataFrame({
    refId: opts.refId,
    name: "trace",
    meta: { preferredVisualisationType: "trace", traceId: opts.traceId },
    fields: [
      { name: "traceID", type: "string", values: traceIds },
      { name: "spanID", type: "string", values: spanIDs },
      { name: "parentSpanID", type: "string", values: parents },
      { name: "operationName", type: "string", values: ops },
      { name: "serviceName", type: "string", values: svcs },
      { name: "startTimeUnixNano", type: "number", values: starts },
      { name: "durationNano", type: "number", values: durs },
      { name: "statusCode", type: "string", values: status }
    ]
  });
}
function mapOtlp(body, opts) {
  const batches = body.batches || body.resourceSpans || [];
  const spanIDs = [];
  const parents = [];
  const ops = [];
  const svcs = [];
  const starts = [];
  const durs = [];
  const status = [];
  const traceIds = [];
  for (const batch of batches) {
    const res = batch.resource || {};
    const attrs = res.attributes || [];
    const svcAttr = Array.isArray(attrs) ? attrs.find((a) => a.key === "service.name") : null;
    const service = svcAttr?.value?.stringValue || svcAttr?.value || res["service.name"] || "unknown";
    const scopeSpans = batch.scopeSpans || batch.instrumentationLibrarySpans || batch.spans || [];
    for (const scope of scopeSpans) {
      const spans = scope.spans || (scope.spanID ? [scope] : []);
      for (const s of spans) {
        spanIDs.push(String(s.spanId || s.spanID || ""));
        parents.push(s.parentSpanId || s.parentSpanID || null);
        ops.push(String(s.name || s.operationName || ""));
        svcs.push(String(service));
        starts.push(Number(s.startTimeUnixNano || 0));
        const end = Number(s.endTimeUnixNano || 0);
        const start = Number(s.startTimeUnixNano || 0);
        durs.push(end && start ? end - start : Number(s.durationNano || 0));
        status.push(String(s.status?.code || s.status?.message || "OK"));
        traceIds.push(String(s.traceId || s.traceID || opts.traceId || ""));
      }
    }
  }
  return createDataFrame({
    refId: opts.refId,
    name: "trace",
    meta: { preferredVisualisationType: "trace", traceId: opts.traceId },
    fields: [
      { name: "traceID", type: "string", values: traceIds },
      { name: "spanID", type: "string", values: spanIDs },
      { name: "parentSpanID", type: "string", values: parents },
      { name: "operationName", type: "string", values: ops },
      { name: "serviceName", type: "string", values: svcs },
      { name: "startTimeUnixNano", type: "number", values: starts },
      { name: "durationNano", type: "number", values: durs },
      { name: "statusCode", type: "string", values: status }
    ]
  });
}
const TEMPO_CAPABILITIES = {
  signals: ["traces"],
  query: true,
  health: true,
  metadata: true,
  variables: false,
  annotations: false,
  exemplars: false,
  streaming: false,
  queryLanguages: ["traceql", "trace-id"]
};
function baseUrlOf(instance) {
  return String(
    instance.url || instance.jsonData?.url || ""
  ).replace(/\/$/, "");
}
function offlineTraceFrame(refId, traceId = "offline-trace") {
  const n = 6;
  return createDataFrame({
    refId,
    name: "trace",
    meta: { preferredVisualisationType: "trace", traceId },
    fields: [
      { name: "traceID", type: "string", values: Array(n).fill(traceId) },
      {
        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" : `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 === 4 ? "ERROR" : "OK")
      }
    ]
  });
}
function createTempoDataSource(instance, meta2) {
  const fallback = createBuiltinDataSourceApi(instance, meta2);
  const url = baseUrlOf(instance);
  async function listSearchTags(signal) {
    if (getBackendMode() === "offline") {
      return [
        "service.name",
        "http.method",
        "http.status_code",
        "span.kind"
      ].map((t2) => ({
        text: t2,
        value: t2
      }));
    }
    if (!url) return [];
    return metadataCacheLoad(instance.uid, "tempo:tags", async () => {
      const cred = await getRuntimeCredential(instance.uid);
      try {
        const res = await datasourceHttp({
          baseUrl: url,
          path: "/api/search/tags",
          method: "GET",
          uid: instance.uid,
          credential: cred,
          signal
        });
        const tags = res.data?.tagNames || res.data?.tags || res.data || [];
        const arr = Array.isArray(tags) ? tags : [];
        return arr.map((t2) => {
          const name = typeof t2 === "string" ? t2 : String(t2);
          return { text: name, value: name };
        });
      } catch {
        return [];
      }
    });
  }
  async function listTagValues(tag, signal) {
    if (!tag) return [];
    if (getBackendMode() === "offline") {
      if (tag === "service.name") {
        return ["frontend", "api", "checkout"].map((v) => ({
          text: v,
          value: v
        }));
      }
      return [];
    }
    if (!url) return [];
    return metadataCacheLoad(
      instance.uid,
      `tempo:tagValues:${tag}`,
      async () => {
        const cred = await getRuntimeCredential(instance.uid);
        try {
          const res = await datasourceHttp({
            baseUrl: url,
            path: `/api/search/tag/${encodeURIComponent(tag)}/values`,
            method: "GET",
            uid: instance.uid,
            credential: cred,
            signal
          });
          const vals = res.data?.tagValues || res.data?.values || res.data || [];
          const arr = Array.isArray(vals) ? vals : [];
          return arr.map((v) => {
            const name = typeof v === "string" ? v : String(v);
            return { text: name, value: name };
          });
        } catch {
          return [];
        }
      },
      3e4
    );
  }
  return {
    uid: instance.uid,
    type: instance.type || meta2.id,
    name: instance.name,
    capabilities: TEMPO_CAPABILITIES,
    async query(request, signal) {
      const targets = request.targets.filter((t2) => !t2.hide);
      if (getBackendMode() === "offline") {
        return {
          data: targets.map(
            (t2) => offlineTraceFrame(
              t2.refId,
              String(t2.query || t2.traceId || "offline-trace")
            )
          )
        };
      }
      if (!url) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Datasource URL is empty"
        );
      }
      const cred = await getRuntimeCredential(instance.uid);
      const frames = [];
      const errors = [];
      const from = request.range.from.getTime();
      const to = request.range.to.getTime();
      await Promise.all(
        targets.map(async (raw) => {
          const q = raw;
          const queryType = String(
            q.queryType || (q.traceId || looksLikeTraceId(q.query) ? "traceId" : "search")
          );
          const traceId = String(
            q.traceId || (looksLikeTraceId(q.query) ? q.query : "") || ""
          ).trim();
          try {
            if (queryType === "traceId" || traceId && !q.search) {
              if (!traceId)
                throw new DataSourceError(
                  "INVALID_RESPONSE",
                  "traceId required"
                );
              const res = await datasourceHttp({
                baseUrl: url,
                path: `/api/traces/${encodeURIComponent(traceId)}`,
                method: "GET",
                uid: instance.uid,
                credential: cred,
                signal,
                timeoutMs: 3e4
              });
              const mapped = mapTempoTraceResponse(res.data, {
                refId: q.refId,
                traceId
              });
              frames.push(...normalizeDataFrames(mapped, { refId: q.refId }));
            } else {
              const searchQ = String(q.query || q.search || q.expr || "{}");
              const res = await datasourceHttp({
                baseUrl: url,
                path: "/api/search",
                method: "GET",
                query: {
                  q: searchQ,
                  start: String(Math.floor(from * 1e3)),
                  // Tempo often expects µs or ns depending on version — send µs-ish
                  end: String(Math.floor(to * 1e3)),
                  limit: String(q.limit ?? 20)
                },
                uid: instance.uid,
                credential: cred,
                signal,
                timeoutMs: 3e4
              });
              const mapped = mapTempoTraceResponse(res.data, {
                refId: q.refId
              });
              frames.push(...normalizeDataFrames(mapped, { refId: q.refId }));
            }
          } catch (e) {
            const msg = e instanceof DataSourceError ? e.message : e instanceof Error ? e.message : String(e);
            errors.push(`${q.refId}: ${msg}`);
            frames.push(
              ...normalizeDataFrames(
                [
                  {
                    refId: q.refId,
                    name: "error",
                    length: 0,
                    fields: [],
                    meta: { error: msg }
                  }
                ],
                { refId: q.refId }
              )
            );
          }
        })
      );
      if (!frames.length && errors.length) {
        throw new DataSourceError("INVALID_RESPONSE", errors.join("; "));
      }
      return { data: frames };
    },
    async testDatasource(signal) {
      if (getBackendMode() === "offline") {
        return fallback.testDatasource?.() ?? {
          status: "success",
          message: "Offline Tempo OK"
        };
      }
      if (!url) return { status: "error", message: "Datasource URL is empty" };
      try {
        await datasourceHttp({
          baseUrl: url,
          path: "/ready",
          method: "GET",
          uid: instance.uid,
          signal,
          timeoutMs: 1e4
        });
        return { status: "success", message: "Tempo is ready" };
      } catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        return { status: "error", message: msg };
      }
    },
    listSearchTags,
    listTagValues,
    async metricFindQuery(query, signal) {
      const q = String(query ?? "").trim().toLowerCase();
      if (!q || q.includes("tag") || q.includes("label")) {
        return listSearchTags(signal);
      }
      if (q.includes("service")) {
        return listTagValues("service.name", signal);
      }
      return [];
    }
  };
}
function looksLikeTraceId(q) {
  const s = String(q ?? "").trim();
  return /^[a-fA-F0-9]{16,32}$/.test(s);
}
const meta$7 = {
  id: "tempo",
  name: "Tempo",
  tracing: true,
  backend: true,
  capabilities: TEMPO_CAPABILITIES
};
createDataSourcePlugin({
  meta: meta$7,
  QueryEditor: SharedQueryEditor,
  ConfigEditor: SharedConfigEditor,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createTempoDataSource(instance, meta$7)
});
const _sfc_main$$ = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "grafana-pyroscope-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$_ = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "grafana-pyroscope-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$6 = {
  id: "grafana-pyroscope-datasource",
  name: "Pyroscope",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$6,
  QueryEditor: _sfc_main$$,
  ConfigEditor: _sfc_main$_,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$6)
});
const _sfc_main$Z = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "cloudwatch"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$Y = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "cloudwatch"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$5 = {
  id: "cloudwatch",
  name: "CloudWatch",
  backend: true,
  metrics: true,
  logs: true,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$5,
  QueryEditor: _sfc_main$Z,
  ConfigEditor: _sfc_main$Y,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$5)
});
const _sfc_main$X = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "grafana-azure-monitor-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$W = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "grafana-azure-monitor-datasource"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$4 = {
  id: "grafana-azure-monitor-datasource",
  name: "Azure Monitor",
  backend: true,
  metrics: true,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$4,
  QueryEditor: _sfc_main$X,
  ConfigEditor: _sfc_main$W,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$4)
});
const _sfc_main$V = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const ds2 = computed(() => ({
      ...props.datasource,
      type: props.datasource?.type || "alertmanager"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedQueryEditor, {
        query: props.query,
        datasource: ds2.value,
        onChange: props.onChange,
        onRunQuery: props.onRunQuery,
        range: props.range,
        data: props.data
      }, null, 8, ["query", "datasource", "onChange", "onRunQuery", "range", "data"]);
    };
  }
});
const _sfc_main$U = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...props.options,
      type: props.options?.type || "alertmanager"
    }));
    return (_ctx, _cache) => {
      return openBlock(), createBlock(SharedConfigEditor, {
        options: options.value,
        onOptionsChange: props.onOptionsChange
      }, null, 8, ["options", "onOptionsChange"]);
    };
  }
});
const meta$3 = {
  id: "alertmanager",
  name: "Alertmanager",
  backend: true,
  metrics: false,
  logs: false,
  tracing: false
};
createDataSourcePlugin({
  meta: meta$3,
  QueryEditor: _sfc_main$V,
  ConfigEditor: _sfc_main$U,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createBuiltinDataSourceApi(instance, meta$3)
});
const _hoisted_1$P = {
  class: "otel-qe",
  "data-testid": "query-editor-opentelemetry"
};
const _hoisted_2$D = {
  key: 0,
  class: "err"
};
const _hoisted_3$y = { class: "row" };
const _hoisted_4$r = { class: "row" };
const _hoisted_5$l = {
  key: 1,
  class: "row",
  "data-testid": "otel-metric-browser"
};
const _hoisted_6$j = {
  key: 2,
  class: "row",
  "data-testid": "otel-service-browser"
};
const _hoisted_7$h = {
  key: 3,
  class: "row",
  "data-testid": "otel-tag-browser"
};
const _hoisted_8$b = { class: "row" };
const _hoisted_9$b = { class: "row" };
const _hoisted_10$9 = { class: "row" };
const _sfc_main$T = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    datasourceApi: {}
  },
  setup(__props) {
    const props = __props;
    const signal = computed({
      get: () => String(props.query.signal || "metrics"),
      set: (v) => props.onChange({ ...props.query, signal: v })
    });
    const expr = computed({
      get: () => String(props.query.expr || props.query.query || ""),
      set: (v) => props.onChange({ ...props.query, expr: v, query: v })
    });
    const provider2 = computed({
      get: () => String(props.query.provider || ""),
      set: (v) => props.onChange({ ...props.query, provider: v })
    });
    const service = computed({
      get: () => String(props.query.service || ""),
      set: (v) => props.onChange({ ...props.query, service: v })
    });
    const maxLines = computed({
      get: () => String(props.query.maxLines ?? props.query.limit ?? ""),
      set: (v) => {
        const n = v === "" ? void 0 : Number(v);
        props.onChange({
          ...props.query,
          maxLines: Number.isFinite(n) ? n : void 0,
          limit: Number.isFinite(n) ? n : void 0
        });
      }
    });
    const signalOptions = [
      { label: "Metrics", value: "metrics" },
      { label: "Logs", value: "logs" },
      { label: "Traces", value: "traces" }
    ];
    const providerHint = computed(() => {
      if (signal.value === "metrics") return "prometheus";
      if (signal.value === "logs") return "loki | signoz";
      return "tempo | jaeger | signoz";
    });
    const services = ref([]);
    const metrics = ref([]);
    const tags = ref([]);
    const metaError = ref("");
    const metaLoading = ref(false);
    async function loadMeta() {
      metaLoading.value = true;
      metaError.value = "";
      try {
        const api = props.datasourceApi;
        if (signal.value === "metrics") {
          if (typeof api?.listMetricNames === "function") {
            const names = await api.listMetricNames();
            metrics.value = (names || []).map((n) => ({
              label: n,
              value: n
            }));
          } else {
            metrics.value = [
              { label: "up", value: "up" },
              { label: "http_requests_total", value: "http_requests_total" }
            ];
          }
        } else if (signal.value === "traces") {
          if (typeof api?.listSearchTags === "function") {
            const rows = await api.listSearchTags();
            tags.value = (rows || []).map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          } else {
            tags.value = [
              { label: "service.name", value: "service.name" },
              { label: "http.method", value: "http.method" }
            ];
          }
          if (typeof api?.listServices === "function") {
            const rows = await api.listServices();
            services.value = (rows || []).map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          } else if (typeof api?.listTagValues === "function") {
            const rows = await api.listTagValues("service.name");
            services.value = (rows || []).map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          } else {
            services.value = [
              { label: "frontend", value: "frontend" },
              { label: "api", value: "api" }
            ];
          }
        } else {
          if (typeof api?.listServices === "function") {
            const rows = await api.listServices();
            services.value = (rows || []).map((r) => ({
              label: String(r.text ?? r.value ?? r),
              value: String(r.value ?? r.text ?? r)
            }));
          } else {
            services.value = [
              { label: "frontend", value: "frontend" },
              { label: "api", value: "api" }
            ];
          }
        }
      } catch (e) {
        metaError.value = e instanceof Error ? e.message : String(e);
      } finally {
        metaLoading.value = false;
      }
    }
    function insertTag(v) {
      const t2 = String(v ?? "");
      if (t2 && !expr.value.trim()) {
        expr.value = "{ " + t2 + ' = "" }';
      }
    }
    function insertMetric(v) {
      const m = String(v ?? "");
      if (m) expr.value = m;
    }
    function pickService(v) {
      const s = String(v ?? "");
      service.value = s;
      if (signal.value === "traces" && s && !expr.value.trim()) {
        expr.value = `{ resource.service.name = "${s}" }`;
      }
    }
    onMounted(loadMeta);
    watch(signal, () => {
      void loadMeta();
    });
    watch(
      () => props.datasourceApi,
      () => {
        void loadMeta();
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$P, [
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_2$D,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_3$y, [
          _cache[6] || (_cache[6] = createElementVNode(
            "label",
            null,
            "Signal",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            modelValue: signal.value,
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => signal.value = $event),
            options: signalOptions,
            "test-id": "otel-signal"
          }, null, 8, ["modelValue"])
        ]),
        createElementVNode("div", _hoisted_4$r, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Provider 覆盖（可选）",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            modelValue: provider2.value,
            "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => provider2.value = $event),
            placeholder: providerHint.value,
            "test-id": "otel-provider"
          }, null, 8, ["modelValue", "placeholder"])
        ]),
        signal.value === "metrics" ? (openBlock(), createElementBlock("div", _hoisted_5$l, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "指标浏览器（预取）",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            options: metrics.value,
            placeholder: "选择指标插入 PromQL",
            "data-testid": "otel-metric-select",
            "onUpdate:value": insertMetric
          }, null, 8, ["loading", "options"])
        ])) : createCommentVNode("v-if", true),
        signal.value !== "metrics" ? (openBlock(), createElementBlock("div", _hoisted_6$j, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "Service（预取）",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            value: service.value || void 0,
            options: services.value,
            placeholder: "service.name",
            "data-testid": "otel-service-select",
            "onUpdate:value": pickService
          }, null, 8, ["loading", "value", "options"])
        ])) : createCommentVNode("v-if", true),
        signal.value === "traces" && tags.value.length ? (openBlock(), createElementBlock("div", _hoisted_7$h, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "Trace 标签",
            -1
            /* CACHED */
          )),
          createVNode(unref(Select), {
            style: { "width": "100%" },
            "show-search": "",
            "allow-clear": "",
            loading: metaLoading.value,
            options: tags.value,
            placeholder: "Tempo 搜索标签",
            "data-testid": "otel-tag-select",
            "onUpdate:value": insertTag
          }, null, 8, ["loading", "options"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_8$b, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "Service / Resource（可选）",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            modelValue: service.value,
            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => service.value = $event),
            placeholder: "service.name",
            "test-id": "otel-service"
          }, null, 8, ["modelValue"])
        ]),
        createElementVNode("div", _hoisted_9$b, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "限制 / maxLines",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            modelValue: maxLines.value,
            "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => maxLines.value = $event),
            placeholder: "1000",
            "test-id": "otel-max-lines"
          }, null, 8, ["modelValue"])
        ]),
        createElementVNode("div", _hoisted_10$9, [
          createElementVNode(
            "label",
            null,
            toDisplayString(signal.value === "metrics" ? "PromQL" : signal.value === "logs" ? "LogQL" : "Trace 查询"),
            1
            /* TEXT */
          ),
          createVNode(unref(GInput), {
            modelValue: expr.value,
            "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => expr.value = $event),
            "test-id": "otel-expr"
          }, null, 8, ["modelValue"])
        ]),
        createVNode(unref(GButton), {
          size: "sm",
          variant: "primary",
          "test-id": "run-query",
          onClick: _cache[5] || (_cache[5] = ($event) => props.onRunQuery?.())
        }, {
          default: withCtx(() => [..._cache[13] || (_cache[13] = [
            createTextVNode(
              "运行查询",
              -1
              /* CACHED */
            )
          ])]),
          _: 1
          /* STABLE */
        }),
        _cache[14] || (_cache[14] = createElementVNode(
          "p",
          { class: "hint" },
          " OpenTelemetry 是查询聚合器，不是 OTLP 写入。请在数据源配置中设置 metricsUrl / logsUrl / tracesUrl。查询编辑器挂载时会预取指标/服务/标签。 ",
          -1
          /* CACHED */
        ))
      ]);
    };
  }
});
const QueryEditor$2 = /* @__PURE__ */ _export_sfc(_sfc_main$T, [["__scopeId", "data-v-539b4835"]]);
const _hoisted_1$O = {
  class: "otel-cfg",
  "data-testid": "config-editor-opentelemetry"
};
const _sfc_main$S = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    function jd() {
      return { ...props.options?.jsonData || {} };
    }
    function patchJson(p) {
      const options = props.options;
      props.onOptionsChange({
        ...options,
        jsonData: { ...jd(), ...p }
      });
    }
    const defaultSignal = computed({
      get: () => String(jd().defaultSignal || "metrics"),
      set: (v) => patchJson({ defaultSignal: v })
    });
    const metricsUrl = computed({
      get: () => String(jd().metricsUrl || ""),
      set: (v) => patchJson({ metricsUrl: v })
    });
    const logsUrl = computed({
      get: () => String(jd().logsUrl || ""),
      set: (v) => patchJson({ logsUrl: v })
    });
    const tracesUrl = computed({
      get: () => String(jd().tracesUrl || ""),
      set: (v) => patchJson({ tracesUrl: v })
    });
    const tracesProvider = computed({
      get: () => String(jd().tracesProvider || "tempo"),
      set: (v) => patchJson({ tracesProvider: v })
    });
    const logsProvider = computed({
      get: () => String(jd().logsProvider || "loki"),
      set: (v) => patchJson({ logsProvider: v })
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$O, [
        _cache[6] || (_cache[6] = createElementVNode(
          "h4",
          null,
          "OpenTelemetry 查询聚合器",
          -1
          /* CACHED */
        )),
        _cache[7] || (_cache[7] = createElementVNode(
          "p",
          { class: "warn" },
          " 浏览器直连查询端点（非 OTLP /v1/* 写入）。凭据仅存运行时内存。 ",
          -1
          /* CACHED */
        )),
        _cache[8] || (_cache[8] = createElementVNode(
          "label",
          null,
          "默认 Signal",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          modelValue: defaultSignal.value,
          "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => defaultSignal.value = $event),
          options: [
            { label: "metrics", value: "metrics" },
            { label: "logs", value: "logs" },
            { label: "traces", value: "traces" }
          ],
          "test-id": "otel-default-signal"
        }, null, 8, ["modelValue"]),
        _cache[9] || (_cache[9] = createElementVNode(
          "label",
          null,
          "Metrics URL（Prometheus-compatible）",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          modelValue: metricsUrl.value,
          "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => metricsUrl.value = $event),
          placeholder: "http://localhost:9090",
          "test-id": "otel-metrics-url"
        }, null, 8, ["modelValue"]),
        _cache[10] || (_cache[10] = createElementVNode(
          "label",
          null,
          "Logs URL（Loki-compatible）",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          modelValue: logsUrl.value,
          "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => logsUrl.value = $event),
          placeholder: "http://localhost:3100",
          "test-id": "otel-logs-url"
        }, null, 8, ["modelValue"]),
        _cache[11] || (_cache[11] = createElementVNode(
          "label",
          null,
          "Logs Provider",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          modelValue: logsProvider.value,
          "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => logsProvider.value = $event),
          options: [
            { label: "loki", value: "loki" },
            { label: "signoz", value: "signoz" }
          ],
          "test-id": "otel-logs-provider"
        }, null, 8, ["modelValue"]),
        _cache[12] || (_cache[12] = createElementVNode(
          "label",
          null,
          "Traces URL",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          modelValue: tracesUrl.value,
          "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => tracesUrl.value = $event),
          placeholder: "http://localhost:3200",
          "test-id": "otel-traces-url"
        }, null, 8, ["modelValue"]),
        _cache[13] || (_cache[13] = createElementVNode(
          "label",
          null,
          "Traces Provider",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          modelValue: tracesProvider.value,
          "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => tracesProvider.value = $event),
          options: [
            { label: "tempo", value: "tempo" },
            { label: "jaeger", value: "jaeger" }
          ],
          "test-id": "otel-traces-provider"
        }, null, 8, ["modelValue"])
      ]);
    };
  }
});
const ConfigEditor$2 = /* @__PURE__ */ _export_sfc(_sfc_main$S, [["__scopeId", "data-v-10e6f551"]]);
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 OTEL_CAPABILITIES = {
  signals: ["metrics", "logs", "traces"],
  query: true,
  health: true,
  metadata: true,
  variables: true,
  annotations: false,
  exemplars: false,
  streaming: false,
  queryLanguages: ["promql", "logql", "traceql", "trace-filter"]
};
function buildOtelCapabilities(json, instanceUrl) {
  const signals = [];
  const langs = [];
  if (json.metricsUrl || instanceUrl) {
    signals.push("metrics");
    langs.push("promql");
  }
  if (json.logsUrl) {
    signals.push("logs");
    langs.push(
      String(json.logsProvider || "loki") === "signoz" ? "signoz-logs" : "logql"
    );
  }
  if (json.tracesUrl) {
    signals.push("traces");
    langs.push("traceql", "trace-filter");
  }
  if (!signals.length) {
    return { ...OTEL_CAPABILITIES };
  }
  return {
    ...OTEL_CAPABILITIES,
    signals,
    queryLanguages: langs.length ? langs : OTEL_CAPABILITIES.queryLanguages
  };
}
function createOpenTelemetryDataSource(instance, meta2) {
  const fallback = createBuiltinDataSourceApi(instance, meta2);
  const json = instance.jsonData || {};
  const metricsProvider = String(json.metricsProvider || "prometheus");
  const logsProvider = String(json.logsProvider || "loki");
  const tracesProvider = String(json.tracesProvider || "tempo");
  return {
    uid: instance.uid,
    type: meta2.id,
    name: instance.name,
    capabilities: buildOtelCapabilities(json, instance.url),
    async query(request, signal) {
      if (getBackendMode() === "offline") return fallback.query(request);
      const frames = [];
      for (const t2 of request.targets.filter((x) => !x.hide)) {
        const signalType = String(
          t2.signal || json.defaultSignal || "metrics"
        );
        if (signalType === "metrics") {
          if (metricsProvider !== "prometheus" && metricsProvider !== "promql") {
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              `Metrics provider "${metricsProvider}" is not configured`
            );
          }
          const promUrl = String(
            json.metricsUrl || instance.url || ""
          );
          if (!promUrl)
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              "metricsUrl not configured for OTel metrics"
            );
          const prom = createPrometheusDataSource(
            {
              ...instance,
              url: promUrl,
              jsonData: { ...json, ...json.metricsJsonData || {} }
            },
            { id: "prometheus", name: "Prometheus" }
          );
          const res = await prom.query(
            {
              ...request,
              targets: [{ ...t2, expr: t2.expr || t2.query }]
            },
            signal
          );
          frames.push(...res.data);
        } else if (signalType === "logs") {
          const endpoint = String(json.logsUrl || "");
          if (!endpoint) {
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              "logs query endpoint not configured (OTel is a query aggregator, not OTLP)"
            );
          }
          if (logsProvider !== "loki" && logsProvider !== "signoz") {
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              `Logs provider "${logsProvider}" is not supported (use loki|signoz)`
            );
          }
          if (logsProvider === "signoz") {
            const signoz = createSignozDataSource$1(
              {
                ...instance,
                url: endpoint,
                jsonData: {
                  ...json,
                  ...json.logsJsonData || {},
                  apiProfile: json.logsApiProfile || "signoz-v3"
                }
              },
              { id: "signoz", name: "SigNoz" }
            );
            const res = await signoz.query(
              {
                ...request,
                targets: [
                  {
                    ...t2,
                    signal: "logs",
                    expr: t2.expr || t2.query
                  }
                ]
              },
              signal
            );
            frames.push(...res.data);
          } else {
            const loki = createLokiDataSource(
              {
                ...instance,
                url: endpoint,
                jsonData: {
                  ...json,
                  ...json.logsJsonData || {},
                  apiProfile: json.logsApiProfile
                }
              },
              { id: "loki", name: "Loki" }
            );
            const res = await loki.query(
              {
                ...request,
                targets: [{ ...t2, expr: t2.expr || t2.query }]
              },
              signal
            );
            frames.push(...res.data);
          }
        } else if (signalType === "traces") {
          const endpoint = String(json.tracesUrl || "");
          if (!endpoint) {
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              "traces query endpoint not configured (OTel is a query aggregator, not OTLP)"
            );
          }
          if (tracesProvider !== "tempo" && tracesProvider !== "jaeger") {
            throw new DataSourceError(
              "UNSUPPORTED_QUERY_API",
              `Traces provider "${tracesProvider}" is not supported (use tempo|jaeger)`
            );
          }
          const tempo = createTempoDataSource(
            {
              ...instance,
              url: endpoint,
              jsonData: { ...json, ...json.tracesJsonData || {} }
            },
            { id: "tempo", name: "Tempo" }
          );
          const res = await tempo.query(
            {
              ...request,
              targets: [
                {
                  ...t2,
                  query: t2.query || t2.expr || t2.traceId,
                  traceId: t2.traceId,
                  queryType: t2.queryType
                }
              ]
            },
            signal
          );
          frames.push(...res.data);
        } else {
          throw new DataSourceError(
            "UNSUPPORTED_QUERY_API",
            `Unknown signal ${signalType}`
          );
        }
      }
      return { data: frames };
    },
    async testDatasource() {
      if (getBackendMode() === "offline")
        return { status: "success", message: "OTel offline OK" };
      if (!json.metricsUrl && !json.logsUrl && !json.tracesUrl && !instance.url) {
        return {
          status: "error",
          message: "Configure metricsUrl/logsUrl/tracesUrl (query providers, not OTLP)"
        };
      }
      return {
        status: "success",
        message: "OpenTelemetry query aggregator configured"
      };
    },
    metricFindQuery: (q) => fallback.metricFindQuery?.(q) ?? Promise.resolve([]),
    /** Prefetch: metrics → Prometheus provider */
    async listMetricNames(signal) {
      const promUrl = String(json.metricsUrl || instance.url || "");
      const prom = createPrometheusDataSource(
        {
          ...instance,
          url: promUrl || "http://localhost:9090",
          jsonData: { ...json, ...json.metricsJsonData || {} }
        },
        { id: "prometheus", name: "Prometheus" }
      );
      if (typeof prom.listMetricNames === "function") {
        return prom.listMetricNames(signal);
      }
      return [];
    },
    async listLabelNames(signal) {
      const promUrl = String(json.metricsUrl || instance.url || "");
      const prom = createPrometheusDataSource(
        {
          ...instance,
          url: promUrl || "http://localhost:9090",
          jsonData: { ...json, ...json.metricsJsonData || {} }
        },
        { id: "prometheus", name: "Prometheus" }
      );
      if (typeof prom.listLabelNames === "function") {
        return prom.listLabelNames(signal);
      }
      return [];
    },
    /** Prefetch: traces → Tempo provider tags/services */
    async listSearchTags(signal) {
      const endpoint = String(json.tracesUrl || "");
      const tempo = createTempoDataSource(
        {
          ...instance,
          url: endpoint || "http://localhost:3200",
          jsonData: { ...json, ...json.tracesJsonData || {} }
        },
        { id: "tempo", name: "Tempo" }
      );
      if (typeof tempo.listSearchTags === "function") {
        return tempo.listSearchTags(signal);
      }
      return [];
    },
    async listTagValues(tag, signal) {
      const endpoint = String(json.tracesUrl || "");
      const tempo = createTempoDataSource(
        {
          ...instance,
          url: endpoint || "http://localhost:3200",
          jsonData: { ...json, ...json.tracesJsonData || {} }
        },
        { id: "tempo", name: "Tempo" }
      );
      if (typeof tempo.listTagValues === "function") {
        return tempo.listTagValues(tag, signal);
      }
      return [];
    },
    /** Prefetch: services (traces tag values or signoz logs) */
    async listServices(signal) {
      if (getBackendMode() === "offline") {
        return [
          { text: "frontend", value: "frontend" },
          { text: "api", value: "api" },
          { text: "checkout", value: "checkout" }
        ];
      }
      if (json.tracesUrl || tracesProvider === "tempo") {
        try {
          const endpoint = String(json.tracesUrl || "http://localhost:3200");
          const tempo = createTempoDataSource(
            {
              ...instance,
              url: endpoint,
              jsonData: { ...json, ...json.tracesJsonData || {} }
            },
            { id: "tempo", name: "Tempo" }
          );
          if (typeof tempo.listTagValues === "function") {
            return await tempo.listTagValues("service.name", signal);
          }
        } catch {
        }
      }
      if (logsProvider === "signoz" && json.logsUrl) {
        const signoz = createSignozDataSource$1(
          {
            ...instance,
            url: String(json.logsUrl),
            jsonData: {
              ...json,
              apiProfile: json.logsApiProfile || "signoz-v3"
            }
          },
          { id: "signoz", name: "SigNoz" }
        );
        if (typeof signoz.listServices === "function") {
          return signoz.listServices(signal);
        }
      }
      return [];
    }
  };
}
const meta$2 = {
  id: "opentelemetry",
  name: "OpenTelemetry",
  metrics: true,
  logs: true,
  tracing: true,
  capabilities: OTEL_CAPABILITIES
};
createDataSourcePlugin({
  meta: meta$2,
  QueryEditor: QueryEditor$2,
  ConfigEditor: ConfigEditor$2,
  VariableQueryEditor: VariableQueryEditor$2,
  AnnotationQueryEditor: AnnotationQueryEditor$2,
  createDataSource: (instance) => createOpenTelemetryDataSource(instance, meta$2)
});
let datasourcesRegistered = false;
function registerBuiltinDataSources() {
  if (datasourcesRegistered) return;
  datasourcesRegistered = true;
  if (listDataSourcePlugins().length === 0) {
    throw new Error(
      "[grafana-vue-datasources] registerBuiltinDataSources produced zero plugins"
    );
  }
}
const ZABBIX_TYPE = "alexanderzobnin-zabbix-datasource";
const SIGNOZ_TYPE = "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 t2 of p.targets || []) {
      const key = JSON.stringify({
        refId: t2.refId,
        queryType: t2.queryType,
        signal: t2.signal,
        requestType: t2.requestType,
        expr: t2.expr,
        item: t2.item,
        schema: t2.schema
      });
      if (seen.has(key) && !t2.expr && !t2.item?.filter && !(t2.queries || []).length) {
        throw new Error(`${uid}: duplicate empty target ${key}`);
      }
      seen.add(`${p.id}:${t2.refId}`);
      if (!t2.datasource?.uid) {
        throw new Error(`${uid}: target ${t2.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, "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, "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, "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, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixServices(uid = "live-zabbix-services") {
  const d = ds(ZABBIX_TYPE, "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, "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, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixProblems(uid = "live-zabbix-problems") {
  const d = ds(ZABBIX_TYPE, "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, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixMacros(uid = "live-zabbix-macros") {
  const d = ds(ZABBIX_TYPE, "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, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixLld(uid = "live-zabbix-lld") {
  const d = ds(ZABBIX_TYPE, "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, "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, 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, dsUid),
          query: { type: "service" }
        },
        {
          name: "metric",
          type: "query",
          datasource: ds(SIGNOZ_TYPE, 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, 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, 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, dsUid),
            hide: true,
            apiProfile: "signoz-v5"
          }
        ]
      }
    )
  ];
  assertNoEmptyDupTargets(
    panels2.map((p) => ({
      ...p,
      targets: (p.targets || []).filter((t2) => !t2.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, 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, "zabbix-3");
  const z14 = ds(ZABBIX_TYPE, "zabbix-14");
  const g = { filter: "$Group" };
  const h2 = { 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: h2,
          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: h2,
          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: h2,
          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: h2,
          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: h2,
          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: h2,
          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: h2,
        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: h2,
        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: h2,
        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: h2,
        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: h2,
        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: h2,
        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 见 `public/app/defaultObservabilityDataSources.json`（不使用 env）\\n- 真实样本: `artifacts/zabbix-signoz-parity/REAL-API-FULL-EXAMPLES.md`'
        }
      }
    )
  ];
  assertNoEmptyDupTargets(
    panels2.map((p) => ({
      ...p,
      targets: (p.targets || []).filter((t2) => t2.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, dsUid),
          query: { type: "service" },
          includeAll: true,
          allValue: ""
        },
        {
          name: "metric",
          type: "query",
          datasource: ds(SIGNOZ_TYPE, 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 t2 = normalizeDsType(type);
  switch (t2) {
    case "prometheus":
      return {
        refId,
        expr: "up",
        range: true,
        instant: false,
        exemplar: false,
        format: "time_series",
        editorMode: "code",
        datasource: { type: t2 }
      };
    case "loki":
      return {
        refId,
        expr: '{job="varlogs"}',
        queryType: "range",
        maxLines: 1e3,
        editorMode: "code",
        datasource: { type: t2 }
      };
    case "grafana-postgresql-datasource":
    case "mysql":
    case "mssql":
      return {
        refId,
        rawSql: "SELECT 1 AS value",
        format: 1,
        rawQuery: true,
        datasource: { type: t2 }
      };
    case "grafana-testdata-datasource":
      return {
        refId,
        scenarioId: "random_walk",
        alias: "test",
        seriesCount: 1,
        datasource: { type: t2 }
      };
    case "graphite":
      return {
        refId,
        target: "stats.counters.*",
        textEditor: true,
        datasource: { type: t2 }
      };
    case "influxdb":
      return {
        refId,
        query: "SELECT mean(value) FROM cpu",
        rawQuery: true,
        resultFormat: "time_series",
        datasource: { type: t2 }
      };
    case "cloudwatch":
      return {
        refId,
        queryMode: "Metrics",
        region: "default",
        namespace: "AWS/EC2",
        metricName: "CPUUtilization",
        statistic: "Average",
        period: "",
        matchExact: true,
        expression: "",
        datasource: { type: t2 }
      };
    case "jaeger":
      return {
        refId,
        query: "",
        service: "",
        operation: "",
        datasource: { type: t2 }
      };
    case "grafana-pyroscope-datasource":
      return {
        refId,
        query: "process_cpu:cpu:nanoseconds:cpu:nanoseconds{}",
        profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds",
        labelSelector: "{}",
        groupBy: [],
        datasource: { type: t2 }
      };
    case "grafana-azure-monitor-datasource":
      return {
        refId,
        queryType: "Azure Monitor",
        azureMonitor: {
          timeGrain: "auto",
          metricName: "",
          aggregation: "Average"
        },
        datasource: { type: t2 }
      };
    case "elasticsearch":
      return {
        refId,
        query: "*",
        timeField: "@timestamp",
        metrics: [{ type: "count", id: "1" }],
        bucketAggs: [
          { type: "date_histogram", id: "2", settings: { interval: "auto" } }
        ],
        datasource: { type: t2 }
      };
    case "tempo":
      return {
        refId,
        query: "{}",
        queryType: "traceql",
        limit: 20,
        datasource: { type: t2 }
      };
    case "grafana":
      return { refId, queryType: "randomWalk", datasource: { type: t2 } };
    case "dashboard":
      return { refId, panelId: void 0, datasource: { type: t2 } };
    case "alertmanager":
      return { refId, query: "", expr: "", datasource: { type: t2 } };
    case "mixed":
      return { refId, datasource: { type: "mixed", uid: "mixed" } };
    default:
      return { refId, query: "", datasource: t2 ? { type: t2 } : 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 }
        }))
      };
  }
}
class LiveAcceptanceError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
    this.name = "LiveAcceptanceError";
  }
  code;
}
function fieldValues$1(frame, name) {
  const field = frame.fields.find((f) => f.name === name);
  return field?.values ?? [];
}
function isEmptyValue(v) {
  return v == null || v === "" || typeof v === "string" && v.trim() === "";
}
function isTestDataUid(uid) {
  const lower = uid.toLowerCase();
  return lower.includes("testdata") || lower.includes("test-data") || lower === "td" || lower.startsWith("testdata-");
}
function isErrorFrame(frame) {
  if (frame.name === "error") return true;
  if (frame.meta && frame.meta.error) return true;
  return false;
}
function isRawFallbackFrame(frame) {
  if (frame.fields.length !== 1) return false;
  const n = String(frame.fields[0]?.name || "").toLowerCase();
  return n === "raw" || n === "payload";
}
function assertLiveFrames(opts) {
  const {
    frames,
    datasourceUid,
    requiredFields = [],
    requiredBusinessKey,
    minRows = 1
  } = opts;
  if (!datasourceUid || typeof datasourceUid !== "string") {
    throw new LiveAcceptanceError(
      "datasourceUid is required",
      "MISSING_DATASOURCE_UID"
    );
  }
  if (isTestDataUid(datasourceUid)) {
    throw new LiveAcceptanceError(
      `TestData datasource uid rejected: ${datasourceUid}`,
      "TESTDATA_UID"
    );
  }
  if (!Array.isArray(frames) || frames.length === 0) {
    throw new LiveAcceptanceError("no frames returned", "EMPTY_FRAMES");
  }
  let totalRows = 0;
  for (const frame of frames) {
    if (isErrorFrame(frame)) {
      throw new LiveAcceptanceError(
        "error frame is not live acceptance data",
        "ERROR_FRAME"
      );
    }
    if (String(frame.name || "").toLowerCase().includes("random_walk")) {
      throw new LiveAcceptanceError(
        `synthetic frame name rejected: ${frame.name}`,
        "SYNTHETIC_NAME"
      );
    }
    const meta2 = frame.meta || {};
    if (meta2.offline === true) {
      throw new LiveAcceptanceError("offline frame rejected", "OFFLINE_FRAME");
    }
    if (meta2.source != null && meta2.source !== "live") {
      throw new LiveAcceptanceError(
        `frame source must be live, got ${String(meta2.source)}`,
        "NON_LIVE_SOURCE"
      );
    }
    if (meta2.source !== "live") {
      throw new LiveAcceptanceError(
        'frame meta.source must be "live"',
        "MISSING_LIVE_SOURCE"
      );
    }
    const frameUid = String(meta2.datasourceUid ?? meta2.uid ?? "");
    if (frameUid && isTestDataUid(frameUid)) {
      throw new LiveAcceptanceError(
        `TestData frame uid rejected: ${frameUid}`,
        "TESTDATA_UID"
      );
    }
    if (frameUid && frameUid !== datasourceUid) {
      throw new LiveAcceptanceError(
        `frame datasourceUid ${frameUid} does not match expected ${datasourceUid}`,
        "UID_MISMATCH"
      );
    }
    if (isRawFallbackFrame(frame)) {
      throw new LiveAcceptanceError(
        "raw/payload single-column fallback rejected",
        "RAW_FALLBACK"
      );
    }
    const length = frame.length ?? Math.max(0, ...frame.fields.map((f) => f.values?.length ?? 0));
    totalRows += length;
    for (const req of requiredFields) {
      const f = frame.fields.find((x) => x.name === req);
      if (!f) {
        throw new LiveAcceptanceError(
          `missing required field: ${req}`,
          "MISSING_FIELD"
        );
      }
    }
    if (requiredBusinessKey) {
      const values = fieldValues$1(frame, requiredBusinessKey);
      if (!values.length || values.every(isEmptyValue)) {
        throw new LiveAcceptanceError(
          `requiredBusinessKey ${requiredBusinessKey} is empty`,
          "EMPTY_BUSINESS_KEY"
        );
      }
    }
  }
  if (totalRows < minRows) {
    throw new LiveAcceptanceError(
      `expected at least ${minRows} rows, got ${totalRows}`,
      "INSUFFICIENT_ROWS"
    );
  }
}
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  DATASOURCE_IDS,
  DS_TYPE_LABELS,
  LiveAcceptanceError,
  assertLiveFrames,
  buildQueryBodyForType,
  catalogCoversDatasourceIds,
  computeStepMs,
  createBuiltinDataSourceApi,
  createPrometheusDataSource: createPrometheusDataSource$1,
  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 heavyGeomap = false;
let heavyZabbix = false;
let heavySignoz = false;
const heavyInflight = /* @__PURE__ */ new Map();
function registerBuiltinPlugins() {
  if (registered) return;
  registerBuiltinPanels();
  registerBuiltinDataSources();
  registerLiveDashboardBuilders(LIVE_DASHBOARD_BUILDERS);
  registered = true;
  if (listPanelPlugins().length === 0) {
    throw new Error(
      "[grafana-vue] registerBuiltinPlugins registered zero panel plugins"
    );
  }
}
function isBuiltinPluginsRegistered() {
  return registered;
}
async function registerHeavyPlugins(needs = "all") {
  const want = needs === "all" ? { geomap: true, zabbix: true, signoz: true } : {
    geomap: !!needs.geomap,
    zabbix: !!needs.zabbix,
    signoz: !!needs.signoz
  };
  const tasks = [];
  if (want.geomap && !heavyGeomap) {
    const key = "geomap";
    if (!heavyInflight.has(key)) {
      heavyInflight.set(
        key,
        Promise.resolve().then(() => register$2).then(async (m) => {
          await m.registerGeomapPanel();
          heavyGeomap = true;
        })
      );
    }
    tasks.push(heavyInflight.get(key));
  }
  if (want.zabbix && !heavyZabbix) {
    const key = "zabbix";
    if (!heavyInflight.has(key)) {
      heavyInflight.set(
        key,
        Promise.resolve().then(() => index).then(async (m) => {
          await m.ensureDatasourceCatalogEntryRegistered(
            "alexanderzobnin-zabbix-datasource"
          );
          heavyZabbix = true;
        })
      );
    }
    tasks.push(heavyInflight.get(key));
  }
  if (want.signoz && !heavySignoz) {
    const key = "signoz";
    if (!heavyInflight.has(key)) {
      heavyInflight.set(
        key,
        Promise.resolve().then(() => index).then(async (m) => {
          await m.ensureDatasourceCatalogEntryRegistered("signoz");
          heavySignoz = true;
        })
      );
    }
    tasks.push(heavyInflight.get(key));
  }
  await Promise.all(tasks);
}
function isHeavyPluginsRegistered() {
  return heavyGeomap && heavyZabbix && heavySignoz;
}
const __vite_import_meta_env__$1 = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
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 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 resolveObservabilityDataSources(opts = {}) {
  opts.env ?? readEnv();
  const defaults2 = opts.defaults ?? defaultObservabilityDataSources({});
  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,
    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();
  const injected = typeof window !== "undefined" ? window.grafanaBootData : void 0;
  setBootData(injected ?? createDefaultBootData());
  initTheme();
  initPerfFlags();
  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(hash2) {
  if (!hash2 || typeof hash2 !== "string") return null;
  const h2 = hash2.toLowerCase().trim();
  if (!h2.length) return null;
  let even = true;
  let latMin = -90;
  let latMax = 90;
  let lonMin = -180;
  let lonMax = 180;
  for (const ch of h2) {
    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$N = ["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$C = {
  key: 1,
  class: "geomap__legend",
  "data-testid": "geomap-legend"
};
const _hoisted_3$x = {
  key: 2,
  class: "geomap__fallback",
  "data-testid": "geomap-fallback"
};
const _hoisted_4$q = {
  viewBox: "0 0 100 90",
  class: "map",
  preserveAspectRatio: "none",
  role: "img",
  "aria-label": "地理地图回退"
};
const _hoisted_5$k = {
  stroke: "var(--grafana-border-weak)",
  "stroke-width": "0.3",
  opacity: "0.55"
};
const _hoisted_6$i = ["y1", "y2"];
const _hoisted_7$g = ["x1", "x2"];
const _hoisted_8$a = ["cx", "cy", "r", "fill"];
const _hoisted_9$a = ["x", "y"];
const _hoisted_10$8 = {
  key: 3,
  class: "geomap__tooltip",
  "data-testid": "geomap-tooltip"
};
const _hoisted_11$7 = {
  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$6 = {
  key: 6,
  class: "geomap__demo-badge",
  "data-testid": "geomap-demo-badge"
};
const _sfc_main$R = /* @__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 t2 = String(base.config.basemapType);
        return t2 === "default" ? "carto" : t2;
      }
      const b = opts.value.basemap;
      if (typeof b === "string" && b) return b === "default" ? "carto" : b;
      if (b && typeof b === "object" && b.type) {
        const t2 = String(b.type);
        return t2 === "default" || !t2 ? "carto" : t2;
      }
      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 ?? "var(--grafana-primary)"
      )
    );
    const markerBorder = computed(
      () => String(opts.value.config?.border ?? "var(--grafana-primary)")
    );
    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 = [
      "var(--grafana-primary)",
      "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: "var(--grafana-bg-secondary)" }),
              stroke: new ol.Stroke({ color: "var(--grafana-text)", 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: "var(--grafana-warning)", 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: "var(--grafana-warning)" })
          })
        })
      });
      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 pending2 = 0;
            const mark = () => {
              if (pending2 <= 0) tilesReady.value = true;
            };
            src2.on("tileloadstart", () => {
              pending2 += 1;
              tilesReady.value = false;
            });
            src2.on("tileloadend", () => {
              pending2 = Math.max(0, pending2 - 1);
              mark();
            });
            src2.on("tileloaderror", () => {
              pending2 = Math.max(0, pending2 - 1);
              mark();
            });
            setTimeout(() => {
              if (pending2 === 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$C, [
          (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$x, [
          (openBlock(), createElementBlock("svg", _hoisted_4$q, [
            _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": "var(--grafana-bg-canvas)"
                  }),
                  createElementVNode("stop", {
                    offset: "100%",
                    "stop-color": "var(--grafana-bg-secondary)"
                  })
                ])
              ],
              -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$k, [
              (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$i);
                }),
                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$g);
                }),
                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: "var(--grafana-bg-primary)",
                    "stroke-width": "0.3",
                    opacity: "0.85"
                  }, null, 8, _hoisted_8$a),
                  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$a)) : 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$8,
          toDisplayString(hoverLabel.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        opts.value.controls?.showDebug ? (openBlock(), createElementBlock(
          "div",
          _hoisted_11$7,
          " 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$6, " 演示数据 ")) : createCommentVNode("v-if", true),
        createCommentVNode(" Grafana has no footer meta strip; keep data attrs on root for tests ")
      ], 10, _hoisted_1$N);
    };
  }
});
const GeomapRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$R, [["__scopeId", "data-v-815dbb02"]]);
const _sfc_main$Q = /* @__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$M = {
  class: "geomap-layers-editor",
  "data-testid": "geomap-layers-editor"
};
const _hoisted_2$B = { class: "head" };
const _hoisted_3$w = ["data-testid"];
const _hoisted_4$p = { class: "layer-head" };
const _hoisted_5$j = { class: "row" };
const _hoisted_6$h = { class: "row" };
const _hoisted_7$f = {
  key: 0,
  class: "row"
};
const _hoisted_8$9 = { class: "row" };
const _hoisted_9$9 = {
  key: 0,
  class: "row cols"
};
const _hoisted_10$7 = {
  key: 1,
  class: "row"
};
const _hoisted_11$6 = {
  key: 2,
  class: "row cols"
};
const _hoisted_12$6 = {
  key: 3,
  class: "row"
};
const _hoisted_13$6 = { class: "row cols" };
const _hoisted_14$5 = { class: "switch-row" };
const _sfc_main$P = /* @__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$M, [
        createElementVNode("div", _hoisted_2$B, [
          _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$p, [
                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$j, [
                _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$h, [
                    _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$f, [
                    _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$9, [
                    _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$9, [
                    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$7, [
                    _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$6, [
                    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$5, [
                      _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$w);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const GeomapLayersEditor = /* @__PURE__ */ _export_sfc(_sfc_main$P, [["__scopeId", "data-v-eab53cb5"]]);
const plugin$4 = new VuePanelPlugin(
  {
    id: "geomap",
    name: "地理地图",
    description: "OpenLayers 地理可视化",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$Q
).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" }));
const SIGNOZ_I18N_ZH_HANS = {
  "signoz.metrics.selectMetricPlaceholder": "请选择指标",
  "signoz.queryBuilder.addFormula": "添加公式",
  "signoz.queryBuilder.addFunction": "添加函数",
  "signoz.queryBuilder.addOnGroupBy": "分组",
  "signoz.queryBuilder.addOnGroupByDesc": "按一个或多个标签值对结果进行分组",
  "signoz.queryBuilder.addOnHaving": "Having",
  "signoz.queryBuilder.addOnHavingDesc": "按聚合条件过滤结果（例如 sum(metric) >= 100）",
  "signoz.queryBuilder.addOnLegend": "图例",
  "signoz.queryBuilder.addOnLegendDesc": "使用 \\{\\{key\\}\\} 模板占位符自定义图例标签",
  "signoz.queryBuilder.addOnLimit": "限制",
  "signoz.queryBuilder.addOnLimitDesc": "限制返回的最大结果序列数",
  "signoz.queryBuilder.addOnOrderBy": "排序",
  "signoz.queryBuilder.addOnOrderByDesc": "按时间戳或聚合值升序或降序排列结果",
  "signoz.queryBuilder.agg": "聚合",
  "signoz.queryBuilder.attributePlaceholder": "属性...",
  "signoz.queryBuilder.clickhousePlaceholder": "输入 ClickHouse SQL 查询，例如 SELECT toStartOfInterval(...) ...",
  "signoz.queryBuilder.cloneQuery": "克隆查询",
  "signoz.queryBuilder.collapse": "收起",
  "signoz.queryBuilder.expand": "展开",
  "signoz.queryBuilder.formulaExpr": "表达式",
  "signoz.queryBuilder.formulaExprPlaceholder": "例如 A / B * 100",
  "signoz.queryBuilder.functionArg": "函数参数",
  "signoz.queryBuilder.functions": "函数",
  "signoz.queryBuilder.groupBy": "分组",
  "signoz.queryBuilder.having": "Having",
  "signoz.queryBuilder.havingPlaceholder": "例如 COUNT() > 10",
  "signoz.queryBuilder.keyDataType": "数据类型",
  "signoz.queryBuilder.keyType": "类型",
  "signoz.queryBuilder.legend": "图例",
  "signoz.queryBuilder.metricType": "指标类型",
  "signoz.queryBuilder.metricTypeExpHistogram": "ExponentialHistogram",
  "signoz.queryBuilder.metricTypeGauge": "Gauge",
  "signoz.queryBuilder.metricTypeHistogram": "Histogram",
  "signoz.queryBuilder.metricTypeSum": "Sum",
  "signoz.queryBuilder.legendPlaceholder": "\\｛\\｛service.name\\｝\\｝-\\｛\\｛endpoint\\｝\\｝",
  "signoz.queryBuilder.limit": "限制",
  "signoz.queryBuilder.of": "字段",
  "signoz.queryBuilder.orderBy": "排序",
  "signoz.queryBuilder.orderTimestampAsc": "时间 ↑",
  "signoz.queryBuilder.orderTimestampDesc": "时间 ↓",
  "signoz.queryBuilder.orderValueAsc": "值 ↑",
  "signoz.queryBuilder.orderValueDesc": "值 ↓",
  "signoz.queryBuilder.placeholderAll": "一切（无故障）",
  "signoz.queryBuilder.promqlPlaceholder": "输入 PromQL 查询，例如 sum(rate(http_requests_total[5m])) by (service)",
  "signoz.queryBuilder.signal.api_monitoring": "API 监控",
  "signoz.queryBuilder.signal.exceptions": "异常",
  "signoz.queryBuilder.signal.logs": "日志",
  "signoz.queryBuilder.signal.metrics": "指标",
  "signoz.queryBuilder.signal.traces": "链路追踪",
  "signoz.queryBuilder.spaceAgg": "空间聚合",
  "signoz.queryBuilder.step": "步长",
  "signoz.queryBuilder.stepAuto": "自动",
  "signoz.queryBuilder.tabBuilder": "查询构建器",
  "signoz.queryBuilder.tabClickhouse": "ClickHouse 查询",
  "signoz.queryBuilder.tabPromql": "PromQL",
  "signoz.queryBuilder.tagPlaceholder": "标签...",
  "signoz.queryBuilder.timeAgg": "时间聚合",
  "signoz.querySearch.docLinkText": "查看官方文档",
  "signoz.querySearch.error": "加载建议时出错",
  "signoz.querySearch.help": "需要帮助了解搜索语法吗？",
  "signoz.querySearch.loading": "正在加载建议...",
  "signoz.querySearch.noSuggestions": "无可用建议",
  "signoz.querySearch.placeholder": "输入过滤条件查询 (例如 service.name = 'frontend' AND body CONTAINS 'error')",
  "signoz.traces.addQuery": "添加查询",
  "signoz.traces.disableQuery": "禁用",
  "signoz.traces.enableQuery": "启用",
  "signoz.traces.orderBy": "排序方式",
  "signoz.traces.removeQuery": "删除查询"
};
const SIGNOZ_I18N_EN_US = {
  "signoz.metrics.selectMetricPlaceholder": "Select metric",
  "signoz.queryBuilder.addFormula": "Add Formula",
  "signoz.queryBuilder.addFunction": "Add Function",
  "signoz.queryBuilder.addOnGroupBy": "Group By",
  "signoz.queryBuilder.addOnGroupByDesc": "Group results by one or more tag values",
  "signoz.queryBuilder.addOnHaving": "Having",
  "signoz.queryBuilder.addOnHavingDesc": "Filter aggregated results by a condition (e.g. sum(metric) >= 100)",
  "signoz.queryBuilder.addOnLegend": "Legend",
  "signoz.queryBuilder.addOnLegendDesc": "Customize legend labels using \\{\\{key\\}\\} template placeholders",
  "signoz.queryBuilder.addOnLimit": "Limit",
  "signoz.queryBuilder.addOnLimitDesc": "Restrict the maximum number of result series returned",
  "signoz.queryBuilder.addOnOrderBy": "Order By",
  "signoz.queryBuilder.addOnOrderByDesc": "Sort results by timestamp or aggregated value in ascending or descending order",
  "signoz.queryBuilder.agg": "AGG",
  "signoz.queryBuilder.attributePlaceholder": "attribute...",
  "signoz.queryBuilder.clickhousePlaceholder": "Enter ClickHouse SQL query, e.g. SELECT toStartOfInterval(...) ...",
  "signoz.queryBuilder.cloneQuery": "Clone Query",
  "signoz.queryBuilder.collapse": "Collapse",
  "signoz.queryBuilder.expand": "Expand",
  "signoz.queryBuilder.formulaExpr": "Expression",
  "signoz.queryBuilder.formulaExprPlaceholder": "e.g. A / B * 100",
  "signoz.queryBuilder.functionArg": "Function arg",
  "signoz.queryBuilder.functions": "Functions",
  "signoz.queryBuilder.groupBy": "GROUP BY",
  "signoz.queryBuilder.having": "HAVING",
  "signoz.queryBuilder.havingPlaceholder": "e.g. COUNT() > 10",
  "signoz.queryBuilder.keyDataType": "Data type",
  "signoz.queryBuilder.keyType": "Type",
  "signoz.queryBuilder.legend": "LEGEND",
  "signoz.queryBuilder.metricType": "Metric type",
  "signoz.queryBuilder.metricTypeExpHistogram": "ExponentialHistogram",
  "signoz.queryBuilder.metricTypeGauge": "Gauge",
  "signoz.queryBuilder.metricTypeHistogram": "Histogram",
  "signoz.queryBuilder.metricTypeSum": "Sum",
  "signoz.queryBuilder.legendPlaceholder": "\\｛\\｛service.name\\｝\\｝-\\｛\\｛endpoint\\｝\\｝",
  "signoz.queryBuilder.limit": "LIMIT",
  "signoz.queryBuilder.of": "OF",
  "signoz.queryBuilder.orderBy": "ORDER BY",
  "signoz.queryBuilder.orderTimestampAsc": "Timestamp ↑",
  "signoz.queryBuilder.orderTimestampDesc": "Timestamp ↓",
  "signoz.queryBuilder.orderValueAsc": "Value ↑",
  "signoz.queryBuilder.orderValueDesc": "Value ↓",
  "signoz.queryBuilder.placeholderAll": "一切（无故障）",
  "signoz.queryBuilder.promqlPlaceholder": "Enter PromQL query, e.g. sum(rate(http_requests_total[5m])) by (service)",
  "signoz.queryBuilder.signal.api_monitoring": "API Monitoring",
  "signoz.queryBuilder.signal.exceptions": "Exceptions",
  "signoz.queryBuilder.signal.logs": "Logs",
  "signoz.queryBuilder.signal.metrics": "Metrics",
  "signoz.queryBuilder.signal.traces": "Traces",
  "signoz.queryBuilder.spaceAgg": "SPACE AGG",
  "signoz.queryBuilder.step": "STEP",
  "signoz.queryBuilder.stepAuto": "Auto",
  "signoz.queryBuilder.tabBuilder": "Query Builder",
  "signoz.queryBuilder.tabClickhouse": "ClickHouse Query",
  "signoz.queryBuilder.tabPromql": "PromQL",
  "signoz.queryBuilder.tagPlaceholder": "tag...",
  "signoz.queryBuilder.timeAgg": "TIME AGG",
  "signoz.querySearch.docLinkText": "View documentation",
  "signoz.querySearch.error": "Error loading suggestions",
  "signoz.querySearch.help": "Need help with search syntax?",
  "signoz.querySearch.loading": "Loading suggestions...",
  "signoz.querySearch.noSuggestions": "No suggestions available",
  "signoz.querySearch.placeholder": "Enter your filter query (e.g., service.name = 'frontend' AND body CONTAINS 'error')",
  "signoz.traces.addQuery": "Add Query",
  "signoz.traces.disableQuery": "Disable",
  "signoz.traces.enableQuery": "Enable",
  "signoz.traces.orderBy": "Order by",
  "signoz.traces.removeQuery": "Remove query"
};
Object.freeze(
  Object.keys(SIGNOZ_I18N_ZH_HANS).sort()
);
function registerSigNozI18nCatalogs() {
  registerI18nCatalog("zh-Hans", SIGNOZ_I18N_ZH_HANS);
  registerI18nCatalog("en-US", SIGNOZ_I18N_EN_US);
}
async function registerSigNozPlugin() {
  registerSigNozI18nCatalogs();
  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$4(v) {
  try {
    return structuredClone(v);
  } catch {
    return JSON.parse(JSON.stringify(v));
  }
}
function nextRefId(targets) {
  const used = new Set(targets.map((t2) => t2.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$4(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 t2 = panel2.targets[key];
        panel2.targets[key] = { ...getDefaultTarget(), ...t2 };
      }
    } else if (Array.isArray(panel2.targets)) {
      panel2.targets = panel2.targets.map((t2) => ({
        ...getDefaultTarget(panel2.targets),
        ...t2
      }));
    }
  }
  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((h2) => ({
    hostid: String(h2.hostid ?? h2.id ?? ""),
    name: String(h2.name ?? h2.host ?? ""),
    host: String(h2.host ?? h2.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(
          (t2) => typeof t2 === "string" ? { tag: t2, value: "" } : { tag: String(t2.tag ?? ""), value: String(t2.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$L = ["data-status", "data-ack"];
const _sfc_main$O = /* @__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$L);
    };
  }
});
const ProblemStatus = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-0240222c"]]);
const _hoisted_1$K = ["data-testid"];
const _hoisted_2$A = ["href"];
const _hoisted_3$v = { key: 1 };
const _sfc_main$N = /* @__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$34), {
                  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$A)) : (openBlock(), createElementBlock("span", _hoisted_3$v, [
                      createVNode(unref(GIcon), {
                        name: ic.icon
                      }, null, 8, ["name"])
                    ]))
                  ]),
                  _: 2
                  /* DYNAMIC */
                }, 1032, ["title"])
              ], 8, _hoisted_1$K);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ],
        2
        /* CLASS */
      );
    };
  }
});
const ProblemStatusBar = /* @__PURE__ */ _export_sfc(_sfc_main$N, [["__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$J = {
  class: "tbl",
  "data-testid": "problems-table"
};
const _hoisted_2$z = ["data-col", "onClick"];
const _hoisted_3$u = ["onMousedown"];
const _hoisted_4$o = ["data-testid", "onClick"];
const _hoisted_5$i = {
  key: 0,
  class: "sub"
};
const _hoisted_6$g = ["title"];
const _hoisted_7$e = ["onClick"];
const _hoisted_8$8 = ["onClick"];
const _hoisted_9$8 = ["onClick"];
const _hoisted_10$6 = ["onClick"];
const _hoisted_11$5 = ["onClick"];
const _hoisted_12$5 = ["onClick"];
const _hoisted_13$5 = ["onClick"];
const _hoisted_14$4 = ["onClick"];
const _hoisted_15$4 = {
  class: "pager",
  "data-testid": "problems-pager"
};
const _hoisted_16$3 = ["disabled"];
const _hoisted_17$3 = ["disabled"];
const _hoisted_18$3 = ["value"];
const _hoisted_19$3 = ["value"];
const _sfc_main$M = /* @__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) {
      const background = severityMap.value.get(n)?.color || "#999999";
      return {
        background,
        color: getContrastText(background)
      };
    }
    function hostLabel(p) {
      return p.hosts.map((h2) => h2.name || h2.host).join(", ");
    }
    function hostTech(p) {
      return p.hosts.map((h2) => h2.host || h2.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 formatTime2(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((t2) => t2.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$J, [
            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$u)
                    ], 14, _hoisted_2$z);
                  }),
                  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(formatTime2(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$i,
                                  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$g)) : c.key === "tags" ? (openBlock(true), createElementBlock(
                              Fragment,
                              { key: 12 },
                              renderList(p.tags, (t2) => {
                                return openBlock(), createElementBlock("button", {
                                  key: t2.tag + t2.value,
                                  type: "button",
                                  class: "tag",
                                  onClick: withModifiers(($event) => onTagClick($event, t2.tag, t2.value, p), ["stop"])
                                }, toDisplayString(t2.tag) + toDisplayString(t2.value ? ":" + t2.value : ""), 9, _hoisted_7$e);
                              }),
                              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$8)) : 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$8)) : 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$6)) : 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$5)) : 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$4)) : createCommentVNode("v-if", true)
                            ])) : createCommentVNode("v-if", true)
                          ],
                          4
                          /* STYLE */
                        );
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ], 14, _hoisted_4$o);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])
          ]),
          createElementVNode("div", _hoisted_15$4, [
            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$3),
            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$3),
            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$3);
                }),
                64
                /* STABLE_FRAGMENT */
              ))
            ], 40, _hoisted_18$3)
          ])
        ],
        4
        /* STYLE */
      );
    };
  }
});
const ProblemsTable = /* @__PURE__ */ _export_sfc(_sfc_main$M, [["__scopeId", "data-v-f3b68a3e"]]);
const _sfc_main$L = /* @__PURE__ */ defineComponent({
  __name: "SeverityBadge",
  props: {
    severity: {},
    label: {},
    color: {}
  },
  setup(__props) {
    const props = __props;
    const style = computed(() => {
      const background = props.color || "var(--grafana-text-secondary)";
      const color = typeof background === "string" && background.startsWith("#") ? getContrastText(background) : "var(--grafana-text-max-contrast)";
      return { background, color };
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "span",
        {
          class: "sev",
          "data-testid": "severity-badge",
          style: normalizeStyle(style.value)
        },
        toDisplayString(__props.label ?? __props.severity),
        5
        /* TEXT, STYLE */
      );
    };
  }
});
const SeverityBadge = /* @__PURE__ */ _export_sfc(_sfc_main$L, [["__scopeId", "data-v-f83bedf7"]]);
const _hoisted_1$I = ["data-testid", "onClick"];
const _hoisted_2$y = { class: "name" };
const _hoisted_3$t = { class: "meta" };
const _hoisted_4$n = {
  key: 0,
  class: "maint",
  title: "维护中",
  "data-testid": "maintenance-icon"
};
const _hoisted_5$h = ["href"];
const _hoisted_6$f = {
  key: 2,
  class: "acks"
};
const _sfc_main$K = /* @__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$y,
                  toDisplayString(p.name),
                  1
                  /* TEXT */
                ),
                createElementVNode(
                  "span",
                  _hoisted_3$t,
                  toDisplayString(p.hosts.map((h2) => h2.name || h2.host).join(", ")),
                  1
                  /* TEXT */
                ),
                p.hostInMaintenance ? (openBlock(), createElementBlock("span", _hoisted_4$n, "🔧")) : 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$h)) : createCommentVNode("v-if", true),
                p.acknowledges.length ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_6$f,
                  "确认 " + toDisplayString(p.acknowledges.length),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ], 14, _hoisted_1$I);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ],
        4
        /* STYLE */
      );
    };
  }
});
const ProblemsList = /* @__PURE__ */ _export_sfc(_sfc_main$K, [["__scopeId", "data-v-56c0cde8"]]);
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 t2 = String(tag).toLowerCase();
    if (!ALLOWED_TAGS.has(t2)) return "";
    if (full.startsWith("</")) return `</${t2}>`;
    if (t2 === "br") return "<br/>";
    return `<${t2}>`;
  });
  return s;
}
const _hoisted_1$H = {
  class: "tl-wrap",
  "data-testid": "problem-timeline",
  "aria-label": "问题时间线"
};
const _hoisted_2$x = ["viewBox"];
const _hoisted_3$s = ["x", "width", "fill", "data-testid"];
const _hoisted_4$m = ["cx", "fill"];
const _hoisted_5$g = {
  key: 1,
  class: "empty",
  "data-testid": "timeline-empty"
};
const width = 480;
const height = 36;
const _sfc_main$J = /* @__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 clock2 = raw < 1e12 ? raw * 1e3 : raw;
        const value = Number(e.value ?? 1);
        return {
          clock: clock2,
          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 kind2 = 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: kind2,
          title: `${kind2 === "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$H, [
        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: "var(--grafana-bg-secondary)",
            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$s);
            }),
            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$m);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 8, _hoisted_2$x)) : (openBlock(), createElementBlock("p", _hoisted_5$g, "无事件时间线"))
      ]);
    };
  }
});
const ProblemTimeline = /* @__PURE__ */ _export_sfc(_sfc_main$J, [["__scopeId", "data-v-3e10d74c"]]);
const _hoisted_1$G = {
  key: 0,
  class: "acks",
  "data-testid": "problem-acks"
};
const _hoisted_2$w = {
  key: 1,
  class: "empty",
  "data-testid": "problem-acks-empty"
};
const _sfc_main$I = /* @__PURE__ */ defineComponent({
  __name: "ProblemAcknowledges",
  props: {
    items: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return __props.items?.length ? (openBlock(), createElementBlock("ul", _hoisted_1$G, [
        (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$w, "暂无确认记录"));
    };
  }
});
const ProblemAcknowledges = /* @__PURE__ */ _export_sfc(_sfc_main$I, [["__scopeId", "data-v-83362a58"]]);
const _hoisted_1$F = {
  class: "tags",
  "data-testid": "tag-list"
};
const _sfc_main$H = /* @__PURE__ */ defineComponent({
  __name: "TagList",
  props: {
    tags: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("span", _hoisted_1$F, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.tags, (t2) => {
            return openBlock(), createElementBlock(
              "span",
              {
                key: t2.tag + t2.value,
                class: "tag"
              },
              toDisplayString(t2.tag) + toDisplayString(t2.value ? ":" + t2.value : ""),
              1
              /* TEXT */
            );
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const TagList = /* @__PURE__ */ _export_sfc(_sfc_main$H, [["__scopeId", "data-v-3e64e7ec"]]);
const _hoisted_1$E = {
  class: "details",
  "data-testid": "problem-details",
  role: "dialog",
  "aria-label": "问题详情"
};
const _hoisted_2$v = { "data-testid": "problem-eventid" };
const _hoisted_3$r = {
  key: 1,
  "data-testid": "problem-hosts"
};
const _hoisted_4$l = {
  key: 2,
  "data-testid": "problem-groups"
};
const _hoisted_5$f = {
  key: 3,
  "data-testid": "problem-tags"
};
const _hoisted_6$e = ["innerHTML"];
const _hoisted_7$d = {
  key: 5,
  "data-testid": "problem-opdata"
};
const _hoisted_8$7 = { "data-testid": "problem-expression" };
const _hoisted_9$7 = {
  key: 6,
  "data-testid": "problem-hist-value"
};
const _hoisted_10$5 = { "data-testid": "problem-manual-close" };
const _hoisted_11$4 = { "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$3 = { key: 0 };
const _hoisted_15$3 = {
  key: 1,
  class: "empty"
};
const _hoisted_16$2 = {
  "data-testid": "problem-alerts",
  class: "block"
};
const _hoisted_17$2 = {
  key: 0,
  class: "plain"
};
const _hoisted_18$2 = {
  key: 1,
  class: "empty"
};
const _hoisted_19$2 = {
  "data-testid": "problem-events",
  class: "block"
};
const _hoisted_20$2 = {
  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$G = /* @__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((h2) => h2.name || h2.host).filter(Boolean).join(", ")
    );
    const suppressionRows = computed(() => props.problem.suppression || []);
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("aside", _hoisted_1$E, [
        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$v,
          "Event: " + toDisplayString(__props.problem.eventid),
          1
          /* TEXT */
        ),
        __props.options.hostField ? (openBlock(), createElementBlock(
          "p",
          _hoisted_3$r,
          " 主机: " + toDisplayString(hostLabel.value || "—"),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        __props.options.hostGroups || __props.problem.groups.length ? (openBlock(), createElementBlock(
          "p",
          _hoisted_4$l,
          " 组: " + 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$f, [
          _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$e)) : createCommentVNode("v-if", true),
        __props.options.opdataField || __props.problem.opdata ? (openBlock(), createElementBlock(
          "p",
          _hoisted_7$d,
          " 运维数据: " + toDisplayString(__props.problem.opdata || "—"),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode(
          "p",
          _hoisted_8$7,
          " 表达式: " + toDisplayString(__props.problem.expression || "—"),
          1
          /* TEXT */
        ),
        __props.problem.historicalItemValue != null ? (openBlock(), createElementBlock(
          "p",
          _hoisted_9$7,
          " 历史值: " + toDisplayString(__props.problem.historicalItemValue),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode(
          "p",
          _hoisted_10$5,
          " 手动关闭: " + toDisplayString(__props.problem.manual_close === "1" || __props.problem.manual_close === true ? "允许" : "否"),
          1
          /* TEXT */
        ),
        createElementVNode(
          "p",
          _hoisted_11$4,
          " 抑制: " + 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$3,
                    "= " + toDisplayString(it.lastvalue),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : (openBlock(), createElementBlock("p", _hoisted_15$3, "无关联监控项"))
        ]),
        createElementVNode("section", _hoisted_16$2, [
          createElementVNode(
            "h5",
            null,
            "告警 (" + toDisplayString(__props.problem.alerts.length) + ")",
            1
            /* TEXT */
          ),
          __props.problem.alerts.length ? (openBlock(), createElementBlock("ul", _hoisted_17$2, [
            (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$2, "无告警记录"))
        ]),
        createElementVNode("section", _hoisted_19$2, [
          createElementVNode(
            "h5",
            null,
            "事件 (" + toDisplayString(__props.problem.events.length) + ")",
            1
            /* TEXT */
          ),
          __props.problem.events.length ? (openBlock(), createElementBlock("ul", _hoisted_20$2, [
            (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$G, [["__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$D = {
  key: 0,
  class: "modal",
  "data-testid": "ack-modal",
  role: "dialog"
};
const _hoisted_2$u = { class: "row" };
const _hoisted_3$q = { class: "row" };
const _hoisted_4$k = {
  key: 0,
  class: "sev-radios",
  "data-testid": "ack-modal-sev-radios"
};
const _hoisted_5$e = ["value", "data-testid"];
const _hoisted_6$d = {
  key: 1,
  class: "row"
};
const _hoisted_7$c = {
  key: 2,
  class: "hint",
  "data-testid": "ack-modal-close-blocked"
};
const _hoisted_8$6 = {
  class: "hint",
  "data-testid": "ack-modal-mask"
};
const _hoisted_9$6 = { key: 1 };
const _hoisted_10$4 = { key: 2 };
const _sfc_main$F = /* @__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$D, [
        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$u, [
              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$q, [
              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$k, [
              (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$e), [
                      [
                        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$d, [
              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$c, " 当前触发器不允许手动关闭 ")),
            createElementVNode(
              "p",
              _hoisted_8$6,
              " action mask = " + toDisplayString(compositeMask()),
              1
              /* TEXT */
            )
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        __props.mode === "changeSeverity" && !isComposite.value ? (openBlock(), createElementBlock("label", _hoisted_9$6, [
          _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$4, [
          _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$F, [["__scopeId", "data-v-576aeb6b"]]);
const _hoisted_1$C = {
  key: 0,
  class: "modal",
  "data-testid": "script-modal",
  role: "dialog"
};
const _hoisted_2$t = {
  key: 0,
  "data-testid": "script-modal-loading"
};
const _hoisted_3$p = {
  key: 1,
  class: "err",
  "data-testid": "script-modal-error"
};
const _hoisted_4$j = ["value"];
const _hoisted_5$d = {
  key: 0,
  class: "empty",
  "data-testid": "script-modal-empty"
};
const _hoisted_6$c = {
  key: 1,
  class: "meta",
  "data-testid": "script-modal-meta"
};
const _hoisted_7$b = { key: 0 };
const _hoisted_8$5 = { class: "actions" };
const _hoisted_9$5 = ["disabled"];
const _sfc_main$E = /* @__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$C, [
        createElementVNode(
          "p",
          null,
          "对 " + toDisplayString(__props.problem.hosts[0]?.name || __props.problem.eventid) + " 执行脚本",
          1
          /* TEXT */
        ),
        loading.value ? (openBlock(), createElementBlock("p", _hoisted_2$t, " 正在加载 script.get… ")) : loadError.value ? (openBlock(), createElementBlock(
          "p",
          _hoisted_3$p,
          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$j);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ],
                512
                /* NEED_PATCH */
              ), [
                [vModelSelect, selectedId.value]
              ])
            ]),
            !scripts.value.length ? (openBlock(), createElementBlock("p", _hoisted_5$d, " 无可用脚本 ")) : createCommentVNode("v-if", true),
            selected.value ? (openBlock(), createElementBlock("dl", _hoisted_6$c, [
              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$b, [
                _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$5, [
          createElementVNode("button", {
            type: "button",
            "data-testid": "script-modal-ok",
            disabled: !selectedId.value,
            onClick: onConfirm
          }, " 执行 ", 8, _hoisted_9$5),
          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$E, [["__scopeId", "data-v-900744b2"]]);
const _hoisted_1$B = { class: "toolbar" };
const _hoisted_2$s = {
  key: 0,
  class: "error",
  role: "alert"
};
const _hoisted_3$o = {
  key: 1,
  class: "ok",
  role: "status"
};
const _hoisted_4$i = {
  key: 2,
  class: "empty",
  "data-testid": "problems-empty"
};
const _hoisted_5$c = {
  key: 5,
  class: "pager"
};
const _hoisted_6$b = ["disabled"];
const _hoisted_7$a = ["disabled"];
const _sfc_main$D = /* @__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$B, [
            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$s,
            toDisplayString(actionError.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          actionOk.value ? (openBlock(), createElementBlock(
            "div",
            _hoisted_3$o,
            toDisplayString(actionOk.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          !problems.value.length ? (openBlock(), createElementBlock("div", _hoisted_4$i, " 当前筛选条件下没有 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$c, [
            createElementVNode("button", {
              type: "button",
              disabled: page.value === 0,
              "data-testid": "problems-prev",
              onClick: _cache[10] || (_cache[10] = ($event) => page.value--)
            }, " 上一页 ", 8, _hoisted_6$b),
            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$a)
          ])) : 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$D, [["__scopeId", "data-v-a4b2e9d4"]]);
const _hoisted_1$A = {
  class: "sev-editor",
  "data-testid": "severity-color-editor"
};
const _hoisted_2$r = ["data-testid"];
const _hoisted_3$n = { class: "name" };
const _sfc_main$C = /* @__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$A, [
        (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$n,
                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(GSwitch), {
                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$r);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const SeverityColorEditor = /* @__PURE__ */ _export_sfc(_sfc_main$C, [["__scopeId", "data-v-1337e1ed"]]);
const _hoisted_1$z = {
  class: "reset-cols",
  "data-testid": "reset-columns-editor"
};
const _hoisted_2$q = {
  key: 0,
  class: "hint"
};
const _sfc_main$B = /* @__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$z, [
        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$q,
          "已自定义 " + toDisplayString(__props.value.length) + " 列",
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const ResetColumnsEditor = /* @__PURE__ */ _export_sfc(_sfc_main$B, [["__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$3(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$3(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$3(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$3(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$3(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 t2 = this.queue.splice(i, 1)[0];
        t2.controller.abort();
        t2.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 t2 of this.queue) {
        t2.controller.abort();
        t2.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 = shallowRef([]);
  const loading = ref(false);
  const error = ref("");
  const stale = ref(false);
  let sequence = 0;
  let controller = null;
  let debounceTimer = null;
  let staleRetryTimer = null;
  let staleRetries = 0;
  let alive = true;
  const debounceMs = opts.debounceMs ?? 0;
  let localRevision = 0;
  const MAX_STALE_RETRIES = Math.max(0, opts.maxStaleRetries ?? 5);
  function resolveScheduler() {
    const s = opts.scheduler;
    if (!s) return void 0;
    return typeof s === "function" ? s() : s;
  }
  function clearStaleRetry() {
    if (staleRetryTimer) {
      clearTimeout(staleRetryTimer);
      staleRetryTimer = null;
    }
  }
  function scheduleStaleRetry(fromSequence) {
    if (!alive) return;
    if (staleRetries >= MAX_STALE_RETRIES) return;
    if (opts.canLoad && !opts.canLoad()) return;
    clearStaleRetry();
    staleRetries += 1;
    staleRetryTimer = setTimeout(() => {
      staleRetryTimer = null;
      if (!alive || fromSequence !== sequence) return;
      if (opts.canLoad && !opts.canLoad()) return;
      void runLoad("refresh");
    }, 50);
  }
  async function runLoad(priority = "refresh") {
    if (opts.canLoad && !opts.canLoad()) {
      options.value = [];
      loading.value = false;
      error.value = "";
      stale.value = false;
      staleRetries = 0;
      clearStaleRetry();
      return;
    }
    const current = ++sequence;
    loading.value = true;
    error.value = "";
    stale.value = false;
    clearStaleRetry();
    try {
      let rows;
      const scheduler = resolveScheduler();
      if (scheduler && opts.owner) {
        localRevision += 1;
        const revision = localRevision;
        const result = await 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;
          }
          stale.value = true;
          scheduleStaleRetry(current);
          return;
        }
        rows = result;
      } else {
        controller?.abort();
        controller = new AbortController();
        rows = await load(controller.signal);
      }
      if (current === sequence) {
        options.value = Array.isArray(rows) ? markRaw(rows) : [];
        staleRetries = 0;
      }
    } catch (cause) {
      if (current === sequence) {
        const err = cause;
        if (err?.name !== "AbortError") {
          error.value = err instanceof Error ? err.message : String(cause);
        } else if (!opts.canLoad || opts.canLoad()) {
          stale.value = true;
          scheduleStaleRetry(current);
        }
      }
    } 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";
    staleRetries = 0;
    clearStaleRetry();
    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;
    }
    staleRetries = 0;
    clearStaleRetry();
    void runLoad("interactive");
  }
  function cancel() {
    if (debounceTimer) {
      clearTimeout(debounceTimer);
      debounceTimer = null;
    }
    clearStaleRetry();
    controller?.abort();
    const scheduler = resolveScheduler();
    if (scheduler && opts.owner) scheduler.cancel(opts.owner);
  }
  onBeforeUnmount(() => {
    alive = false;
    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$y = {
  class: "zbx-fn",
  "data-testid": "zabbix-functions"
};
const _hoisted_2$p = { class: "row add-row" };
const _hoisted_3$m = ["data-testid"];
const _hoisted_4$h = { class: "fn-main" };
const _hoisted_5$b = ["title"];
const _hoisted_6$a = {
  class: "fn-toolbar",
  "data-testid": "fn-toolbar"
};
const _sfc_main$A = /* @__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$y, [
        _cache[4] || (_cache[4] = createElementVNode(
          "span",
          {
            hidden: "",
            "data-testid": "zabbix-function-editor"
          },
          null,
          -1
          /* CACHED */
        )),
        createElementVNode("div", _hoisted_2$p, [
          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$h, [
                createElementVNode("strong", {
                  title: fn.text || fn.name,
                  class: normalizeClass({ "fn-name--error": unknownDef(fn.name) })
                }, toDisplayString(fn.name), 11, _hoisted_5$b),
                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$a, [
                createVNode(
                  unref(_sfc_main$34),
                  { 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$34),
                  { 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$34),
                  { 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$m);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const FunctionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$A, [["__scopeId", "data-v-ea345298"]]);
const _hoisted_1$x = {
  class: "host-tag-editor",
  "data-testid": "zabbix-host-tag-editor"
};
const _hoisted_2$o = { class: "toolbar" };
const _hoisted_3$l = ["data-testid"];
const _sfc_main$z = /* @__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(
        (t2, j) => j === i ? { ...t2, ...partial } : t2
      );
      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$x, [
        createElementVNode("div", _hoisted_2$o, [
          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 || [], (t2, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: "host-tag-row",
              "data-testid": `zabbix-host-tag-row-${i}`
            }, [
              createVNode(unref(GSelect), {
                value: t2.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: t2.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(t2.operator)) ? (openBlock(), createBlock(unref(GInput), {
                key: 0,
                "model-value": t2.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$l);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const HostTagQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$z, [["__scopeId", "data-v-7aa10521"]]);
const _hoisted_1$w = ["for"];
const _hoisted_2$n = { class: "inline-field__text" };
const _hoisted_3$k = {
  class: "inline-field__tip",
  "aria-hidden": "true"
};
const _hoisted_4$g = { class: "inline-field__control" };
const _sfc_main$y = /* @__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$n,
              toDisplayString(__props.label),
              1
              /* TEXT */
            ),
            __props.tooltip ? (openBlock(), createBlock(unref(_sfc_main$34), {
              key: 0,
              title: __props.tooltip
            }, {
              default: withCtx(() => [
                createElementVNode("span", _hoisted_3$k, [
                  createVNode(unref(GIcon), { name: "info-circle" })
                ])
              ]),
              _: 1
              /* STABLE */
            }, 8, ["title"])) : createCommentVNode("v-if", true)
          ], 12, _hoisted_1$w),
          createElementVNode("div", _hoisted_4$g, [
            renderSlot(_ctx.$slots, "default", {}, void 0, true)
          ])
        ],
        2
        /* CLASS */
      );
    };
  }
});
const InlineField = /* @__PURE__ */ _export_sfc(_sfc_main$y, [["__scopeId", "data-v-b1be77e5"]]);
const _hoisted_1$v = {
  class: "inline-field-row",
  "data-testid": "zabbix-inline-field-row"
};
const _sfc_main$x = /* @__PURE__ */ defineComponent({
  __name: "InlineFieldRow",
  props: {
    filler: { type: Boolean, default: true },
    fillerWidth: { default: 10 }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$v, [
        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$x, [["__scopeId", "data-v-e9095d9e"]]);
const _hoisted_1$u = {
  class: "lld",
  "data-testid": "zabbix-lld-selector"
};
const _hoisted_2$m = {
  key: 0,
  class: "hint",
  "data-testid": "zabbix-lld-loading"
};
const _hoisted_3$j = {
  key: 1,
  class: "hint",
  "data-testid": "zabbix-lld-empty"
};
const _hoisted_4$f = {
  key: 2,
  class: "err",
  "data-testid": "zabbix-lld-error"
};
const _sfc_main$w = /* @__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$u, [
        _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$m, " 加载中… ")) : !unref(rulesMeta).loading.value && __props.hostids.length && !ruleOptions.value.length ? (openBlock(), createElementBlock("p", _hoisted_3$j, " 无发现规则 ")) : createCommentVNode("v-if", true),
        rulesError.value || protosError.value ? (openBlock(), createElementBlock("p", _hoisted_4$f, [
          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$w, [["__scopeId", "data-v-31767cc1"]]);
const _hoisted_1$t = ["data-testid"];
const _hoisted_2$l = {
  key: 0,
  class: "lbl"
};
const _hoisted_3$i = {
  key: 1,
  class: "hint",
  role: "status"
};
const _hoisted_4$e = ["data-testid"];
const VIRTUAL_THRESHOLD = 200;
const _sfc_main$v = /* @__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 useVirtual = computed(
      () => (props.options?.length ?? 0) >= VIRTUAL_THRESHOLD
    );
    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, useVirtual });
    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$l,
          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$i, "加载中…")) : 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$e)) : createCommentVNode("v-if", true)
      ], 10, _hoisted_1$t);
    };
  }
});
const MetricPicker = /* @__PURE__ */ _export_sfc(_sfc_main$v, [["__scopeId", "data-v-bd25541f"]]);
const _hoisted_1$s = {
  class: "fields",
  "data-testid": "zabbix-fields-metrics"
};
const _sfc_main$u = /* @__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 groupRevision = ref(0);
    function schedulerForUid() {
      return getZabbixMetadataScheduler(String(props.datasourceUid || "default"));
    }
    function hasGroupScope() {
      return (props.query.group?.ids?.length ?? 0) > 0 || Boolean(String(props.query.group?.filter || "").trim());
    }
    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: schedulerForUid,
        owner: "group",
        canLoad: () => Boolean(api.value),
        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: schedulerForUid,
        owner: "host",
        // Freeform / variable group filters (/.*/, $Group) must arm host.get without group ids.
        // Require api so a null-api empty success does not permanently skip host.get.
        canLoad: () => Boolean(api.value) && hasGroupScope(),
        parents: () => ({
          groupIds: props.query.group?.ids || [],
          scope: (props.query.group?.ids?.length ?? 0) > 0 ? "scoped" : hasGroupScope() ? "all" : "scoped"
        }),
        requestKey: () => `hosts:${(props.query.group?.ids || []).join(",")}|${props.query.group?.filter || ""}`,
        // Slow host.get + suite load: allow more abort retries than the default 5.
        maxStaleRetries: 20
      }
    );
    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: schedulerForUid,
        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 t2 of rawTags) {
                const key = `${t2.tag}: ${t2.value}`;
                tags.set(key, key);
              }
            }
          }
          if (tags.size)
            itemTagOptions.value = [...tags.values()].map((v) => ({
              label: v,
              value: v
            }));
          return res.values;
        }
        return [];
      },
      {
        scheduler: schedulerForUid,
        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((t2) => `${t2.tag ?? t2.key ?? ""}=${t2.value ?? ""}`).join("|")
      ],
      () => {
        const sched = schedulerForUid();
        groupRevision.value = sched.invalidateFrom(
          "group",
          groupRevision.value + 1
        );
        groups.refresh({ revision: groupRevision.value });
        hosts.refresh({
          revision: groupRevision.value,
          priority: "interactive"
        });
      }
    );
    function kickMetadata(priority = "refresh") {
      if (!api.value) return;
      const sched = schedulerForUid();
      groupRevision.value = sched.invalidateFrom(
        "group",
        groupRevision.value + 1
      );
      groups.refresh({ revision: groupRevision.value, priority });
      hosts.refresh({
        revision: groupRevision.value,
        priority: hasGroupScope() ? "interactive" : priority
      });
    }
    function kickHostsOnly(priority = "interactive") {
      if (!api.value) return;
      if (!hasGroupScope()) return;
      hosts.refresh({ priority });
    }
    onMounted(() => {
      nextTick(() => {
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            const ric = globalThis.requestIdleCallback;
            if (typeof ric === "function") ric(() => kickMetadata("refresh"), { timeout: 400 });
            else setTimeout(() => kickMetadata("refresh"), 0);
            const rearm = () => kickHostsOnly("interactive");
            setTimeout(rearm, 400);
            setTimeout(rearm, 900);
            setTimeout(rearm, 1800);
            setTimeout(rearm, 3200);
          });
        });
      });
    });
    watch(
      () => [props.datasourceUid, props.datasourceApi, Boolean(api.value)],
      ([, , ready], prev) => {
        const wasReady = Boolean(prev?.[2]);
        if (!ready || wasReady) return;
        kickMetadata("interactive");
      }
    );
    watch(
      () => hasGroupScope(),
      (ok2) => {
        if (ok2) kickHostsOnly("interactive");
      },
      { immediate: true }
    );
    watch(
      () => [props.query.host?.filter, props.query.host?.ids?.join(",")],
      () => {
        const rev = schedulerForUid().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 ?? "")
      }));
    }
    const groupPickerOptions = computed(() => toOptions(groups.options.value));
    const hostPickerOptions = computed(() => toOptions(hosts.options.value));
    const applicationPickerOptions = computed(
      () => toOptions(applications.options.value)
    );
    const itemPickerOptions = computed(() => toOptions(items.options.value));
    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 t2 = String(token || "").trim();
      if (!t2) return { filter: "" };
      if (t2.startsWith("/") || t2.startsWith("$") || t2 === "/.*/")
        return freeformToFilter(t2);
      const opt = findOption(list, t2);
      if (opt) {
        const next = optionToFilter(opt);
        return next.ids?.length ? next : { filter: next.filter, name: next.name };
      }
      return freeformToFilter(t2);
    }
    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$s, [
        _cache[7] || (_cache[7] = createStaticVNode('<span hidden data-testid="zabbix-functions" data-v-2eb05c92></span><span hidden data-testid="zabbix-cascade-filters" data-v-2eb05c92></span><span hidden data-testid="zabbix-group" data-v-2eb05c92></span><span hidden data-testid="zabbix-host" data-v-2eb05c92></span><span hidden data-testid="zabbix-application" data-v-2eb05c92></span><span hidden data-testid="zabbix-itemTag" data-v-2eb05c92></span><span hidden data-testid="zabbix-item" data-v-2eb05c92></span>', 7)),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Group",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.group),
                  options: groupPickerOptions.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: hostPickerOptions.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: applicationPickerOptions.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: itemPickerOptions.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, {
                  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$u, [["__scopeId", "data-v-2eb05c92"]]);
const _hoisted_1$r = ["data-testid"];
const _hoisted_2$k = {
  key: 0,
  class: "lbl"
};
const _hoisted_3$h = {
  key: 1,
  class: "hint",
  role: "status"
};
const _sfc_main$t = /* @__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;
    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 });
    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
      }))
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "filter-picker",
        "data-testid": __props.testId
      }, [
        __props.label ? (openBlock(), createElementBlock(
          "label",
          _hoisted_2$k,
          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$h, "加载中…")) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$r);
    };
  }
});
const FilterPicker = /* @__PURE__ */ _export_sfc(_sfc_main$t, [["__scopeId", "data-v-00870a55"]]);
const _hoisted_1$q = {
  class: "cascade",
  "data-testid": "zabbix-cascade-filters"
};
const _sfc_main$s = /* @__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$q, [
        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$s, [["__scopeId", "data-v-bc850fdd"]]);
const _hoisted_1$p = {
  class: "fields",
  "data-testid": "zabbix-fields-text"
};
const _hoisted_2$j = { class: "row" };
const _sfc_main$r = /* @__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$p, [
        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$j, [
          createVNode(unref(GSwitch), {
            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$r, [["__scopeId", "data-v-0d88475b"]]);
const _hoisted_1$o = {
  class: "fields",
  "data-testid": "zabbix-fields-itemid"
};
const _sfc_main$q = /* @__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$o, [
        _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$q, [["__scopeId", "data-v-422148e0"]]);
const _hoisted_1$n = {
  class: "fields",
  "data-testid": "zabbix-fields-problems"
};
const _sfc_main$p = /* @__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$n, [
        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$p, [["__scopeId", "data-v-b65b5880"]]);
const _hoisted_1$m = {
  class: "fields",
  "data-testid": "zabbix-fields-triggers"
};
const _hoisted_2$i = { class: "row" };
const _sfc_main$o = /* @__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$m, [
        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$i, [
          createVNode(unref(GSwitch), {
            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$o, [["__scopeId", "data-v-9e1c71cd"]]);
const _hoisted_1$l = {
  class: "fields",
  "data-testid": "zabbix-fields-services"
};
const _sfc_main$n = /* @__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$l, [
        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$n, [["__scopeId", "data-v-e28f273d"]]);
const _hoisted_1$k = {
  class: "fields",
  "data-testid": "zabbix-fields-macros"
};
const _sfc_main$m = /* @__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$k, [
        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$m, [["__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$j = ["data-testid"];
const _hoisted_2$h = {
  class: "editor-alert__icon",
  "aria-hidden": "true"
};
const _hoisted_3$g = { class: "editor-alert__body" };
const _hoisted_4$d = { class: "editor-alert__title" };
const _hoisted_5$a = {
  key: 0,
  class: "editor-alert__msg"
};
const _sfc_main$l = /* @__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$h, [
          createVNode(unref(GIcon), { name: "exclamation-triangle" })
        ]),
        createElementVNode("div", _hoisted_3$g, [
          createElementVNode(
            "strong",
            _hoisted_4$d,
            toDisplayString(__props.title),
            1
            /* TEXT */
          ),
          __props.message ? (openBlock(), createElementBlock(
            "p",
            _hoisted_5$a,
            toDisplayString(__props.message),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          renderSlot(_ctx.$slots, "default", {}, void 0, true)
        ])
      ], 10, _hoisted_1$j);
    };
  }
});
const EditorAlert = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-d2eebf65"]]);
const _sfc_main$k = /* @__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$j = /* @__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$i = {
  key: 0,
  class: "opts",
  "data-testid": "zabbix-query-options"
};
const _hoisted_2$g = ["aria-expanded"];
const _hoisted_3$f = { class: "chev" };
const _hoisted_4$c = {
  key: 0,
  class: "summary",
  "data-testid": "zabbix-query-options-summary"
};
const _hoisted_5$9 = {
  key: 1,
  class: "summary muted"
};
const _hoisted_6$9 = {
  class: "opts-body",
  "data-testid": "zabbix-query-options-body"
};
const _hoisted_7$9 = {
  key: 1,
  "data-testid": "zabbix-query-options-empty",
  class: "empty"
};
const _sfc_main$i = /* @__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$i, [
        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$f,
            toDisplayString(expanded.value ? "▾" : "▸"),
            1
            /* TEXT */
          ),
          _cache[15] || (_cache[15] = createElementVNode(
            "strong",
            null,
            "Options",
            -1
            /* CACHED */
          )),
          !expanded.value && summary.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_4$c,
            toDisplayString(summary.value),
            1
            /* TEXT */
          )) : !expanded.value ? (openBlock(), createElementBlock("span", _hoisted_5$9, "无额外选项")) : createCommentVNode("v-if", true)
        ], 8, _hoisted_2$g),
        withDirectives(createElementVNode(
          "div",
          _hoisted_6$9,
          [
            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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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(GSwitch), {
                      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$9));
    };
  }
});
const QueryOptionsEditor = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-ad526b39"]]);
const _hoisted_1$h = {
  class: "zbx-qe",
  "data-testid": "query-editor-zabbix"
};
const _sfc_main$h = /* @__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$h, [
        createVNode(_sfc_main$j, {
          range: props.range
        }, null, 8, ["range"]),
        queryType.value === "0" ? (openBlock(), createBlock(_sfc_main$k, {
          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$h, [["__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$g = {
  class: "zbx-cfg",
  "data-testid": "config-editor-zabbix"
};
const _hoisted_2$f = {
  class: "section",
  "aria-labelledby": "zbx-conn"
};
const _hoisted_3$e = { class: "cred-field" };
const _hoisted_4$b = {
  class: "tip-wrap",
  "data-testid": "zabbix-token-tip",
  tabindex: "0"
};
const _hoisted_5$8 = {
  class: "cred-status",
  "data-testid": "zabbix-credential-status"
};
const _hoisted_6$8 = {
  key: 0,
  class: "configured"
};
const _hoisted_7$8 = {
  key: 1,
  class: "not-configured"
};
const _hoisted_8$4 = {
  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$2 = {
  key: 3,
  class: "err",
  "data-testid": "zabbix-query-timeout-error",
  role: "alert"
};
const _hoisted_15$2 = { class: "row" };
const _hoisted_16$1 = {
  class: "sr-only",
  "data-testid": "zabbix-db-candidates",
  "aria-label": "Direct DB 候选项"
};
const _hoisted_17$1 = ["data-uid", "data-type"];
const _hoisted_18$1 = {
  key: 1,
  class: "err"
};
const _hoisted_19$1 = { class: "row" };
const _hoisted_20$1 = { class: "row" };
const _hoisted_21$1 = { class: "row" };
const _hoisted_22$1 = {
  key: 5,
  "data-testid": "zabbix-enable-writes-warn"
};
const _sfc_main$g = /* @__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$g, [
        createVNode(unref(_sfc_main$38), {
          layout: "vertical",
          "test-id": "zabbix-config-form"
        }, {
          default: withCtx(() => [
            createElementVNode("section", _hoisted_2$f, [
              _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$e, [
                    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$34), { title: "凭据仅保存在运行时内存，不会写入 jsonData、URL 或日志" }, {
                      default: withCtx(() => [
                        createElementVNode("span", _hoisted_4$b, [
                          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$8, [
                credentialConfigured.value ? (openBlock(), createElementBlock("span", _hoisted_6$8, "已配置凭据")) : (openBlock(), createElementBlock("span", _hoisted_7$8, "未配置凭据")),
                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$4, [
              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(GSwitch), {
                    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$2,
                  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$2, [
                  createVNode(unref(GSwitch), {
                    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$1, [
                      (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$1);
                        }),
                        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$1,
                      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$1, [
                  createVNode(unref(GSwitch), {
                    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$1, [
                  createVNode(unref(GSwitch), {
                    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(GSwitch), {
                    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$g, [["__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((t2) => t2.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((t2) => ({
    ...t2,
    tag: interpolateZabbixValue(t2.tag, vars),
    value: interpolateZabbixValue(t2.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 t2 = String(row.type ?? "0");
  if (t2 === "1" || t2 === "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((h2) => String(h2.hostid)),
    macroFilter.filter,
    ctx.signal
  );
  const rows = Array.isArray(page) ? page : page.rows || [];
  const hostMap = new Map(hosts.map((h2) => [String(h2.hostid), h2]));
  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 t2 = String(query || "").trim();
  if (/^hostgroup(\.get)?$/i.test(t2)) return { queryType: "group" };
  if (/^host(\.get)?$/i.test(t2) && !/^hostgroup/i.test(t2))
    return { queryType: "host" };
  if (/^item(\.get)?$/i.test(t2)) return { queryType: "item" };
  if (/^application(\.get)?$/i.test(t2)) return { queryType: "application" };
  if (/^proxy(\.get)?$/i.test(t2)) return { queryType: "proxy" };
  if (/^service(\.get)?$/i.test(t2)) return { queryType: "service" };
  if (/^sla(\.get)?$/i.test(t2)) return { queryType: "sla" };
  if (/^trigger(\.get)?$/i.test(t2)) return { queryType: "trigger" };
  if (/^usermacro(\.get)?$/i.test(t2) || /^macro$/i.test(t2))
    return { queryType: "macro" };
  if (t2.startsWith("{") && t2.endsWith("}")) {
    try {
      return JSON.parse(t2);
    } catch {
    }
  }
  const [kind2, ...rest] = t2.split(":");
  if (kind2 === "group") return { queryType: "group", filter: rest.join(":") };
  if (kind2 === "host")
    return {
      queryType: "host",
      group: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind2 === "application")
    return {
      queryType: "application",
      group: rest[0],
      host: rest[1],
      filter: rest.slice(2).join(":")
    };
  if (kind2 === "item")
    return {
      queryType: "item",
      group: rest[0],
      host: rest[1],
      filter: rest.slice(2).join(":")
    };
  if (kind2 === "itemTag")
    return { queryType: "itemTag", filter: rest.join(":") };
  if (kind2 === "macro") return { queryType: "macro", filter: rest.join(":") };
  if (kind2 === "proxy") return { queryType: "proxy", filter: rest.join(":") };
  if (kind2 === "service")
    return { queryType: "service", filter: rest.join(":") };
  if (kind2 === "sla") return { queryType: "sla", filter: rest.join(":") };
  if (kind2 === "trigger")
    return { queryType: "trigger", filter: rest.join(":") };
  if (kind2 === "itemValues")
    return {
      queryType: "itemValues",
      item: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind2 === "lldRule" || kind2 === "discoveryRule")
    return {
      queryType: "lldRule",
      host: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind2 === "itemPrototype" || kind2 === "prototype")
    return {
      queryType: "itemPrototype",
      item: rest[0],
      filter: rest.slice(1).join(":")
    };
  return { queryType: "group", filter: t2 };
}
function splitTemplateQuery(query) {
  const t2 = String(query || "").trim();
  if (!t2) return [];
  const braced = t2.match(/\{[^}]*\}/g);
  if (braced?.length) return braced.map((s) => s.slice(1, -1));
  if (t2.includes(".") && !t2.includes(":") && !t2.startsWith("/")) {
    return t2.split(".");
  }
  return [t2];
}
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((h2) => ({
      text: String(h2.name || h2.host),
      value: preferId ? String(h2.hostid ?? h2.name ?? h2.host) : String(h2.name || h2.host),
      id: String(h2.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((h2) => String(h2.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((h2) => String(h2.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((h2) => String(h2.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((h2) => String(h2.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((t2) => ({
      text: String(t2.description || t2.triggerid),
      value: preferId ? String(t2.triggerid) : String(t2.description || t2.triggerid),
      id: String(t2.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((h2) => String(h2.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$f = {
  class: "var-qe",
  "data-testid": "zabbix-variable-query-editor"
};
const _hoisted_2$e = {
  key: 0,
  class: "legacy",
  "data-testid": "zabbix-var-legacy",
  role: "status"
};
const _hoisted_3$d = {
  key: 0,
  class: "row"
};
const _sfc_main$f = /* @__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(t2) {
      const s = t2.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$f, [
        legacyReadonly.value ? (openBlock(), createElementBlock("div", _hoisted_2$e, [
          _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$d, [
              createVNode(unref(GSwitch), {
                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$f, [["__scopeId", "data-v-58089d47"]]);
const _hoisted_1$e = {
  class: "anno-qe",
  "data-testid": "zabbix-annotation-query-editor"
};
const _hoisted_2$d = { class: "row" };
const _hoisted_3$c = { class: "row" };
const _hoisted_4$a = { class: "row" };
const _sfc_main$e = /* @__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$e, [
        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$d, [
          createVNode(unref(GSwitch), {
            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$c, [
          createVNode(unref(GSwitch), {
            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$a, [
          createVNode(unref(GSwitch), {
            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$e, [["__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, ttlMs2, consumerSignal, loader) {
    const serialized = serializeZabbixCacheKey(key);
    const now2 = Date.now();
    const hit = this.entries.get(serialized);
    if (hit && hit.expiresAt > now2) {
      hit.lastAccess = now2;
      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 inflight2 = {
      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, ttlMs2),
          lastAccess: Date.now(),
          value
        });
        this.evictIfNeeded();
        return value;
      }).finally(() => {
        this.inflight.delete(serialized);
      })
    };
    this.inflight.set(serialized, inflight2);
    if (consumerSignal?.aborted) {
      inflight2.consumers -= 1;
      if (inflight2.consumers <= 0) inflight2.controller.abort();
      return Promise.reject(new DOMException("Aborted", "AbortError"));
    }
    return this.bindConsumer(inflight2, consumerSignal);
  }
  bindConsumer(inflight2, signal) {
    return new Promise((resolve, reject) => {
      let settled = false;
      const onAbort = () => {
        if (settled) return;
        settled = true;
        inflight2.consumers -= 1;
        if (inflight2.consumers <= 0) inflight2.controller.abort();
        reject(new DOMException("Aborted", "AbortError"));
      };
      if (signal) {
        if (signal.aborted) {
          onAbort();
          return;
        }
        signal.addEventListener("abort", onAbort, { once: true });
      }
      inflight2.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 now2 = Date.now();
    const hit = this.trendHistoryCache.get(key);
    if (hit && now2 - 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: now2, 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((t2) => ({
        tag: t2.tag,
        value: t2.value,
        operator: t2.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, history2, from, to, signal, limit) {
    if (!itemids?.length) return [];
    const ids = [...itemids].map(String).sort();
    const key = `h|${ids.join(",")}|${history2}|${from}|${to}|${limit ?? ""}`;
    return this.cachedTrendHistory(key, async () => {
      const params = {
        itemids: ids,
        history: history2,
        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 clock2 = String(start + i * step);
    points.push({ itemid, clock: clock2, 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 t2 = Number(b.clock || 0) - Number(a.clock || 0);
      if (t2 !== 0) return t2;
    } else {
      const c = Number(b.severity || 0) - Number(a.severity || 0);
      if (c !== 0) return c;
      const t2 = Number(b.clock || 0) - Number(a.clock || 0);
      if (t2 !== 0) return t2;
    }
    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 clock2 = Number(r.clock || 0);
        if (!clock2) {
          values[index2] = null;
          return null;
        }
        const hist = await ctx.api.getHistory(
          [String(item.itemid)],
          vt,
          clock2 - 1,
          clock2 + 1,
          ctx.signal,
          1
        );
        const point = (hist || []).find((h2) => Number(h2.clock) <= clock2) || 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((t2) => [String(t2.triggerid), t2])
    );
    return rows.map((r) => {
      const t2 = byId2.get(String(r.objectid));
      if (!t2) return r;
      const hosts = Array.isArray(r.hosts) && r.hosts.length ? r.hosts : t2.hosts;
      const groups = Array.isArray(r.groups) && r.groups.length ? r.groups : t2.groups || t2.hostgroups;
      const items = Array.isArray(r.items) && r.items.length ? r.items : t2.items;
      return {
        ...r,
        hosts: hosts || [],
        groups: groups || [],
        items: items || [],
        description: r.description || t2.description,
        comments: r.comments || t2.comments,
        url: r.url || t2.url,
        expression: r.expression || t2.expression,
        manual_close: r.manual_close ?? t2.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((h2) => String(h2.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((h2) => String(h2?.name || h2?.host || h2?.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 t2 of series.item.tags || []) {
    if (!t2.tag) continue;
    const key = sanitizeTagName(t2.tag);
    const list = tagMap.get(key) || [];
    list.push(String(t2.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 t2 = Math.floor(fromMs / intervalMs) * intervalMs; t2 <= toMs2; t2 += intervalMs) {
    points.push({ time: t2, value: map.has(t2) ? map.get(t2) : 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 num2 = 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(num2)) {
        const rangeMatch = String(m.value).match(
          /^(-?\d+(?:\.\d+)?)-(-?\d+(?:\.\d+)?)$/
        );
        if (rangeMatch) {
          const lo = Number(rangeMatch[1]);
          const hi = Number(rangeMatch[2]);
          if (num2 >= lo && num2 <= hi) return m.newvalue ?? raw;
        }
      }
    }
    if (type === "1" || type === "range") {
      const parts = String(m.value || "").split(/[,:]/);
      if (parts.length >= 2 && Number.isFinite(num2)) {
        const lo = Number(parts[0]);
        const hi = Number(parts[1]);
        if (num2 >= lo && num2 <= 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 t2 = Number(row.time);
    const time = !Number.isFinite(t2) ? 0 : t2 < 1e12 ? t2 * 1e3 : t2;
    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(history2) {
  return history2 === 3 ? "history_uint" : "history";
}
function trendsTable$1(history2) {
  return history2 === 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(history2) {
  return history2 === 3 ? "history_uint" : "history";
}
function trendsTable(history2) {
  return history2 === 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 t2 = String(type || "").toLowerCase();
  if (t2.includes("postgres")) return "postgres";
  if (t2.includes("mysql")) return "mysql";
  if (t2.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 valueField2 = 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,
      valueField2?.values?.length || 0,
      itemField?.values?.length || 0
    );
    const labelItemid = frame.name || valueField2?.labels?.itemid;
    for (let i = 0; i < n; i++) {
      rows.push({
        itemid: String(itemField?.values?.[i] ?? labelItemid ?? ""),
        time: timeField?.values?.[i],
        value: valueField2?.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((h2) => String(h2.hostid)),
    ctx.signal
  );
  const items = await resolveItems(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hosts.map((h2) => String(h2.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 [history2, group] of groups) {
    const itemids = group.map((i) => String(i.itemid));
    const rawQuery = buildDirectDbQueryText({
      dialect,
      itemids,
      history: history2,
      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}-${history2}`,
        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
  });
}
let _worker = null;
let _workerFailed = false;
const pending = /* @__PURE__ */ new Map();
let seq = 0;
function getWorker() {
  if (_workerFailed) return null;
  if (typeof Worker === "undefined") return null;
  if (!_worker) {
    try {
      _worker = new Worker(new URL(
        /* @vite-ignore */
        "/assets/frameWorker-C6D9tEGY.js",
        import.meta.url
      ), {
        type: "module"
      });
      _worker.addEventListener("message", (e) => {
        const id = e.data?.id;
        if (!id) return;
        const slot = pending.get(id);
        if (!slot) return;
        pending.delete(id);
        if (e.data.ok) slot.resolve(e.data.frames);
        else slot.reject(new Error(String(e.data.error || "frame worker failed")));
      });
    } catch {
      _workerFailed = true;
      return null;
    }
  }
  return _worker;
}
function syncBuild(payload) {
  return seriesListToFrames(
    payload.series,
    payload.refId,
    payload.datasourceUid
  );
}
async function chunkedBuild(payload, signal) {
  const series = payload.series || [];
  if (series.length <= 1) {
    if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
    return syncBuild(payload);
  }
  const out = [];
  const chunkSize = 4;
  for (let i = 0; i < series.length; i += chunkSize) {
    if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
    const slice = series.slice(i, i + chunkSize);
    out.push(
      ...seriesListToFrames(slice, payload.refId, payload.datasourceUid)
    );
    await new Promise((r) => setTimeout(r, 0));
  }
  return out;
}
function buildFramesAsync(payload, signal) {
  if (signal?.aborted) {
    return Promise.reject(new DOMException("Aborted", "AbortError"));
  }
  const worker = getWorker();
  if (!worker) {
    return chunkedBuild(payload, signal);
  }
  const id = `${payload.requestId || "req"}-${++seq}`;
  return new Promise((resolve, reject) => {
    const onAbort = () => {
      pending.delete(id);
      try {
        worker.postMessage({ type: "cancel", id });
      } catch {
      }
      reject(new DOMException("Aborted", "AbortError"));
    };
    if (signal) {
      if (signal.aborted) {
        onAbort();
        return;
      }
      signal.addEventListener("abort", onAbort, { once: true });
    }
    pending.set(id, {
      resolve: (frames) => {
        signal?.removeEventListener("abort", onAbort);
        resolve(frames);
      },
      reject: (err) => {
        signal?.removeEventListener("abort", onAbort);
        reject(err);
      }
    });
    try {
      worker.postMessage({ id, ...payload });
    } catch {
      pending.delete(id);
      signal?.removeEventListener("abort", onAbort);
      void chunkedBuild(payload, signal).then(resolve, reject);
    }
  });
}
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((h2) => String(h2.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 [history2, group] of byType) {
    const spec = resolveValueTypeSpec(history2);
    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(
            (t2) => String(t2.itemid) === String(item.itemid)
          );
          let points = rows.map((t2) => ({
            time: Number(t2.clock) * 1e3,
            value: pickTrendValue(t2, trendMode),
            valueRaw: String(t2.value_avg ?? t2.value_min ?? ""),
            value_min: t2.value_min,
            value_avg: t2.value_avg,
            value_max: t2.value_max,
            num: t2.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(
            (h2) => String(h2.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: history2
            }
          });
        }
      }
      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: history2,
            fromSec,
            toSec,
            pageLimit,
            maxRows: Math.min(maxRows, perSeries * batch.length),
            signal: ctx.signal,
            getHistory: (itemids, h2, f, t2, signal, limit) => ctx.api.getHistory(itemids, h2, f, t2, 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((h2) => String(h2.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((h2) => String(h2.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((h2) => String(h2.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 history2 = Number(item.value_type);
    const rows = await ctx.api.getHistory(
      [item.itemid],
      history2,
      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((h2) => String(h2.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((h2) => String(h2?.name || h2?.host || h2?.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((t2) => ({
            refId: t2.refId,
            value: results.get(t2.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 || getRuntimeDataSourceSettings(instance.uid)?.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((h2) => ({
      text: String(h2.name || h2.host),
      value: String(h2.name || h2.host),
      id: String(h2.hostid)
    }));
  }
  async function listItems(hostFilter = "") {
    const q = migrateZabbixQuery({
      host: { filter: hostFilter },
      item: { filter: "" }
    });
    const hosts = await resolveHosts(api, q, {}, []);
    const hostids = hosts.map((h2) => String(h2.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((h2) => ({
              text: String(h2.name || h2.host),
              value: String(h2.name || h2.host),
              id: String(h2.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((t2) => ({
              text: String(t2.description || t2.triggerid),
              value: String(t2.description || t2.triggerid),
              id: String(t2.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();
  /** In-flight loaders keyed by serializeCacheKey — shared across consumers. */
  inflight = /* @__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, ttlMs2) {
    if (ttlMs2 <= 0) return;
    if (value == null) return;
    if (this.entries.size >= MAX_ENTRIES) this.evict();
    this.entries.set(serializeCacheKey(key), {
      value,
      expiresAt: Date.now() + ttlMs2,
      lastAccess: Date.now()
    });
  }
  /**
   * Cache hit or single-flight load.
   * - error/abort: do not write cache; remove inflight so next call retries
   * - one consumer abort must NOT cancel shared promise (loader owns its signal policy)
   */
  async getOrLoad(key, ttlMs2, loader) {
    const hit = this.get(key);
    if (hit !== void 0) return hit;
    const s = serializeCacheKey(key);
    const existing = this.inflight.get(s);
    if (existing) return existing;
    const pending2 = (async () => {
      try {
        const value = await loader();
        this.set(key, value, ttlMs2);
        return value;
      } finally {
        this.inflight.delete(s);
      }
    })();
    this.inflight.set(s, pending2);
    return pending2;
  }
  inflightSize() {
    return this.inflight.size;
  }
  /** 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();
    this.inflight.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((h2) => {
    const path = h2.path;
    const kind2 = path.includes("healthz") || path.includes("v2") ? "v2" : path.includes("v1") ? "v1" : "other";
    return { path, method: h2.method, kind: kind2 };
  });
  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 t2 = typeof a === "string" ? a : a?.type;
    if (ALLOWED_AGG.has(t2)) out.push({ type: t2 });
  }
  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)
  });
}
const WATERFALL_CACHE_MAX_ENTRIES = 128;
const WATERFALL_CACHE_MAX_BYTES = 32 * 1024 * 1024;
const WATERFALL_CACHE_TTL_MS = 5 * 60 * 1e3;
function estimateDetailBytes(v) {
  try {
    return JSON.stringify(v).length * 2;
  } catch {
    return 1024;
  }
}
function createMemoryWaterfallCache(opts) {
  const maxEntries = WATERFALL_CACHE_MAX_ENTRIES;
  const maxBytes2 = WATERFALL_CACHE_MAX_BYTES;
  const ttlMs2 = WATERFALL_CACHE_TTL_MS;
  const resolved = /* @__PURE__ */ new Map();
  const details = /* @__PURE__ */ new Map();
  let detailBytes = 0;
  const touchResolved = (k, v) => {
    resolved.delete(k);
    resolved.set(k, v);
  };
  const touchDetail = (k, v) => {
    details.delete(k);
    details.set(k, v);
  };
  const evictDetails = () => {
    while (details.size > maxEntries || detailBytes > maxBytes2) {
      const first = details.keys().next().value;
      if (first == null) break;
      const ent = details.get(first);
      details.delete(first);
      if (ent) detailBytes = Math.max(0, detailBytes - ent.bytes);
    }
    while (resolved.size > maxEntries) {
      const first = resolved.keys().next().value;
      if (first == null) break;
      resolved.delete(first);
    }
  };
  return {
    getResolved: (k) => {
      const v = resolved.get(k);
      if (!v) return void 0;
      if (v.expiresAt <= Date.now()) {
        resolved.delete(k);
        return void 0;
      }
      touchResolved(k, v);
      return {
        id: v.id,
        path: v.path,
        method: v.method,
        observedAt: v.observedAt
      };
    },
    setResolved: (k, v) => {
      touchResolved(k, {
        ...v,
        expiresAt: Date.now() + ttlMs2
      });
      evictDetails();
    },
    getDetail: (k) => {
      const ent = details.get(k);
      if (!ent) return void 0;
      if (ent.expiresAt <= Date.now()) {
        details.delete(k);
        detailBytes = Math.max(0, detailBytes - ent.bytes);
        return void 0;
      }
      touchDetail(k, ent);
      return ent.value;
    },
    setDetail: (k, v) => {
      const prev = details.get(k);
      if (prev) detailBytes = Math.max(0, detailBytes - prev.bytes);
      const bytes = estimateDetailBytes(v);
      touchDetail(k, {
        value: v,
        expiresAt: Date.now() + ttlMs2,
        bytes
      });
      detailBytes += bytes;
      evictDetails();
    },
    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)) {
          const ent = details.get(k);
          details.delete(k);
          if (ent) detailBytes = Math.max(0, detailBytes - ent.bytes);
        }
      }
    }
  };
}
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 t2 = s.time_unix ?? s.timeUnix ?? s.startTimeUnixNano ?? s.startTime ?? s.timestamp;
      if (t2 == null) return 0;
      const n = Number(t2);
      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$d = {
  class: "tbl",
  "data-testid": "issues-table"
};
const _hoisted_2$c = { key: 0 };
const _hoisted_3$b = ["data-testid", "onClick"];
const _hoisted_4$9 = { key: 0 };
const _hoisted_5$7 = ["onClick"];
const _hoisted_6$7 = ["onClick"];
const _hoisted_7$7 = {
  key: 1,
  class: "ro"
};
const _sfc_main$d = /* @__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 "var(--grafana-error)";
      if (s === "error") return "var(--grafana-error)";
      if (s === "warning" || s === "warn") return "var(--grafana-warning)";
      if (s === "info") return "var(--grafana-info-main, var(--grafana-primary))";
      return "var(--grafana-text-secondary)";
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("table", _hoisted_1$d, [
        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$c, "数据源")) : 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$9,
                  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$7),
                      createElementVNode("button", {
                        type: "button",
                        "data-testid": "issue-resolve",
                        onClick: ($event) => emit("resolve", issue)
                      }, " 解决 ", 8, _hoisted_6$7)
                    ],
                    64
                    /* STABLE_FRAGMENT */
                  )) : (openBlock(), createElementBlock("span", _hoisted_7$7, "只读"))
                ])
              ], 8, _hoisted_3$b);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])
      ]);
    };
  }
});
const IssuesTable = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-cce1a8e4"]]);
const _hoisted_1$c = {
  class: "list",
  "data-testid": "issues-list"
};
const _hoisted_2$b = ["data-testid", "onClick"];
const _hoisted_3$a = { class: "title" };
const _hoisted_4$8 = { class: "meta" };
const _sfc_main$c = /* @__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 "var(--grafana-error)";
      if (s === "error") return "var(--grafana-error)";
      if (s === "warning" || s === "warn") return "var(--grafana-warning)";
      return "var(--grafana-text-secondary)";
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("ul", _hoisted_1$c, [
        (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$a,
                toDisplayString(issue.title),
                1
                /* TEXT */
              ),
              createElementVNode(
                "span",
                _hoisted_4$8,
                toDisplayString(issue.service) + " · " + toDisplayString(new Date(issue.time).toLocaleString()),
                1
                /* TEXT */
              )
            ], 8, _hoisted_2$b);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const IssuesList = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-995992a7"]]);
const _hoisted_1$b = {
  class: "detail",
  "data-testid": "issue-detail"
};
const _hoisted_2$a = { key: 0 };
const _hoisted_3$9 = { "data-testid": "issue-trace-id" };
const _hoisted_4$7 = ["href"];
const _hoisted_5$6 = {
  key: 1,
  "data-testid": "issue-attributes"
};
const _hoisted_6$6 = {
  key: 2,
  "data-testid": "issue-detail-loading"
};
const _hoisted_7$6 = {
  key: 3,
  class: "err",
  role: "alert"
};
const _hoisted_8$3 = {
  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$1 = {
  key: 5,
  "data-testid": "issue-related-logs",
  class: "block"
};
const _hoisted_15$1 = { class: "muted" };
const _sfc_main$b = /* @__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 seq2 = 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 = ++seq2;
      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 !== seq2) return;
        spans.value = framesToSpanRows(spanFrames);
        logs.value = framesToLogRows(logRes?.frames || []);
      } catch (e) {
        if (e?.name === "AbortError") return;
        if (my === seq2) error.value = e instanceof Error ? e.message : String(e);
      } finally {
        if (my === seq2) loading.value = false;
      }
    }
    watch(
      () => [
        props.issue.id,
        props.issue.traceId,
        props.range?.fromMs,
        props.range?.toMs
      ],
      () => void loadDetail(),
      { immediate: true }
    );
    onBeforeUnmount(() => {
      controller?.abort();
      seq2 += 1;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("aside", _hoisted_1$b, [
        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$a, [
          _cache[1] || (_cache[1] = createTextVNode(
            " Trace: ",
            -1
            /* CACHED */
          )),
          createElementVNode(
            "span",
            _hoisted_3$9,
            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$7)) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        __props.options.showAttributes && __props.issue.attributes ? (openBlock(), createElementBlock("div", _hoisted_5$6, [
          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$6, "加载详情…")) : createCommentVNode("v-if", true),
        error.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_7$6,
          toDisplayString(error.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        spans.value.length ? (openBlock(), createElementBlock("div", _hoisted_8$3, [
          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$1, [
          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$1,
                    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$b, [["__scopeId", "data-v-3bc8d87d"]]);
const _hoisted_1$a = {
  class: "signoz-issues",
  "data-testid": "signoz-issues-panel"
};
const _hoisted_2$9 = { class: "toolbar" };
const _hoisted_3$8 = {
  key: 0,
  "data-testid": "issue-action-msg"
};
const _hoisted_4$6 = {
  key: 1,
  class: "err",
  "data-testid": "issue-action-error",
  role: "alert"
};
const _hoisted_5$5 = {
  key: 0,
  "data-testid": "issues-empty"
};
const _hoisted_6$5 = {
  key: 3,
  class: "pager"
};
const _hoisted_7$5 = ["disabled"];
const _hoisted_8$2 = ["disabled"];
const _hoisted_9$2 = {
  key: 5,
  class: "confirm",
  "data-testid": "issue-action-confirm",
  role: "dialog"
};
const _sfc_main$a = /* @__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$a, [
        createElementVNode("div", _hoisted_2$9, [
          createElementVNode(
            "span",
            null,
            "Issues " + toDisplayString(issues.value.length),
            1
            /* TEXT */
          ),
          actionMsg.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_3$8,
            toDisplayString(actionMsg.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          actionError.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_4$6,
            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$5, " 当前筛选条件下没有 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$5, [
          createElementVNode("button", {
            type: "button",
            disabled: page.value === 0,
            "data-testid": "issues-prev",
            onClick: _cache[4] || (_cache[4] = ($event) => page.value--)
          }, " 上一页 ", 8, _hoisted_7$5),
          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$2)
        ])) : 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$a, [["__scopeId", "data-v-17c979ee"]]);
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 add-ons; 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: []
};
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 === "argus-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 };
}
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-v5": {
    id: "signoz-v5",
    signals: ["metrics", "logs", "traces"],
    formulaServerSide: true,
    supportsServerFormula: true,
    // Argus host rewrites SigNoz under /api/apm/* and uses Bearer session token.
    credentialModes: ["bearer", "proxy", "headers", "signozApiKey", "session"],
    defaultCredentialHeader: "Authorization",
    queryModesBySignal: {
      metrics: ALL_MODES,
      logs: ALL_MODES,
      traces: BUILDER_ONLY
    },
    isHealthy: defaultIsHealthy,
    endpoints: {
      metricsQuery: { path: "/api/apm/v5/query_range", method: "POST" },
      logsQuery: { path: "/api/apm/v5/query_range", method: "POST" },
      tracesQuery: { path: "/api/apm/v5/query_range", method: "POST" },
      health: { path: "/api/apm/v1/health", method: "GET" },
      healthCandidates: [
        { path: "/api/apm/v1/health", method: "GET" },
        { path: "/api/apm/v2/healthz", method: "GET" }
      ],
      version: { path: "/api/apm/v1/version", method: "GET" },
      metricsList: { path: "/api/apm/v2/metrics", method: "GET" },
      metadata: { path: "/api/apm/v2/metrics", method: "GET" },
      fieldsKeys: { path: "/api/apm/v1/fields/keys", method: "GET" },
      fieldsValues: { path: "/api/apm/v1/fields/values", method: "GET" },
      attributeKeys: { path: "/api/apm/v1/fields/keys", method: "GET" },
      attributeValues: { path: "/api/apm/v1/fields/values", method: "GET" },
      services: { path: "/api/apm/v2/services", method: "POST" },
      alertsQuery: { path: "/api/apm/v1/rules", method: "GET" },
      variablesQuery: { path: "/api/apm/v2/variables/query", method: "POST" },
      traceById: { path: "/api/apm/v4/traces/{id}", method: "GET" },
      liveTail: { path: "/api/apm/v3/logs/livetail", method: "GET" },
      liveTailLegacy: { path: "/api/apm/v1/logs/tail", method: "GET" },
      exportRaw: { path: "/api/apm/v1/export_raw_data", method: "POST" }
    }
  },
  custom: {
    id: "custom",
    signals: [],
    formulaServerSide: false,
    supportsServerFormula: false,
    queryModesBySignal: { ...EMPTY_MODES },
    isHealthy: defaultIsHealthy,
    endpoints: {}
  }
};
function isV5WireProfile(id) {
  const p = String(id || "");
  return p === "signoz-v5" || p === "signoz-v5";
}
function resolveSigNozProfile(options) {
  let id = String(options?.apiProfile || "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 deepClone$2(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$2(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$2(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}`;
}
const QUERY_NAMES = "ABCDEFGHIJ";
function nextQueryNameByLength(length) {
  return QUERY_NAMES[length] ?? `Q${length + 1}`;
}
function nextFormulaNameByLength(length) {
  return `F${length + 1}`;
}
function deepClone$1(v) {
  return JSON.parse(JSON.stringify(v));
}
function cloneBuilderSpec(spec) {
  return deepClone$1(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$1(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$1({
          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$1(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$1(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$1(state2.legacySchema1),
      editor: deepClone$1(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$1(f) });
    }
    for (const t2 of state2.builder.traceOperators) {
      queries.push({ type: "builder_trace_operator", spec: deepClone$1(t2) });
    }
  } 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$1(state2)
  };
}
function commitGlobalMode(state2, mode2) {
  const next = deepClone$1(state2);
  next.activeQueryType = mode2;
  next.legacyMixed = false;
  next.legacySchema1 = void 0;
  return next;
}
const QUERY_TYPE_TABS_DEFAULT_SHOW_AGG = true;
const QUERY_ADD_ON_KEYS = [
  "group_by",
  "having",
  "order_by",
  "limit",
  "legend_format"
];
const METRIC_FUNCTIONS = [
  {
    value: "cutOffMin",
    label: "Cut Off Min",
    showArg: true,
    argPlaceholder: "Threshold"
  },
  {
    value: "cutOffMax",
    label: "Cut Off Max",
    showArg: true,
    argPlaceholder: "Threshold"
  },
  {
    value: "clampMin",
    label: "Clamp Min",
    showArg: true,
    argPlaceholder: "Threshold"
  },
  {
    value: "clampMax",
    label: "Clamp Max",
    showArg: true,
    argPlaceholder: "Threshold"
  },
  { value: "absolute", label: "Absolute", showArg: false },
  { value: "runningDiff", label: "Running Diff", showArg: false },
  { value: "log2", label: "Log2", showArg: false },
  { value: "log10", label: "Log10", showArg: false },
  { value: "cumulativeSum", label: "Cumulative Sum", showArg: false },
  { value: "ewma3", label: "EWMA 3", showArg: true, argPlaceholder: "Alpha" },
  { value: "ewma5", label: "EWMA 5", showArg: true, argPlaceholder: "Alpha" },
  { value: "ewma7", label: "EWMA 7", showArg: true, argPlaceholder: "Alpha" },
  { value: "median3", label: "Median 3", showArg: false },
  { value: "median5", label: "Median 5", showArg: false },
  { value: "median7", label: "Median 7", showArg: false },
  {
    value: "timeShift",
    label: "Time Shift",
    showArg: true,
    argPlaceholder: "Seconds"
  },
  { value: "fillZero", label: "Fill Zero", showArg: false }
];
const LOG_FUNCTIONS = [
  {
    value: "timeShift",
    label: "Time Shift",
    showArg: true,
    argPlaceholder: "Seconds"
  }
];
const METRIC_TIME_AGG_BY_TYPE = {
  Sum: [
    { label: "Rate", value: "rate" },
    { label: "Increase", value: "increase" }
  ],
  Gauge: [
    { label: "Latest", value: "latest" },
    { label: "Sum", value: "sum" },
    { label: "Avg", value: "avg" },
    { label: "Min", value: "min" },
    { label: "Max", value: "max" },
    { label: "Count", value: "count" },
    { label: "Count Distinct", value: "count_distinct" }
  ]
};
const METRIC_SPACE_AGG_BY_TYPE = {
  Sum: [
    { label: "Sum", value: "sum" },
    { label: "Avg", value: "avg" },
    { label: "Min", value: "min" },
    { label: "Max", value: "max" }
  ],
  Gauge: [
    { label: "Sum", value: "sum" },
    { label: "Avg", value: "avg" },
    { label: "Min", value: "min" },
    { label: "Max", value: "max" }
  ],
  Histogram: [
    { label: "P50", value: "p50" },
    { label: "P75", value: "p75" },
    { label: "P90", value: "p90" },
    { label: "P95", value: "p95" },
    { label: "P99", value: "p99" }
  ],
  ExponentialHistogram: [
    { label: "P50", value: "p50" },
    { label: "P75", value: "p75" },
    { label: "P90", value: "p90" },
    { label: "P95", value: "p95" },
    { label: "P99", value: "p99" }
  ]
};
const METRIC_TIME_AGG_DEFAULT = [
  { label: "Rate", value: "rate" },
  { label: "Increase", value: "increase" },
  { label: "Sum", value: "sum" },
  { label: "Avg", value: "avg" },
  { label: "Min", value: "min" },
  { label: "Max", value: "max" },
  { label: "Count", value: "count" }
];
const METRIC_SPACE_AGG_DEFAULT = [
  { label: "Sum", value: "sum" },
  { label: "Avg", value: "avg" },
  { label: "Min", value: "min" },
  { label: "Max", value: "max" }
];
function deepClone(value) {
  return JSON.parse(JSON.stringify(value));
}
function clock(opts) {
  return opts?.now?.() ?? Date.now();
}
function resolveDisplayFlags(input) {
  return {
    showAgg: Boolean(input?.showAgg),
    simple: Boolean(input?.simple),
    queryTypeTabsShowAggDefault: QUERY_TYPE_TABS_DEFAULT_SHOW_AGG
  };
}
function currentSignal(query, mode2) {
  return mode2 ?? query.signal;
}
function timeAggOps(metricType) {
  return METRIC_TIME_AGG_BY_TYPE[metricType] ?? METRIC_TIME_AGG_DEFAULT;
}
function spaceAggOps(metricType) {
  return METRIC_SPACE_AGG_BY_TYPE[metricType] ?? METRIC_SPACE_AGG_DEFAULT;
}
function functionOptionsForSignal(signal) {
  return signal === "logs" ? LOG_FUNCTIONS : METRIC_FUNCTIONS;
}
function visibleAddOnKeys(signal, mode2) {
  const s = mode2 ?? signal;
  return QUERY_ADD_ON_KEYS.filter((key) => {
    if (key === "group_by") return s !== "metrics";
    return true;
  });
}
function makeQuery(name, opts) {
  const ts = clock(opts);
  return {
    id: `${name}-${ts}`,
    name,
    signal: opts?.mode ?? "traces",
    where: "",
    aggregations: "count()",
    aggOp: "count",
    aggAttr: "",
    metricName: "",
    metricType: "",
    timeAggregation: "rate",
    spaceAggregation: "sum",
    groupBy: [],
    having: "",
    orderBy: "timestamp:desc",
    limit: 100,
    legend: "",
    step: 60,
    disabled: false,
    spanScope: "all_spans",
    expression: "",
    functions: [],
    _addOns: [],
    _collapsed: false,
    _keyOpts: [],
    _keysLoading: false,
    _metricOpts: [],
    _metricLoading: false
  };
}
function makeFormula(name, opts) {
  const ts = clock(opts);
  return {
    id: `f-${name}-${ts}`,
    name,
    expression: "",
    legend: "",
    having: "",
    orderBy: "",
    limit: 100,
    disabled: false,
    _addOns: [],
    _collapsed: false
  };
}
function createInitialState(opts) {
  return {
    queries: [makeQuery("A", opts)],
    formulas: []
  };
}
function addQuery(state2, opts) {
  const name = nextQueryNameByLength(state2.queries.length);
  return {
    queries: [...state2.queries.map(deepClone), makeQuery(name, opts)],
    formulas: state2.formulas.map(deepClone)
  };
}
function removeQuery(state2, index2) {
  if (index2 < 0 || index2 >= state2.queries.length) {
    return {
      queries: state2.queries.map(deepClone),
      formulas: state2.formulas.map(deepClone)
    };
  }
  return {
    queries: state2.queries.filter((_, i) => i !== index2).map(deepClone),
    formulas: state2.formulas.map(deepClone)
  };
}
function cloneQuery(state2, index2, opts) {
  if (index2 < 0 || index2 >= state2.queries.length) {
    return {
      queries: state2.queries.map(deepClone),
      formulas: state2.formulas.map(deepClone)
    };
  }
  const src = state2.queries[index2];
  const name = nextQueryNameByLength(state2.queries.length);
  const ts = clock(opts);
  const cloned = {
    ...deepClone(src),
    id: `${name}-${ts}`,
    name,
    disabled: false,
    _keyOpts: [],
    _keysLoading: false,
    _metricOpts: [],
    _metricLoading: false
  };
  return {
    queries: [...state2.queries.map(deepClone), cloned],
    formulas: state2.formulas.map(deepClone)
  };
}
function toggleDisabled(state2, index2) {
  return {
    queries: state2.queries.map(
      (q, i) => i === index2 ? { ...deepClone(q), disabled: !q.disabled } : deepClone(q)
    ),
    formulas: state2.formulas.map(deepClone)
  };
}
function toggleCollapse(state2, index2) {
  return {
    queries: state2.queries.map(
      (q, i) => i === index2 ? { ...deepClone(q), _collapsed: !q._collapsed } : deepClone(q)
    ),
    formulas: state2.formulas.map(deepClone)
  };
}
function addFormula(state2, opts) {
  const name = nextFormulaNameByLength(state2.formulas.length);
  return {
    queries: state2.queries.map(deepClone),
    formulas: [...state2.formulas.map(deepClone), makeFormula(name, opts)]
  };
}
function removeFormula(state2, index2) {
  if (index2 < 0 || index2 >= state2.formulas.length) {
    return {
      queries: state2.queries.map(deepClone),
      formulas: state2.formulas.map(deepClone)
    };
  }
  return {
    queries: state2.queries.map(deepClone),
    formulas: state2.formulas.filter((_, i) => i !== index2).map(deepClone)
  };
}
function toggleFormulaDisabled(state2, index2) {
  return {
    queries: state2.queries.map(deepClone),
    formulas: state2.formulas.map(
      (f, i) => i === index2 ? { ...deepClone(f), disabled: !f.disabled } : deepClone(f)
    )
  };
}
function toggleFormulaCollapse(state2, index2) {
  return {
    queries: state2.queries.map(deepClone),
    formulas: state2.formulas.map(
      (f, i) => i === index2 ? { ...deepClone(f), _collapsed: !f._collapsed } : deepClone(f)
    )
  };
}
function seedLegendFromGroupBy(query) {
  if (query.legend || !query.groupBy.length) return query.legend;
  return query.groupBy.map((g) => `{{${g}}}`).join("-");
}
function toggleAddOn(state2, queryIndex, key) {
  return {
    queries: state2.queries.map((q, i) => {
      if (i !== queryIndex) return deepClone(q);
      const next = deepClone(q);
      const idx = next._addOns.indexOf(key);
      if (idx === -1) {
        next._addOns = [...next._addOns, key];
        if (key === "legend_format") {
          next.legend = seedLegendFromGroupBy(next);
        }
      } else {
        next._addOns = next._addOns.filter((k) => k !== key);
      }
      return next;
    }),
    formulas: state2.formulas.map(deepClone)
  };
}
function toggleFormulaAddOn(state2, formulaIndex, key) {
  return {
    queries: state2.queries.map(deepClone),
    formulas: state2.formulas.map((f, i) => {
      if (i !== formulaIndex) return deepClone(f);
      const next = deepClone(f);
      const idx = next._addOns.indexOf(key);
      if (idx === -1) next._addOns = [...next._addOns, key];
      else next._addOns = next._addOns.filter((k) => k !== key);
      return next;
    })
  };
}
function setState(nextQueries, nextFormulas, opts) {
  const qIn = nextQueries && nextQueries.length ? deepClone(nextQueries) : null;
  const fIn = nextFormulas && nextFormulas.length ? deepClone(nextFormulas) : deepClone([]);
  const queries = qIn ? qIn.map((q) => {
    const name = q.name || "A";
    const base = makeQuery(name, opts);
    return { ...base, ...q, name: q.name || name };
  }) : [makeQuery("A", opts)];
  const formulas = (fIn ?? []).map((f) => {
    const name = f.name || "F1";
    const base = makeFormula(name, opts);
    return { ...base, ...f, name: f.name || name };
  });
  return {
    queries: queries.map(deepClone),
    formulas: formulas.map(deepClone)
  };
}
function applyMutation(state2, mutation) {
  let next;
  let shouldEmit = true;
  switch (mutation.type) {
    case "addQuery":
      next = addQuery(state2, mutation.opts);
      break;
    case "removeQuery":
      next = removeQuery(state2, mutation.index);
      break;
    case "cloneQuery":
      next = cloneQuery(state2, mutation.index, mutation.opts);
      break;
    case "toggleDisabled":
      next = toggleDisabled(state2, mutation.index);
      break;
    case "toggleCollapse":
      next = toggleCollapse(state2, mutation.index);
      shouldEmit = false;
      break;
    case "addFormula":
      next = addFormula(state2, mutation.opts);
      break;
    case "removeFormula":
      next = removeFormula(state2, mutation.index);
      break;
    case "toggleFormulaDisabled":
      next = toggleFormulaDisabled(state2, mutation.index);
      break;
    case "toggleFormulaCollapse":
      next = toggleFormulaCollapse(state2, mutation.index);
      shouldEmit = false;
      break;
    case "toggleAddOn":
      next = toggleAddOn(state2, mutation.queryIndex, mutation.key);
      break;
    case "toggleFormulaAddOn":
      next = toggleFormulaAddOn(state2, mutation.formulaIndex, mutation.key);
      break;
    case "setState":
      next = setState(mutation.queries, mutation.formulas, mutation.opts);
      shouldEmit = false;
      break;
    default: {
      next = {
        queries: state2.queries.map(deepClone),
        formulas: state2.formulas.map(deepClone)
      };
      shouldEmit = false;
    }
  }
  return {
    state: next,
    shouldEmit,
    event: shouldEmit ? { type: "change", queries: next.queries, formulas: next.formulas } : void 0
  };
}
function clampAggregationsForMetricType(query, metricType) {
  const next = deepClone(query);
  next.metricType = metricType;
  const timeOpts = timeAggOps(metricType);
  const spaceOpts = spaceAggOps(metricType);
  if (!timeOpts.some((o) => o.value === next.timeAggregation)) {
    next.timeAggregation = timeOpts[0]?.value ?? "rate";
  }
  if (!spaceOpts.some((o) => o.value === next.spaceAggregation)) {
    next.spaceAggregation = spaceOpts[0]?.value ?? "sum";
  }
  return next;
}
function addFunction(state2, queryIndex, mode2) {
  return {
    queries: state2.queries.map((q, i) => {
      if (i !== queryIndex) return deepClone(q);
      const next = deepClone(q);
      if (next.functions.length >= 3) return next;
      const opts = functionOptionsForSignal(currentSignal(next, mode2));
      next.functions = [
        ...next.functions,
        { name: opts[0]?.value ?? "cutOffMin", arg: "" }
      ];
      return next;
    }),
    formulas: state2.formulas.map(deepClone)
  };
}
function removeFunction(state2, queryIndex, functionIndex) {
  return {
    queries: state2.queries.map((q, i) => {
      if (i !== queryIndex) return deepClone(q);
      const next = deepClone(q);
      next.functions = next.functions.filter((_, fi) => fi !== functionIndex);
      return next;
    }),
    formulas: state2.formulas.map(deepClone)
  };
}
const AGG_OPS = [
  { value: "count", label: "Count", acceptsArgs: false, multiple: false },
  {
    value: "count_distinct",
    label: "Count Distinct",
    acceptsArgs: true,
    multiple: true
  },
  { value: "sum", label: "Sum", acceptsArgs: true, multiple: false },
  { value: "avg", label: "Avg", acceptsArgs: true, multiple: false },
  { value: "max", label: "Max", acceptsArgs: true, multiple: false },
  { value: "min", label: "Min", acceptsArgs: true, multiple: false },
  { value: "p05", label: "P05", acceptsArgs: true, multiple: false },
  { value: "p10", label: "P10", acceptsArgs: true, multiple: false },
  { value: "p20", label: "P20", acceptsArgs: true, multiple: false },
  { value: "p25", label: "P25", acceptsArgs: true, multiple: false },
  { value: "p50", label: "P50", acceptsArgs: true, multiple: false },
  { value: "p75", label: "P75", acceptsArgs: true, multiple: false },
  { value: "p90", label: "P90", acceptsArgs: true, multiple: false },
  { value: "p95", label: "P95", acceptsArgs: true, multiple: false },
  { value: "p99", label: "P99", acceptsArgs: true, multiple: false },
  { value: "rate", label: "Rate", acceptsArgs: false, multiple: false },
  { value: "rate_sum", label: "Rate Sum", acceptsArgs: true, multiple: false },
  { value: "rate_avg", label: "Rate Avg", acceptsArgs: true, multiple: false },
  { value: "rate_min", label: "Rate Min", acceptsArgs: true, multiple: false },
  { value: "rate_max", label: "Rate Max", acceptsArgs: true, multiple: false },
  { value: "noop", label: "Noop", acceptsArgs: false, multiple: false }
];
const VALID_FUNCS = new Set(AGG_OPS.map((o) => o.value));
const ANY_TYPE_OPS = /* @__PURE__ */ new Set(["count", "count_distinct", "rate", "noop"]);
const NUMERIC_ONLY_OPS = new Set(
  AGG_OPS.map((o) => o.value).filter((v) => !ANY_TYPE_OPS.has(v))
);
function opMeta(name) {
  return AGG_OPS.find((o) => o.value === name.toLowerCase());
}
function getFunctionContextAtCursor(text, cursorPos) {
  let openParenIndex = -1;
  let funcName = null;
  let parenStack = 0;
  for (let i = cursorPos - 1; i >= 0; i--) {
    if (text[i] === ")") parenStack++;
    else if (text[i] === "(") {
      if (parenStack === 0) {
        openParenIndex = i;
        const before = text.slice(0, i);
        const match = before.match(/(\w+)\s*$/);
        if (match) funcName = match[1].toLowerCase();
        break;
      }
      parenStack--;
    }
  }
  if (openParenIndex === -1 || !funcName) return null;
  let closeParenIndex = -1;
  let depth = 1;
  for (let j = openParenIndex + 1; j < text.length; j++) {
    if (text[j] === "(") depth++;
    else if (text[j] === ")") depth--;
    if (depth === 0) {
      closeParenIndex = j;
      break;
    }
  }
  if (cursorPos > openParenIndex && (closeParenIndex === -1 || cursorPos <= closeParenIndex)) {
    return funcName;
  }
  return null;
}
function validateAggregations(text) {
  if (!text.trim()) return null;
  if (/([a-z_]\w*)\s*\([^)]*$/i.test(text)) {
    return "Incomplete function call — missing closing parenthesis";
  }
  const re = /([a-z_]\w*)\s*\(([^)]*)\)/gi;
  let m;
  let sawCount = false;
  while ((m = re.exec(text)) !== null) {
    const fn = m[1].toLowerCase();
    if (!VALID_FUNCS.has(fn)) return `Unknown function: ${fn}`;
    const meta2 = opMeta(fn);
    if (meta2?.acceptsArgs && m[2].trim() === "") {
      return `Function ${fn}() requires arguments`;
    }
    if (fn === "count") {
      if (sawCount) return "count() may appear only once";
      sawCount = true;
    }
  }
  return null;
}
function requiresNumericFieldKeys(funcName) {
  return NUMERIC_ONLY_OPS.has(funcName.toLowerCase());
}
const _hoisted_1$9 = ["data-testid"];
const _hoisted_2$8 = {
  key: 0,
  class: "qae-interval"
};
const _hoisted_3$7 = { class: "qae-interval-label" };
const _hoisted_4$5 = { class: "qae-step-box" };
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
  __name: "QueryAggregationEditor",
  props: {
    modelValue: {},
    signal: { default: "traces" },
    showInterval: { type: Boolean, default: false },
    stepInterval: { default: null },
    loadKeys: {},
    testId: {}
  },
  emits: ["update:modelValue", "update:stepInterval", "run"],
  setup(__props, { emit: __emit }) {
    const CHIP_PATTERN = /\b([a-z_]\w*)\s*\(([^)]*)\)/gi;
    function chipValidate(_matched, groups) {
      return VALID_FUNCS.has((groups[0] || "").toLowerCase());
    }
    const props = __props;
    const emit = __emit;
    const validationError = computed(() => validateAggregations(props.modelValue || ""));
    const stepLocal = ref(
      props.stepInterval == null ? "" : String(props.stepInterval)
    );
    watch(
      () => props.stepInterval,
      (v) => {
        stepLocal.value = v == null ? "" : String(v);
      }
    );
    function onStepInput(v) {
      stepLocal.value = v;
      if (v.trim() === "") {
        emit("update:stepInterval", null);
        return;
      }
      const n = Number(v);
      if (Number.isFinite(n) && n >= 1) emit("update:stepInterval", Math.floor(n));
    }
    async function completionSource(context) {
      const text = context.state.doc.toString();
      const pos = context.pos;
      const func = getFunctionContextAtCursor(text, pos);
      if (func && props.loadKeys) {
        const word2 = context.matchBefore(/[\w./-]*$/);
        const from2 = word2?.from ?? pos;
        const search = word2?.text ?? "";
        const keys = await props.loadKeys({
          signal: props.signal || "traces",
          searchText: search,
          fieldDataType: requiresNumericFieldKeys(func) ? "number" : void 0
        });
        return {
          from: from2,
          options: keys.map((k) => ({
            label: k.name,
            type: "variable",
            detail: k.dataType || "",
            apply: k.name
          }))
        };
      }
      const word = context.matchBefore(/[a-zA-Z_][\w]*/);
      if (!word && !context.explicit) return null;
      const from = word?.from ?? pos;
      const prefix = (word?.text || "").toLowerCase();
      const options = AGG_OPS.filter((o) => o.value.startsWith(prefix) || !prefix).map(
        (o) => ({
          label: o.value,
          type: "keyword",
          detail: o.label,
          apply: o.acceptsArgs ? `${o.value}(` : `${o.value}()`
        })
      );
      return options.length ? { from, options } : null;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "qae",
        "data-testid": __props.testId || "query-aggregation-editor"
      }, [
        createElementVNode(
          "div",
          {
            class: normalizeClass(["qae-editor-wrap", { "qae-editor-wrap--error": Boolean(validationError.value) }])
          },
          [
            createVNode(unref(GQueryExpressionEditor), {
              "model-value": __props.modelValue,
              "completion-source": completionSource,
              invalid: Boolean(validationError.value),
              placeholder: "count()",
              "aria-label": unref(t)("signoz.queryBuilder.agg", "聚合"),
              "chip-pattern": CHIP_PATTERN,
              "chip-validate": chipValidate,
              embedded: true,
              "font-size": 13,
              "test-id": "query-aggregation-cm",
              "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", $event)),
              onRun: _cache[1] || (_cache[1] = ($event) => emit("run"))
            }, null, 8, ["model-value", "completion-source", "invalid", "aria-label"]),
            validationError.value ? (openBlock(), createBlock(unref(_sfc_main$34), {
              key: 0,
              title: validationError.value
            }, {
              default: withCtx(() => [..._cache[3] || (_cache[3] = [
                createElementVNode(
                  "span",
                  {
                    class: "qae-error",
                    "aria-label": "validation error"
                  },
                  "!",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            }, 8, ["title"])) : (openBlock(), createBlock(unref(_sfc_main$34), {
              key: 1,
              title: "聚合函数：count / sum / avg / min / max / pXX / rate / count_distinct"
            }, {
              default: withCtx(() => [
                createVNode(unref(GIcon), {
                  name: "info",
                  size: 14,
                  class: "qae-info-icon"
                })
              ]),
              _: 1
              /* STABLE */
            }))
          ],
          2
          /* CLASS */
        ),
        __props.showInterval ? (openBlock(), createElementBlock("div", _hoisted_2$8, [
          createElementVNode(
            "span",
            _hoisted_3$7,
            toDisplayString(unref(t)("signoz.queryBuilder.step")),
            1
            /* TEXT */
          ),
          createElementVNode("div", _hoisted_4$5, [
            createVNode(unref(GInput), {
              class: "qae-step-input",
              "model-value": stepLocal.value,
              type: "number",
              placeholder: unref(t)("signoz.queryBuilder.stepAuto"),
              "data-testid": "query-aggregation-step",
              "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => onStepInput(String($event ?? "")))
            }, null, 8, ["model-value", "placeholder"]),
            _cache[4] || (_cache[4] = createElementVNode(
              "div",
              {
                class: "qae-step-controls",
                "aria-hidden": "true"
              },
              [
                createElementVNode("span", { class: "qae-step-btn qae-step-btn--up" }),
                createElementVNode("span", { class: "qae-step-btn qae-step-btn--down" })
              ],
              -1
              /* CACHED */
            ))
          ]),
          _cache[5] || (_cache[5] = createElementVNode(
            "span",
            { class: "qae-interval-unit" },
            "s",
            -1
            /* CACHED */
          ))
        ])) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$9);
    };
  }
});
const QueryAggregationEditor = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__scopeId", "data-v-364c092d"]]);
const OPERATORS = {
  "EXISTS": "EXISTS",
  "NOT": "NOT"
};
const NON_VALUE_OPERATORS = [OPERATORS.EXISTS];
class FilterQueryLexer extends Lexer {
  static LPAREN = 1;
  static RPAREN = 2;
  static LBRACK = 3;
  static RBRACK = 4;
  static COMMA = 5;
  static EQUALS = 6;
  static NOT_EQUALS = 7;
  static NEQ = 8;
  static LT = 9;
  static LE = 10;
  static GT = 11;
  static GE = 12;
  static LIKE = 13;
  static ILIKE = 14;
  static BETWEEN = 15;
  static EXISTS = 16;
  static REGEXP = 17;
  static CONTAINS = 18;
  static IN = 19;
  static NOT = 20;
  static AND = 21;
  static OR = 22;
  static HASTOKEN = 23;
  static HAS = 24;
  static HASANY = 25;
  static HASALL = 26;
  static BOOL = 27;
  static NUMBER = 28;
  static QUOTED_TEXT = 29;
  static KEY = 30;
  static WS = 31;
  static FREETEXT = 32;
  static EOF = Token.EOF;
  static channelNames = ["DEFAULT_TOKEN_CHANNEL", "HIDDEN"];
  static literalNames = [
    null,
    "'('",
    "')'",
    "'['",
    "']'",
    "','",
    null,
    "'!='",
    "'<>'",
    "'<'",
    "'<='",
    "'>'",
    "'>='"
  ];
  static symbolicNames = [
    null,
    "LPAREN",
    "RPAREN",
    "LBRACK",
    "RBRACK",
    "COMMA",
    "EQUALS",
    "NOT_EQUALS",
    "NEQ",
    "LT",
    "LE",
    "GT",
    "GE",
    "LIKE",
    "ILIKE",
    "BETWEEN",
    "EXISTS",
    "REGEXP",
    "CONTAINS",
    "IN",
    "NOT",
    "AND",
    "OR",
    "HASTOKEN",
    "HAS",
    "HASANY",
    "HASALL",
    "BOOL",
    "NUMBER",
    "QUOTED_TEXT",
    "KEY",
    "WS",
    "FREETEXT"
  ];
  static modeNames = ["DEFAULT_MODE"];
  static ruleNames = [
    "LPAREN",
    "RPAREN",
    "LBRACK",
    "RBRACK",
    "COMMA",
    "EQUALS",
    "NOT_EQUALS",
    "NEQ",
    "LT",
    "LE",
    "GT",
    "GE",
    "LIKE",
    "ILIKE",
    "BETWEEN",
    "EXISTS",
    "REGEXP",
    "CONTAINS",
    "IN",
    "NOT",
    "AND",
    "OR",
    "HASTOKEN",
    "HAS",
    "HASANY",
    "HASALL",
    "BOOL",
    "SIGN",
    "NUMBER",
    "QUOTED_TEXT",
    "SEGMENT",
    "EMPTY_BRACKS",
    "OLD_JSON_BRACKS",
    "KEY",
    "WS",
    "DIGIT",
    "FREETEXT"
  ];
  constructor(input) {
    super(input);
    this._interp = new LexerATNSimulator(
      this,
      FilterQueryLexer._ATN,
      FilterQueryLexer.DecisionsToDFA,
      new PredictionContextCache()
    );
  }
  get grammarFileName() {
    return "FilterQuery.g4";
  }
  get literalNames() {
    return FilterQueryLexer.literalNames;
  }
  get symbolicNames() {
    return FilterQueryLexer.symbolicNames;
  }
  get ruleNames() {
    return FilterQueryLexer.ruleNames;
  }
  get serializedATN() {
    return FilterQueryLexer._serializedATN;
  }
  get channelNames() {
    return FilterQueryLexer.channelNames;
  }
  get modeNames() {
    return FilterQueryLexer.modeNames;
  }
  static _serializedATN = [
    4,
    0,
    32,
    320,
    6,
    -1,
    2,
    0,
    7,
    0,
    2,
    1,
    7,
    1,
    2,
    2,
    7,
    2,
    2,
    3,
    7,
    3,
    2,
    4,
    7,
    4,
    2,
    5,
    7,
    5,
    2,
    6,
    7,
    6,
    2,
    7,
    7,
    7,
    2,
    8,
    7,
    8,
    2,
    9,
    7,
    9,
    2,
    10,
    7,
    10,
    2,
    11,
    7,
    11,
    2,
    12,
    7,
    12,
    2,
    13,
    7,
    13,
    2,
    14,
    7,
    14,
    2,
    15,
    7,
    15,
    2,
    16,
    7,
    16,
    2,
    17,
    7,
    17,
    2,
    18,
    7,
    18,
    2,
    19,
    7,
    19,
    2,
    20,
    7,
    20,
    2,
    21,
    7,
    21,
    2,
    22,
    7,
    22,
    2,
    23,
    7,
    23,
    2,
    24,
    7,
    24,
    2,
    25,
    7,
    25,
    2,
    26,
    7,
    26,
    2,
    27,
    7,
    27,
    2,
    28,
    7,
    28,
    2,
    29,
    7,
    29,
    2,
    30,
    7,
    30,
    2,
    31,
    7,
    31,
    2,
    32,
    7,
    32,
    2,
    33,
    7,
    33,
    2,
    34,
    7,
    34,
    2,
    35,
    7,
    35,
    2,
    36,
    7,
    36,
    1,
    0,
    1,
    0,
    1,
    1,
    1,
    1,
    1,
    2,
    1,
    2,
    1,
    3,
    1,
    3,
    1,
    4,
    1,
    4,
    1,
    5,
    1,
    5,
    1,
    5,
    3,
    5,
    89,
    8,
    5,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    8,
    1,
    8,
    1,
    9,
    1,
    9,
    1,
    9,
    1,
    10,
    1,
    10,
    1,
    11,
    1,
    11,
    1,
    11,
    1,
    12,
    1,
    12,
    1,
    12,
    1,
    12,
    1,
    12,
    1,
    13,
    1,
    13,
    1,
    13,
    1,
    13,
    1,
    13,
    1,
    13,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    15,
    1,
    15,
    1,
    15,
    1,
    15,
    1,
    15,
    1,
    15,
    3,
    15,
    132,
    8,
    15,
    1,
    16,
    1,
    16,
    1,
    16,
    1,
    16,
    1,
    16,
    1,
    16,
    1,
    16,
    1,
    17,
    1,
    17,
    1,
    17,
    1,
    17,
    1,
    17,
    1,
    17,
    1,
    17,
    1,
    17,
    3,
    17,
    149,
    8,
    17,
    1,
    18,
    1,
    18,
    1,
    18,
    1,
    19,
    1,
    19,
    1,
    19,
    1,
    19,
    1,
    20,
    1,
    20,
    1,
    20,
    1,
    20,
    1,
    21,
    1,
    21,
    1,
    21,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    22,
    1,
    23,
    1,
    23,
    1,
    23,
    1,
    23,
    1,
    24,
    1,
    24,
    1,
    24,
    1,
    24,
    1,
    24,
    1,
    24,
    1,
    24,
    1,
    25,
    1,
    25,
    1,
    25,
    1,
    25,
    1,
    25,
    1,
    25,
    1,
    25,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    1,
    26,
    3,
    26,
    201,
    8,
    26,
    1,
    27,
    1,
    27,
    1,
    28,
    3,
    28,
    206,
    8,
    28,
    1,
    28,
    4,
    28,
    209,
    8,
    28,
    11,
    28,
    12,
    28,
    210,
    1,
    28,
    1,
    28,
    5,
    28,
    215,
    8,
    28,
    10,
    28,
    12,
    28,
    218,
    9,
    28,
    3,
    28,
    220,
    8,
    28,
    1,
    28,
    1,
    28,
    3,
    28,
    224,
    8,
    28,
    1,
    28,
    4,
    28,
    227,
    8,
    28,
    11,
    28,
    12,
    28,
    228,
    3,
    28,
    231,
    8,
    28,
    1,
    28,
    3,
    28,
    234,
    8,
    28,
    1,
    28,
    1,
    28,
    4,
    28,
    238,
    8,
    28,
    11,
    28,
    12,
    28,
    239,
    1,
    28,
    1,
    28,
    3,
    28,
    244,
    8,
    28,
    1,
    28,
    4,
    28,
    247,
    8,
    28,
    11,
    28,
    12,
    28,
    248,
    3,
    28,
    251,
    8,
    28,
    3,
    28,
    253,
    8,
    28,
    1,
    29,
    1,
    29,
    1,
    29,
    1,
    29,
    5,
    29,
    259,
    8,
    29,
    10,
    29,
    12,
    29,
    262,
    9,
    29,
    1,
    29,
    1,
    29,
    1,
    29,
    1,
    29,
    1,
    29,
    5,
    29,
    269,
    8,
    29,
    10,
    29,
    12,
    29,
    272,
    9,
    29,
    1,
    29,
    3,
    29,
    275,
    8,
    29,
    1,
    30,
    1,
    30,
    5,
    30,
    279,
    8,
    30,
    10,
    30,
    12,
    30,
    282,
    9,
    30,
    1,
    31,
    1,
    31,
    1,
    31,
    1,
    32,
    1,
    32,
    1,
    32,
    1,
    32,
    1,
    33,
    1,
    33,
    1,
    33,
    1,
    33,
    1,
    33,
    1,
    33,
    1,
    33,
    4,
    33,
    298,
    8,
    33,
    11,
    33,
    12,
    33,
    299,
    5,
    33,
    302,
    8,
    33,
    10,
    33,
    12,
    33,
    305,
    9,
    33,
    1,
    34,
    4,
    34,
    308,
    8,
    34,
    11,
    34,
    12,
    34,
    309,
    1,
    34,
    1,
    34,
    1,
    35,
    1,
    35,
    1,
    36,
    4,
    36,
    317,
    8,
    36,
    11,
    36,
    12,
    36,
    318,
    0,
    0,
    37,
    1,
    1,
    3,
    2,
    5,
    3,
    7,
    4,
    9,
    5,
    11,
    6,
    13,
    7,
    15,
    8,
    17,
    9,
    19,
    10,
    21,
    11,
    23,
    12,
    25,
    13,
    27,
    14,
    29,
    15,
    31,
    16,
    33,
    17,
    35,
    18,
    37,
    19,
    39,
    20,
    41,
    21,
    43,
    22,
    45,
    23,
    47,
    24,
    49,
    25,
    51,
    26,
    53,
    27,
    55,
    0,
    57,
    28,
    59,
    29,
    61,
    0,
    63,
    0,
    65,
    0,
    67,
    30,
    69,
    31,
    71,
    0,
    73,
    32,
    1,
    0,
    29,
    2,
    0,
    76,
    76,
    108,
    108,
    2,
    0,
    73,
    73,
    105,
    105,
    2,
    0,
    75,
    75,
    107,
    107,
    2,
    0,
    69,
    69,
    101,
    101,
    2,
    0,
    66,
    66,
    98,
    98,
    2,
    0,
    84,
    84,
    116,
    116,
    2,
    0,
    87,
    87,
    119,
    119,
    2,
    0,
    78,
    78,
    110,
    110,
    2,
    0,
    88,
    88,
    120,
    120,
    2,
    0,
    83,
    83,
    115,
    115,
    2,
    0,
    82,
    82,
    114,
    114,
    2,
    0,
    71,
    71,
    103,
    103,
    2,
    0,
    80,
    80,
    112,
    112,
    2,
    0,
    67,
    67,
    99,
    99,
    2,
    0,
    79,
    79,
    111,
    111,
    2,
    0,
    65,
    65,
    97,
    97,
    2,
    0,
    68,
    68,
    100,
    100,
    2,
    0,
    72,
    72,
    104,
    104,
    2,
    0,
    89,
    89,
    121,
    121,
    2,
    0,
    85,
    85,
    117,
    117,
    2,
    0,
    70,
    70,
    102,
    102,
    2,
    0,
    43,
    43,
    45,
    45,
    2,
    0,
    34,
    34,
    92,
    92,
    2,
    0,
    39,
    39,
    92,
    92,
    4,
    0,
    35,
    36,
    64,
    90,
    95,
    95,
    97,
    123,
    7,
    0,
    35,
    36,
    45,
    45,
    47,
    58,
    64,
    90,
    95,
    95,
    97,
    123,
    125,
    125,
    3,
    0,
    9,
    10,
    13,
    13,
    32,
    32,
    1,
    0,
    48,
    57,
    8,
    0,
    9,
    10,
    13,
    13,
    32,
    34,
    39,
    41,
    44,
    44,
    60,
    62,
    91,
    91,
    93,
    93,
    344,
    0,
    1,
    1,
    0,
    0,
    0,
    0,
    3,
    1,
    0,
    0,
    0,
    0,
    5,
    1,
    0,
    0,
    0,
    0,
    7,
    1,
    0,
    0,
    0,
    0,
    9,
    1,
    0,
    0,
    0,
    0,
    11,
    1,
    0,
    0,
    0,
    0,
    13,
    1,
    0,
    0,
    0,
    0,
    15,
    1,
    0,
    0,
    0,
    0,
    17,
    1,
    0,
    0,
    0,
    0,
    19,
    1,
    0,
    0,
    0,
    0,
    21,
    1,
    0,
    0,
    0,
    0,
    23,
    1,
    0,
    0,
    0,
    0,
    25,
    1,
    0,
    0,
    0,
    0,
    27,
    1,
    0,
    0,
    0,
    0,
    29,
    1,
    0,
    0,
    0,
    0,
    31,
    1,
    0,
    0,
    0,
    0,
    33,
    1,
    0,
    0,
    0,
    0,
    35,
    1,
    0,
    0,
    0,
    0,
    37,
    1,
    0,
    0,
    0,
    0,
    39,
    1,
    0,
    0,
    0,
    0,
    41,
    1,
    0,
    0,
    0,
    0,
    43,
    1,
    0,
    0,
    0,
    0,
    45,
    1,
    0,
    0,
    0,
    0,
    47,
    1,
    0,
    0,
    0,
    0,
    49,
    1,
    0,
    0,
    0,
    0,
    51,
    1,
    0,
    0,
    0,
    0,
    53,
    1,
    0,
    0,
    0,
    0,
    57,
    1,
    0,
    0,
    0,
    0,
    59,
    1,
    0,
    0,
    0,
    0,
    67,
    1,
    0,
    0,
    0,
    0,
    69,
    1,
    0,
    0,
    0,
    0,
    73,
    1,
    0,
    0,
    0,
    1,
    75,
    1,
    0,
    0,
    0,
    3,
    77,
    1,
    0,
    0,
    0,
    5,
    79,
    1,
    0,
    0,
    0,
    7,
    81,
    1,
    0,
    0,
    0,
    9,
    83,
    1,
    0,
    0,
    0,
    11,
    88,
    1,
    0,
    0,
    0,
    13,
    90,
    1,
    0,
    0,
    0,
    15,
    93,
    1,
    0,
    0,
    0,
    17,
    96,
    1,
    0,
    0,
    0,
    19,
    98,
    1,
    0,
    0,
    0,
    21,
    101,
    1,
    0,
    0,
    0,
    23,
    103,
    1,
    0,
    0,
    0,
    25,
    106,
    1,
    0,
    0,
    0,
    27,
    111,
    1,
    0,
    0,
    0,
    29,
    117,
    1,
    0,
    0,
    0,
    31,
    125,
    1,
    0,
    0,
    0,
    33,
    133,
    1,
    0,
    0,
    0,
    35,
    140,
    1,
    0,
    0,
    0,
    37,
    150,
    1,
    0,
    0,
    0,
    39,
    153,
    1,
    0,
    0,
    0,
    41,
    157,
    1,
    0,
    0,
    0,
    43,
    161,
    1,
    0,
    0,
    0,
    45,
    164,
    1,
    0,
    0,
    0,
    47,
    173,
    1,
    0,
    0,
    0,
    49,
    177,
    1,
    0,
    0,
    0,
    51,
    184,
    1,
    0,
    0,
    0,
    53,
    200,
    1,
    0,
    0,
    0,
    55,
    202,
    1,
    0,
    0,
    0,
    57,
    252,
    1,
    0,
    0,
    0,
    59,
    274,
    1,
    0,
    0,
    0,
    61,
    276,
    1,
    0,
    0,
    0,
    63,
    283,
    1,
    0,
    0,
    0,
    65,
    286,
    1,
    0,
    0,
    0,
    67,
    290,
    1,
    0,
    0,
    0,
    69,
    307,
    1,
    0,
    0,
    0,
    71,
    313,
    1,
    0,
    0,
    0,
    73,
    316,
    1,
    0,
    0,
    0,
    75,
    76,
    5,
    40,
    0,
    0,
    76,
    2,
    1,
    0,
    0,
    0,
    77,
    78,
    5,
    41,
    0,
    0,
    78,
    4,
    1,
    0,
    0,
    0,
    79,
    80,
    5,
    91,
    0,
    0,
    80,
    6,
    1,
    0,
    0,
    0,
    81,
    82,
    5,
    93,
    0,
    0,
    82,
    8,
    1,
    0,
    0,
    0,
    83,
    84,
    5,
    44,
    0,
    0,
    84,
    10,
    1,
    0,
    0,
    0,
    85,
    89,
    5,
    61,
    0,
    0,
    86,
    87,
    5,
    61,
    0,
    0,
    87,
    89,
    5,
    61,
    0,
    0,
    88,
    85,
    1,
    0,
    0,
    0,
    88,
    86,
    1,
    0,
    0,
    0,
    89,
    12,
    1,
    0,
    0,
    0,
    90,
    91,
    5,
    33,
    0,
    0,
    91,
    92,
    5,
    61,
    0,
    0,
    92,
    14,
    1,
    0,
    0,
    0,
    93,
    94,
    5,
    60,
    0,
    0,
    94,
    95,
    5,
    62,
    0,
    0,
    95,
    16,
    1,
    0,
    0,
    0,
    96,
    97,
    5,
    60,
    0,
    0,
    97,
    18,
    1,
    0,
    0,
    0,
    98,
    99,
    5,
    60,
    0,
    0,
    99,
    100,
    5,
    61,
    0,
    0,
    100,
    20,
    1,
    0,
    0,
    0,
    101,
    102,
    5,
    62,
    0,
    0,
    102,
    22,
    1,
    0,
    0,
    0,
    103,
    104,
    5,
    62,
    0,
    0,
    104,
    105,
    5,
    61,
    0,
    0,
    105,
    24,
    1,
    0,
    0,
    0,
    106,
    107,
    7,
    0,
    0,
    0,
    107,
    108,
    7,
    1,
    0,
    0,
    108,
    109,
    7,
    2,
    0,
    0,
    109,
    110,
    7,
    3,
    0,
    0,
    110,
    26,
    1,
    0,
    0,
    0,
    111,
    112,
    7,
    1,
    0,
    0,
    112,
    113,
    7,
    0,
    0,
    0,
    113,
    114,
    7,
    1,
    0,
    0,
    114,
    115,
    7,
    2,
    0,
    0,
    115,
    116,
    7,
    3,
    0,
    0,
    116,
    28,
    1,
    0,
    0,
    0,
    117,
    118,
    7,
    4,
    0,
    0,
    118,
    119,
    7,
    3,
    0,
    0,
    119,
    120,
    7,
    5,
    0,
    0,
    120,
    121,
    7,
    6,
    0,
    0,
    121,
    122,
    7,
    3,
    0,
    0,
    122,
    123,
    7,
    3,
    0,
    0,
    123,
    124,
    7,
    7,
    0,
    0,
    124,
    30,
    1,
    0,
    0,
    0,
    125,
    126,
    7,
    3,
    0,
    0,
    126,
    127,
    7,
    8,
    0,
    0,
    127,
    128,
    7,
    1,
    0,
    0,
    128,
    129,
    7,
    9,
    0,
    0,
    129,
    131,
    7,
    5,
    0,
    0,
    130,
    132,
    7,
    9,
    0,
    0,
    131,
    130,
    1,
    0,
    0,
    0,
    131,
    132,
    1,
    0,
    0,
    0,
    132,
    32,
    1,
    0,
    0,
    0,
    133,
    134,
    7,
    10,
    0,
    0,
    134,
    135,
    7,
    3,
    0,
    0,
    135,
    136,
    7,
    11,
    0,
    0,
    136,
    137,
    7,
    3,
    0,
    0,
    137,
    138,
    7,
    8,
    0,
    0,
    138,
    139,
    7,
    12,
    0,
    0,
    139,
    34,
    1,
    0,
    0,
    0,
    140,
    141,
    7,
    13,
    0,
    0,
    141,
    142,
    7,
    14,
    0,
    0,
    142,
    143,
    7,
    7,
    0,
    0,
    143,
    144,
    7,
    5,
    0,
    0,
    144,
    145,
    7,
    15,
    0,
    0,
    145,
    146,
    7,
    1,
    0,
    0,
    146,
    148,
    7,
    7,
    0,
    0,
    147,
    149,
    7,
    9,
    0,
    0,
    148,
    147,
    1,
    0,
    0,
    0,
    148,
    149,
    1,
    0,
    0,
    0,
    149,
    36,
    1,
    0,
    0,
    0,
    150,
    151,
    7,
    1,
    0,
    0,
    151,
    152,
    7,
    7,
    0,
    0,
    152,
    38,
    1,
    0,
    0,
    0,
    153,
    154,
    7,
    7,
    0,
    0,
    154,
    155,
    7,
    14,
    0,
    0,
    155,
    156,
    7,
    5,
    0,
    0,
    156,
    40,
    1,
    0,
    0,
    0,
    157,
    158,
    7,
    15,
    0,
    0,
    158,
    159,
    7,
    7,
    0,
    0,
    159,
    160,
    7,
    16,
    0,
    0,
    160,
    42,
    1,
    0,
    0,
    0,
    161,
    162,
    7,
    14,
    0,
    0,
    162,
    163,
    7,
    10,
    0,
    0,
    163,
    44,
    1,
    0,
    0,
    0,
    164,
    165,
    7,
    17,
    0,
    0,
    165,
    166,
    7,
    15,
    0,
    0,
    166,
    167,
    7,
    9,
    0,
    0,
    167,
    168,
    7,
    5,
    0,
    0,
    168,
    169,
    7,
    14,
    0,
    0,
    169,
    170,
    7,
    2,
    0,
    0,
    170,
    171,
    7,
    3,
    0,
    0,
    171,
    172,
    7,
    7,
    0,
    0,
    172,
    46,
    1,
    0,
    0,
    0,
    173,
    174,
    7,
    17,
    0,
    0,
    174,
    175,
    7,
    15,
    0,
    0,
    175,
    176,
    7,
    9,
    0,
    0,
    176,
    48,
    1,
    0,
    0,
    0,
    177,
    178,
    7,
    17,
    0,
    0,
    178,
    179,
    7,
    15,
    0,
    0,
    179,
    180,
    7,
    9,
    0,
    0,
    180,
    181,
    7,
    15,
    0,
    0,
    181,
    182,
    7,
    7,
    0,
    0,
    182,
    183,
    7,
    18,
    0,
    0,
    183,
    50,
    1,
    0,
    0,
    0,
    184,
    185,
    7,
    17,
    0,
    0,
    185,
    186,
    7,
    15,
    0,
    0,
    186,
    187,
    7,
    9,
    0,
    0,
    187,
    188,
    7,
    15,
    0,
    0,
    188,
    189,
    7,
    0,
    0,
    0,
    189,
    190,
    7,
    0,
    0,
    0,
    190,
    52,
    1,
    0,
    0,
    0,
    191,
    192,
    7,
    5,
    0,
    0,
    192,
    193,
    7,
    10,
    0,
    0,
    193,
    194,
    7,
    19,
    0,
    0,
    194,
    201,
    7,
    3,
    0,
    0,
    195,
    196,
    7,
    20,
    0,
    0,
    196,
    197,
    7,
    15,
    0,
    0,
    197,
    198,
    7,
    0,
    0,
    0,
    198,
    199,
    7,
    9,
    0,
    0,
    199,
    201,
    7,
    3,
    0,
    0,
    200,
    191,
    1,
    0,
    0,
    0,
    200,
    195,
    1,
    0,
    0,
    0,
    201,
    54,
    1,
    0,
    0,
    0,
    202,
    203,
    7,
    21,
    0,
    0,
    203,
    56,
    1,
    0,
    0,
    0,
    204,
    206,
    3,
    55,
    27,
    0,
    205,
    204,
    1,
    0,
    0,
    0,
    205,
    206,
    1,
    0,
    0,
    0,
    206,
    208,
    1,
    0,
    0,
    0,
    207,
    209,
    3,
    71,
    35,
    0,
    208,
    207,
    1,
    0,
    0,
    0,
    209,
    210,
    1,
    0,
    0,
    0,
    210,
    208,
    1,
    0,
    0,
    0,
    210,
    211,
    1,
    0,
    0,
    0,
    211,
    219,
    1,
    0,
    0,
    0,
    212,
    216,
    5,
    46,
    0,
    0,
    213,
    215,
    3,
    71,
    35,
    0,
    214,
    213,
    1,
    0,
    0,
    0,
    215,
    218,
    1,
    0,
    0,
    0,
    216,
    214,
    1,
    0,
    0,
    0,
    216,
    217,
    1,
    0,
    0,
    0,
    217,
    220,
    1,
    0,
    0,
    0,
    218,
    216,
    1,
    0,
    0,
    0,
    219,
    212,
    1,
    0,
    0,
    0,
    219,
    220,
    1,
    0,
    0,
    0,
    220,
    230,
    1,
    0,
    0,
    0,
    221,
    223,
    7,
    3,
    0,
    0,
    222,
    224,
    3,
    55,
    27,
    0,
    223,
    222,
    1,
    0,
    0,
    0,
    223,
    224,
    1,
    0,
    0,
    0,
    224,
    226,
    1,
    0,
    0,
    0,
    225,
    227,
    3,
    71,
    35,
    0,
    226,
    225,
    1,
    0,
    0,
    0,
    227,
    228,
    1,
    0,
    0,
    0,
    228,
    226,
    1,
    0,
    0,
    0,
    228,
    229,
    1,
    0,
    0,
    0,
    229,
    231,
    1,
    0,
    0,
    0,
    230,
    221,
    1,
    0,
    0,
    0,
    230,
    231,
    1,
    0,
    0,
    0,
    231,
    253,
    1,
    0,
    0,
    0,
    232,
    234,
    3,
    55,
    27,
    0,
    233,
    232,
    1,
    0,
    0,
    0,
    233,
    234,
    1,
    0,
    0,
    0,
    234,
    235,
    1,
    0,
    0,
    0,
    235,
    237,
    5,
    46,
    0,
    0,
    236,
    238,
    3,
    71,
    35,
    0,
    237,
    236,
    1,
    0,
    0,
    0,
    238,
    239,
    1,
    0,
    0,
    0,
    239,
    237,
    1,
    0,
    0,
    0,
    239,
    240,
    1,
    0,
    0,
    0,
    240,
    250,
    1,
    0,
    0,
    0,
    241,
    243,
    7,
    3,
    0,
    0,
    242,
    244,
    3,
    55,
    27,
    0,
    243,
    242,
    1,
    0,
    0,
    0,
    243,
    244,
    1,
    0,
    0,
    0,
    244,
    246,
    1,
    0,
    0,
    0,
    245,
    247,
    3,
    71,
    35,
    0,
    246,
    245,
    1,
    0,
    0,
    0,
    247,
    248,
    1,
    0,
    0,
    0,
    248,
    246,
    1,
    0,
    0,
    0,
    248,
    249,
    1,
    0,
    0,
    0,
    249,
    251,
    1,
    0,
    0,
    0,
    250,
    241,
    1,
    0,
    0,
    0,
    250,
    251,
    1,
    0,
    0,
    0,
    251,
    253,
    1,
    0,
    0,
    0,
    252,
    205,
    1,
    0,
    0,
    0,
    252,
    233,
    1,
    0,
    0,
    0,
    253,
    58,
    1,
    0,
    0,
    0,
    254,
    260,
    5,
    34,
    0,
    0,
    255,
    259,
    8,
    22,
    0,
    0,
    256,
    257,
    5,
    92,
    0,
    0,
    257,
    259,
    9,
    0,
    0,
    0,
    258,
    255,
    1,
    0,
    0,
    0,
    258,
    256,
    1,
    0,
    0,
    0,
    259,
    262,
    1,
    0,
    0,
    0,
    260,
    258,
    1,
    0,
    0,
    0,
    260,
    261,
    1,
    0,
    0,
    0,
    261,
    263,
    1,
    0,
    0,
    0,
    262,
    260,
    1,
    0,
    0,
    0,
    263,
    275,
    5,
    34,
    0,
    0,
    264,
    270,
    5,
    39,
    0,
    0,
    265,
    269,
    8,
    23,
    0,
    0,
    266,
    267,
    5,
    92,
    0,
    0,
    267,
    269,
    9,
    0,
    0,
    0,
    268,
    265,
    1,
    0,
    0,
    0,
    268,
    266,
    1,
    0,
    0,
    0,
    269,
    272,
    1,
    0,
    0,
    0,
    270,
    268,
    1,
    0,
    0,
    0,
    270,
    271,
    1,
    0,
    0,
    0,
    271,
    273,
    1,
    0,
    0,
    0,
    272,
    270,
    1,
    0,
    0,
    0,
    273,
    275,
    5,
    39,
    0,
    0,
    274,
    254,
    1,
    0,
    0,
    0,
    274,
    264,
    1,
    0,
    0,
    0,
    275,
    60,
    1,
    0,
    0,
    0,
    276,
    280,
    7,
    24,
    0,
    0,
    277,
    279,
    7,
    25,
    0,
    0,
    278,
    277,
    1,
    0,
    0,
    0,
    279,
    282,
    1,
    0,
    0,
    0,
    280,
    278,
    1,
    0,
    0,
    0,
    280,
    281,
    1,
    0,
    0,
    0,
    281,
    62,
    1,
    0,
    0,
    0,
    282,
    280,
    1,
    0,
    0,
    0,
    283,
    284,
    5,
    91,
    0,
    0,
    284,
    285,
    5,
    93,
    0,
    0,
    285,
    64,
    1,
    0,
    0,
    0,
    286,
    287,
    5,
    91,
    0,
    0,
    287,
    288,
    5,
    42,
    0,
    0,
    288,
    289,
    5,
    93,
    0,
    0,
    289,
    66,
    1,
    0,
    0,
    0,
    290,
    303,
    3,
    61,
    30,
    0,
    291,
    292,
    5,
    46,
    0,
    0,
    292,
    302,
    3,
    61,
    30,
    0,
    293,
    302,
    3,
    63,
    31,
    0,
    294,
    302,
    3,
    65,
    32,
    0,
    295,
    297,
    5,
    46,
    0,
    0,
    296,
    298,
    3,
    71,
    35,
    0,
    297,
    296,
    1,
    0,
    0,
    0,
    298,
    299,
    1,
    0,
    0,
    0,
    299,
    297,
    1,
    0,
    0,
    0,
    299,
    300,
    1,
    0,
    0,
    0,
    300,
    302,
    1,
    0,
    0,
    0,
    301,
    291,
    1,
    0,
    0,
    0,
    301,
    293,
    1,
    0,
    0,
    0,
    301,
    294,
    1,
    0,
    0,
    0,
    301,
    295,
    1,
    0,
    0,
    0,
    302,
    305,
    1,
    0,
    0,
    0,
    303,
    301,
    1,
    0,
    0,
    0,
    303,
    304,
    1,
    0,
    0,
    0,
    304,
    68,
    1,
    0,
    0,
    0,
    305,
    303,
    1,
    0,
    0,
    0,
    306,
    308,
    7,
    26,
    0,
    0,
    307,
    306,
    1,
    0,
    0,
    0,
    308,
    309,
    1,
    0,
    0,
    0,
    309,
    307,
    1,
    0,
    0,
    0,
    309,
    310,
    1,
    0,
    0,
    0,
    310,
    311,
    1,
    0,
    0,
    0,
    311,
    312,
    6,
    34,
    0,
    0,
    312,
    70,
    1,
    0,
    0,
    0,
    313,
    314,
    7,
    27,
    0,
    0,
    314,
    72,
    1,
    0,
    0,
    0,
    315,
    317,
    8,
    28,
    0,
    0,
    316,
    315,
    1,
    0,
    0,
    0,
    317,
    318,
    1,
    0,
    0,
    0,
    318,
    316,
    1,
    0,
    0,
    0,
    318,
    319,
    1,
    0,
    0,
    0,
    319,
    74,
    1,
    0,
    0,
    0,
    29,
    0,
    88,
    131,
    148,
    200,
    205,
    210,
    216,
    219,
    223,
    228,
    230,
    233,
    239,
    243,
    248,
    250,
    252,
    258,
    260,
    268,
    270,
    274,
    280,
    299,
    301,
    303,
    309,
    318,
    1,
    6,
    0,
    0
  ];
  static __ATN;
  static get _ATN() {
    if (!FilterQueryLexer.__ATN) {
      FilterQueryLexer.__ATN = new ATNDeserializer().deserialize(FilterQueryLexer._serializedATN);
    }
    return FilterQueryLexer.__ATN;
  }
  static DecisionsToDFA = FilterQueryLexer._ATN.decisionToState.map(
    (ds2, index2) => new DFA(ds2, index2)
  );
}
function isKeyToken(tokenType) {
  return tokenType === FilterQueryLexer.KEY;
}
function isOperatorToken(tokenType) {
  return [
    FilterQueryLexer.EQUALS,
    FilterQueryLexer.NOT_EQUALS,
    FilterQueryLexer.NEQ,
    FilterQueryLexer.LT,
    FilterQueryLexer.LE,
    FilterQueryLexer.GT,
    FilterQueryLexer.GE,
    FilterQueryLexer.LIKE,
    FilterQueryLexer.ILIKE,
    FilterQueryLexer.BETWEEN,
    FilterQueryLexer.EXISTS,
    FilterQueryLexer.REGEXP,
    FilterQueryLexer.CONTAINS,
    FilterQueryLexer.IN,
    FilterQueryLexer.NOT
  ].includes(tokenType);
}
function isNonValueOperatorToken(tokenType) {
  return [FilterQueryLexer.EXISTS].includes(tokenType);
}
function isValueToken(tokenType) {
  return [
    FilterQueryLexer.QUOTED_TEXT,
    FilterQueryLexer.NUMBER,
    FilterQueryLexer.BOOL,
    FilterQueryLexer.KEY
  ].includes(tokenType);
}
function isConjunctionToken(tokenType) {
  return [FilterQueryLexer.AND, FilterQueryLexer.OR].includes(tokenType);
}
function isBracketToken(tokenType) {
  return [
    FilterQueryLexer.LPAREN,
    FilterQueryLexer.RPAREN,
    FilterQueryLexer.LBRACK,
    FilterQueryLexer.RBRACK
  ].includes(tokenType);
}
function isMultiValueOperator(operatorToken) {
  if (!operatorToken) {
    return false;
  }
  const upperOp = operatorToken.toUpperCase();
  return upperOp === "IN";
}
function isFunctionToken(tokenType) {
  return [
    FilterQueryLexer.HAS,
    FilterQueryLexer.HASANY,
    FilterQueryLexer.HASALL,
    FilterQueryLexer.HASTOKEN
  ].includes(tokenType);
}
function isNonValueOperator(operator) {
  const upperOperator = operator.toUpperCase();
  if (NON_VALUE_OPERATORS.includes(upperOperator)) {
    return true;
  }
  if (upperOperator.startsWith(OPERATORS.NOT)) {
    const operatorWithoutNot = upperOperator.slice(4).trim();
    return NON_VALUE_OPERATORS.includes(operatorWithoutNot);
  }
  return false;
}
class FilterQueryParser extends Parser {
  static LPAREN = 1;
  static RPAREN = 2;
  static LBRACK = 3;
  static RBRACK = 4;
  static COMMA = 5;
  static EQUALS = 6;
  static NOT_EQUALS = 7;
  static NEQ = 8;
  static LT = 9;
  static LE = 10;
  static GT = 11;
  static GE = 12;
  static LIKE = 13;
  static ILIKE = 14;
  static BETWEEN = 15;
  static EXISTS = 16;
  static REGEXP = 17;
  static CONTAINS = 18;
  static IN = 19;
  static NOT = 20;
  static AND = 21;
  static OR = 22;
  static HASTOKEN = 23;
  static HAS = 24;
  static HASANY = 25;
  static HASALL = 26;
  static BOOL = 27;
  static NUMBER = 28;
  static QUOTED_TEXT = 29;
  static KEY = 30;
  static WS = 31;
  static FREETEXT = 32;
  static EOF = Token.EOF;
  static RULE_query = 0;
  static RULE_expression = 1;
  static RULE_orExpression = 2;
  static RULE_andExpression = 3;
  static RULE_unaryExpression = 4;
  static RULE_primary = 5;
  static RULE_comparison = 6;
  static RULE_inClause = 7;
  static RULE_notInClause = 8;
  static RULE_valueList = 9;
  static RULE_fullText = 10;
  static RULE_functionCall = 11;
  static RULE_functionParamList = 12;
  static RULE_functionParam = 13;
  static RULE_array = 14;
  static RULE_value = 15;
  static RULE_key = 16;
  static literalNames = [
    null,
    "'('",
    "')'",
    "'['",
    "']'",
    "','",
    null,
    "'!='",
    "'<>'",
    "'<'",
    "'<='",
    "'>'",
    "'>='"
  ];
  static symbolicNames = [
    null,
    "LPAREN",
    "RPAREN",
    "LBRACK",
    "RBRACK",
    "COMMA",
    "EQUALS",
    "NOT_EQUALS",
    "NEQ",
    "LT",
    "LE",
    "GT",
    "GE",
    "LIKE",
    "ILIKE",
    "BETWEEN",
    "EXISTS",
    "REGEXP",
    "CONTAINS",
    "IN",
    "NOT",
    "AND",
    "OR",
    "HASTOKEN",
    "HAS",
    "HASANY",
    "HASALL",
    "BOOL",
    "NUMBER",
    "QUOTED_TEXT",
    "KEY",
    "WS",
    "FREETEXT"
  ];
  // tslint:disable:no-trailing-whitespace
  static ruleNames = [
    "query",
    "expression",
    "orExpression",
    "andExpression",
    "unaryExpression",
    "primary",
    "comparison",
    "inClause",
    "notInClause",
    "valueList",
    "fullText",
    "functionCall",
    "functionParamList",
    "functionParam",
    "array",
    "value",
    "key"
  ];
  get grammarFileName() {
    return "FilterQuery.g4";
  }
  get literalNames() {
    return FilterQueryParser.literalNames;
  }
  get symbolicNames() {
    return FilterQueryParser.symbolicNames;
  }
  get ruleNames() {
    return FilterQueryParser.ruleNames;
  }
  get serializedATN() {
    return FilterQueryParser._serializedATN;
  }
  createFailedPredicateException(predicate, message) {
    return new FailedPredicateException(this, predicate, message);
  }
  constructor(input) {
    super(input);
    this._interp = new ParserATNSimulator(
      this,
      FilterQueryParser._ATN,
      FilterQueryParser.DecisionsToDFA,
      new PredictionContextCache()
    );
  }
  // @RuleVersion(0)
  query() {
    const localctx = new QueryContext(this, this._ctx, this.state);
    this.enterRule(localctx, 0, FilterQueryParser.RULE_query);
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 34;
        this.expression();
        this.state = 35;
        this.match(FilterQueryParser.EOF);
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  expression() {
    const localctx = new ExpressionContext(this, this._ctx, this.state);
    this.enterRule(localctx, 2, FilterQueryParser.RULE_expression);
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 37;
        this.orExpression();
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  orExpression() {
    const localctx = new OrExpressionContext(this, this._ctx, this.state);
    this.enterRule(localctx, 4, FilterQueryParser.RULE_orExpression);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 39;
        this.andExpression();
        this.state = 44;
        this._errHandler.sync(this);
        _la = this._input.LA(1);
        while (_la === 22) {
          {
            {
              this.state = 40;
              this.match(FilterQueryParser.OR);
              this.state = 41;
              this.andExpression();
            }
          }
          this.state = 46;
          this._errHandler.sync(this);
          _la = this._input.LA(1);
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  andExpression() {
    const localctx = new AndExpressionContext(this, this._ctx, this.state);
    this.enterRule(localctx, 6, FilterQueryParser.RULE_andExpression);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 47;
        this.unaryExpression();
        this.state = 53;
        this._errHandler.sync(this);
        _la = this._input.LA(1);
        while ((_la - 1 & ~31) === 0 && (1 << _la - 1 & 3218604033) !== 0) {
          {
            this.state = 51;
            this._errHandler.sync(this);
            switch (this._input.LA(1)) {
              case 21:
                {
                  this.state = 48;
                  this.match(FilterQueryParser.AND);
                  this.state = 49;
                  this.unaryExpression();
                }
                break;
              case 1:
              case 20:
              case 23:
              case 24:
              case 25:
              case 26:
              case 27:
              case 28:
              case 29:
              case 30:
              case 32:
                {
                  this.state = 50;
                  this.unaryExpression();
                }
                break;
              default:
                throw new NoViableAltException(this);
            }
          }
          this.state = 55;
          this._errHandler.sync(this);
          _la = this._input.LA(1);
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  unaryExpression() {
    const localctx = new UnaryExpressionContext(
      this,
      this._ctx,
      this.state
    );
    this.enterRule(localctx, 8, FilterQueryParser.RULE_unaryExpression);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 57;
        this._errHandler.sync(this);
        _la = this._input.LA(1);
        if (_la === 20) {
          {
            this.state = 56;
            this.match(FilterQueryParser.NOT);
          }
        }
        this.state = 59;
        this.primary();
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  primary() {
    const localctx = new PrimaryContext(this, this._ctx, this.state);
    this.enterRule(localctx, 10, FilterQueryParser.RULE_primary);
    try {
      this.state = 70;
      this._errHandler.sync(this);
      switch (this._interp.adaptivePredict(this._input, 4, this._ctx)) {
        case 1:
          this.enterOuterAlt(localctx, 1);
          {
            this.state = 61;
            this.match(FilterQueryParser.LPAREN);
            this.state = 62;
            this.orExpression();
            this.state = 63;
            this.match(FilterQueryParser.RPAREN);
          }
          break;
        case 2:
          this.enterOuterAlt(localctx, 2);
          {
            this.state = 65;
            this.comparison();
          }
          break;
        case 3:
          this.enterOuterAlt(localctx, 3);
          {
            this.state = 66;
            this.functionCall();
          }
          break;
        case 4:
          this.enterOuterAlt(localctx, 4);
          {
            this.state = 67;
            this.fullText();
          }
          break;
        case 5:
          this.enterOuterAlt(localctx, 5);
          {
            this.state = 68;
            this.key();
          }
          break;
        case 6:
          this.enterOuterAlt(localctx, 6);
          {
            this.state = 69;
            this.value();
          }
          break;
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  comparison() {
    const localctx = new ComparisonContext(this, this._ctx, this.state);
    this.enterRule(localctx, 12, FilterQueryParser.RULE_comparison);
    let _la;
    try {
      this.state = 149;
      this._errHandler.sync(this);
      switch (this._interp.adaptivePredict(this._input, 5, this._ctx)) {
        case 1:
          this.enterOuterAlt(localctx, 1);
          {
            this.state = 72;
            this.key();
            this.state = 73;
            this.match(FilterQueryParser.EQUALS);
            this.state = 74;
            this.value();
          }
          break;
        case 2:
          this.enterOuterAlt(localctx, 2);
          {
            this.state = 76;
            this.key();
            this.state = 77;
            _la = this._input.LA(1);
            if (!(_la === 7 || _la === 8)) {
              this._errHandler.recoverInline(this);
            } else {
              this._errHandler.reportMatch(this);
              this.consume();
            }
            this.state = 78;
            this.value();
          }
          break;
        case 3:
          this.enterOuterAlt(localctx, 3);
          {
            this.state = 80;
            this.key();
            this.state = 81;
            this.match(FilterQueryParser.LT);
            this.state = 82;
            this.value();
          }
          break;
        case 4:
          this.enterOuterAlt(localctx, 4);
          {
            this.state = 84;
            this.key();
            this.state = 85;
            this.match(FilterQueryParser.LE);
            this.state = 86;
            this.value();
          }
          break;
        case 5:
          this.enterOuterAlt(localctx, 5);
          {
            this.state = 88;
            this.key();
            this.state = 89;
            this.match(FilterQueryParser.GT);
            this.state = 90;
            this.value();
          }
          break;
        case 6:
          this.enterOuterAlt(localctx, 6);
          {
            this.state = 92;
            this.key();
            this.state = 93;
            this.match(FilterQueryParser.GE);
            this.state = 94;
            this.value();
          }
          break;
        case 7:
          this.enterOuterAlt(localctx, 7);
          {
            this.state = 96;
            this.key();
            this.state = 97;
            _la = this._input.LA(1);
            if (!(_la === 13 || _la === 14)) {
              this._errHandler.recoverInline(this);
            } else {
              this._errHandler.reportMatch(this);
              this.consume();
            }
            this.state = 98;
            this.value();
          }
          break;
        case 8:
          this.enterOuterAlt(localctx, 8);
          {
            this.state = 100;
            this.key();
            this.state = 101;
            this.match(FilterQueryParser.NOT);
            this.state = 102;
            _la = this._input.LA(1);
            if (!(_la === 13 || _la === 14)) {
              this._errHandler.recoverInline(this);
            } else {
              this._errHandler.reportMatch(this);
              this.consume();
            }
            this.state = 103;
            this.value();
          }
          break;
        case 9:
          this.enterOuterAlt(localctx, 9);
          {
            this.state = 105;
            this.key();
            this.state = 106;
            this.match(FilterQueryParser.BETWEEN);
            this.state = 107;
            this.value();
            this.state = 108;
            this.match(FilterQueryParser.AND);
            this.state = 109;
            this.value();
          }
          break;
        case 10:
          this.enterOuterAlt(localctx, 10);
          {
            this.state = 111;
            this.key();
            this.state = 112;
            this.match(FilterQueryParser.NOT);
            this.state = 113;
            this.match(FilterQueryParser.BETWEEN);
            this.state = 114;
            this.value();
            this.state = 115;
            this.match(FilterQueryParser.AND);
            this.state = 116;
            this.value();
          }
          break;
        case 11:
          this.enterOuterAlt(localctx, 11);
          {
            this.state = 118;
            this.key();
            this.state = 119;
            this.inClause();
          }
          break;
        case 12:
          this.enterOuterAlt(localctx, 12);
          {
            this.state = 121;
            this.key();
            this.state = 122;
            this.notInClause();
          }
          break;
        case 13:
          this.enterOuterAlt(localctx, 13);
          {
            this.state = 124;
            this.key();
            this.state = 125;
            this.match(FilterQueryParser.EXISTS);
          }
          break;
        case 14:
          this.enterOuterAlt(localctx, 14);
          {
            this.state = 127;
            this.key();
            this.state = 128;
            this.match(FilterQueryParser.NOT);
            this.state = 129;
            this.match(FilterQueryParser.EXISTS);
          }
          break;
        case 15:
          this.enterOuterAlt(localctx, 15);
          {
            this.state = 131;
            this.key();
            this.state = 132;
            this.match(FilterQueryParser.REGEXP);
            this.state = 133;
            this.value();
          }
          break;
        case 16:
          this.enterOuterAlt(localctx, 16);
          {
            this.state = 135;
            this.key();
            this.state = 136;
            this.match(FilterQueryParser.NOT);
            this.state = 137;
            this.match(FilterQueryParser.REGEXP);
            this.state = 138;
            this.value();
          }
          break;
        case 17:
          this.enterOuterAlt(localctx, 17);
          {
            this.state = 140;
            this.key();
            this.state = 141;
            this.match(FilterQueryParser.CONTAINS);
            this.state = 142;
            this.value();
          }
          break;
        case 18:
          this.enterOuterAlt(localctx, 18);
          {
            this.state = 144;
            this.key();
            this.state = 145;
            this.match(FilterQueryParser.NOT);
            this.state = 146;
            this.match(FilterQueryParser.CONTAINS);
            this.state = 147;
            this.value();
          }
          break;
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  inClause() {
    const localctx = new InClauseContext(this, this._ctx, this.state);
    this.enterRule(localctx, 14, FilterQueryParser.RULE_inClause);
    try {
      this.state = 163;
      this._errHandler.sync(this);
      switch (this._interp.adaptivePredict(this._input, 6, this._ctx)) {
        case 1:
          this.enterOuterAlt(localctx, 1);
          {
            this.state = 151;
            this.match(FilterQueryParser.IN);
            this.state = 152;
            this.match(FilterQueryParser.LPAREN);
            this.state = 153;
            this.valueList();
            this.state = 154;
            this.match(FilterQueryParser.RPAREN);
          }
          break;
        case 2:
          this.enterOuterAlt(localctx, 2);
          {
            this.state = 156;
            this.match(FilterQueryParser.IN);
            this.state = 157;
            this.match(FilterQueryParser.LBRACK);
            this.state = 158;
            this.valueList();
            this.state = 159;
            this.match(FilterQueryParser.RBRACK);
          }
          break;
        case 3:
          this.enterOuterAlt(localctx, 3);
          {
            this.state = 161;
            this.match(FilterQueryParser.IN);
            this.state = 162;
            this.value();
          }
          break;
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  notInClause() {
    const localctx = new NotInClauseContext(this, this._ctx, this.state);
    this.enterRule(localctx, 16, FilterQueryParser.RULE_notInClause);
    try {
      this.state = 180;
      this._errHandler.sync(this);
      switch (this._interp.adaptivePredict(this._input, 7, this._ctx)) {
        case 1:
          this.enterOuterAlt(localctx, 1);
          {
            this.state = 165;
            this.match(FilterQueryParser.NOT);
            this.state = 166;
            this.match(FilterQueryParser.IN);
            this.state = 167;
            this.match(FilterQueryParser.LPAREN);
            this.state = 168;
            this.valueList();
            this.state = 169;
            this.match(FilterQueryParser.RPAREN);
          }
          break;
        case 2:
          this.enterOuterAlt(localctx, 2);
          {
            this.state = 171;
            this.match(FilterQueryParser.NOT);
            this.state = 172;
            this.match(FilterQueryParser.IN);
            this.state = 173;
            this.match(FilterQueryParser.LBRACK);
            this.state = 174;
            this.valueList();
            this.state = 175;
            this.match(FilterQueryParser.RBRACK);
          }
          break;
        case 3:
          this.enterOuterAlt(localctx, 3);
          {
            this.state = 177;
            this.match(FilterQueryParser.NOT);
            this.state = 178;
            this.match(FilterQueryParser.IN);
            this.state = 179;
            this.value();
          }
          break;
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  valueList() {
    const localctx = new ValueListContext(this, this._ctx, this.state);
    this.enterRule(localctx, 18, FilterQueryParser.RULE_valueList);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 182;
        this.value();
        this.state = 187;
        this._errHandler.sync(this);
        _la = this._input.LA(1);
        while (_la === 5) {
          {
            {
              this.state = 183;
              this.match(FilterQueryParser.COMMA);
              this.state = 184;
              this.value();
            }
          }
          this.state = 189;
          this._errHandler.sync(this);
          _la = this._input.LA(1);
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  fullText() {
    const localctx = new FullTextContext(this, this._ctx, this.state);
    this.enterRule(localctx, 20, FilterQueryParser.RULE_fullText);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 190;
        _la = this._input.LA(1);
        if (!(_la === 29 || _la === 32)) {
          this._errHandler.recoverInline(this);
        } else {
          this._errHandler.reportMatch(this);
          this.consume();
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  functionCall() {
    const localctx = new FunctionCallContext(this, this._ctx, this.state);
    this.enterRule(localctx, 22, FilterQueryParser.RULE_functionCall);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 192;
        _la = this._input.LA(1);
        if (!((_la & ~31) === 0 && (1 << _la & 125829120) !== 0)) {
          this._errHandler.recoverInline(this);
        } else {
          this._errHandler.reportMatch(this);
          this.consume();
        }
        this.state = 193;
        this.match(FilterQueryParser.LPAREN);
        this.state = 194;
        this.functionParamList();
        this.state = 195;
        this.match(FilterQueryParser.RPAREN);
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  functionParamList() {
    const localctx = new FunctionParamListContext(
      this,
      this._ctx,
      this.state
    );
    this.enterRule(localctx, 24, FilterQueryParser.RULE_functionParamList);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 197;
        this.functionParam();
        this.state = 202;
        this._errHandler.sync(this);
        _la = this._input.LA(1);
        while (_la === 5) {
          {
            {
              this.state = 198;
              this.match(FilterQueryParser.COMMA);
              this.state = 199;
              this.functionParam();
            }
          }
          this.state = 204;
          this._errHandler.sync(this);
          _la = this._input.LA(1);
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  functionParam() {
    const localctx = new FunctionParamContext(this, this._ctx, this.state);
    this.enterRule(localctx, 26, FilterQueryParser.RULE_functionParam);
    try {
      this.state = 208;
      this._errHandler.sync(this);
      switch (this._interp.adaptivePredict(this._input, 10, this._ctx)) {
        case 1:
          this.enterOuterAlt(localctx, 1);
          {
            this.state = 205;
            this.key();
          }
          break;
        case 2:
          this.enterOuterAlt(localctx, 2);
          {
            this.state = 206;
            this.value();
          }
          break;
        case 3:
          this.enterOuterAlt(localctx, 3);
          {
            this.state = 207;
            this.array();
          }
          break;
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  array() {
    const localctx = new ArrayContext(this, this._ctx, this.state);
    this.enterRule(localctx, 28, FilterQueryParser.RULE_array);
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 210;
        this.match(FilterQueryParser.LBRACK);
        this.state = 211;
        this.valueList();
        this.state = 212;
        this.match(FilterQueryParser.RBRACK);
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  value() {
    const localctx = new ValueContext(this, this._ctx, this.state);
    this.enterRule(localctx, 30, FilterQueryParser.RULE_value);
    let _la;
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 214;
        _la = this._input.LA(1);
        if (!((_la & ~31) === 0 && (1 << _la & 2013265920) !== 0)) {
          this._errHandler.recoverInline(this);
        } else {
          this._errHandler.reportMatch(this);
          this.consume();
        }
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  // @RuleVersion(0)
  key() {
    const localctx = new KeyContext(this, this._ctx, this.state);
    this.enterRule(localctx, 32, FilterQueryParser.RULE_key);
    try {
      this.enterOuterAlt(localctx, 1);
      {
        this.state = 216;
        this.match(FilterQueryParser.KEY);
      }
    } catch (error) {
      if (error instanceof RecognitionException) {
        localctx.exception = error;
        this._errHandler.reportError(this, error);
        this._errHandler.recover(this, error);
      } else {
        throw error;
      }
    } finally {
      this.exitRule();
    }
    return localctx;
  }
  static _serializedATN = [
    4,
    1,
    32,
    219,
    2,
    0,
    7,
    0,
    2,
    1,
    7,
    1,
    2,
    2,
    7,
    2,
    2,
    3,
    7,
    3,
    2,
    4,
    7,
    4,
    2,
    5,
    7,
    5,
    2,
    6,
    7,
    6,
    2,
    7,
    7,
    7,
    2,
    8,
    7,
    8,
    2,
    9,
    7,
    9,
    2,
    10,
    7,
    10,
    2,
    11,
    7,
    11,
    2,
    12,
    7,
    12,
    2,
    13,
    7,
    13,
    2,
    14,
    7,
    14,
    2,
    15,
    7,
    15,
    2,
    16,
    7,
    16,
    1,
    0,
    1,
    0,
    1,
    0,
    1,
    1,
    1,
    1,
    1,
    2,
    1,
    2,
    1,
    2,
    5,
    2,
    43,
    8,
    2,
    10,
    2,
    12,
    2,
    46,
    9,
    2,
    1,
    3,
    1,
    3,
    1,
    3,
    1,
    3,
    5,
    3,
    52,
    8,
    3,
    10,
    3,
    12,
    3,
    55,
    9,
    3,
    1,
    4,
    3,
    4,
    58,
    8,
    4,
    1,
    4,
    1,
    4,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    1,
    5,
    3,
    5,
    71,
    8,
    5,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    1,
    6,
    3,
    6,
    150,
    8,
    6,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    1,
    7,
    3,
    7,
    164,
    8,
    7,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    1,
    8,
    3,
    8,
    181,
    8,
    8,
    1,
    9,
    1,
    9,
    1,
    9,
    5,
    9,
    186,
    8,
    9,
    10,
    9,
    12,
    9,
    189,
    9,
    9,
    1,
    10,
    1,
    10,
    1,
    11,
    1,
    11,
    1,
    11,
    1,
    11,
    1,
    11,
    1,
    12,
    1,
    12,
    1,
    12,
    5,
    12,
    201,
    8,
    12,
    10,
    12,
    12,
    12,
    204,
    9,
    12,
    1,
    13,
    1,
    13,
    1,
    13,
    3,
    13,
    209,
    8,
    13,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    14,
    1,
    15,
    1,
    15,
    1,
    16,
    1,
    16,
    1,
    16,
    0,
    0,
    17,
    0,
    2,
    4,
    6,
    8,
    10,
    12,
    14,
    16,
    18,
    20,
    22,
    24,
    26,
    28,
    30,
    32,
    0,
    5,
    1,
    0,
    7,
    8,
    1,
    0,
    13,
    14,
    2,
    0,
    29,
    29,
    32,
    32,
    1,
    0,
    23,
    26,
    1,
    0,
    27,
    30,
    235,
    0,
    34,
    1,
    0,
    0,
    0,
    2,
    37,
    1,
    0,
    0,
    0,
    4,
    39,
    1,
    0,
    0,
    0,
    6,
    47,
    1,
    0,
    0,
    0,
    8,
    57,
    1,
    0,
    0,
    0,
    10,
    70,
    1,
    0,
    0,
    0,
    12,
    149,
    1,
    0,
    0,
    0,
    14,
    163,
    1,
    0,
    0,
    0,
    16,
    180,
    1,
    0,
    0,
    0,
    18,
    182,
    1,
    0,
    0,
    0,
    20,
    190,
    1,
    0,
    0,
    0,
    22,
    192,
    1,
    0,
    0,
    0,
    24,
    197,
    1,
    0,
    0,
    0,
    26,
    208,
    1,
    0,
    0,
    0,
    28,
    210,
    1,
    0,
    0,
    0,
    30,
    214,
    1,
    0,
    0,
    0,
    32,
    216,
    1,
    0,
    0,
    0,
    34,
    35,
    3,
    2,
    1,
    0,
    35,
    36,
    5,
    0,
    0,
    1,
    36,
    1,
    1,
    0,
    0,
    0,
    37,
    38,
    3,
    4,
    2,
    0,
    38,
    3,
    1,
    0,
    0,
    0,
    39,
    44,
    3,
    6,
    3,
    0,
    40,
    41,
    5,
    22,
    0,
    0,
    41,
    43,
    3,
    6,
    3,
    0,
    42,
    40,
    1,
    0,
    0,
    0,
    43,
    46,
    1,
    0,
    0,
    0,
    44,
    42,
    1,
    0,
    0,
    0,
    44,
    45,
    1,
    0,
    0,
    0,
    45,
    5,
    1,
    0,
    0,
    0,
    46,
    44,
    1,
    0,
    0,
    0,
    47,
    53,
    3,
    8,
    4,
    0,
    48,
    49,
    5,
    21,
    0,
    0,
    49,
    52,
    3,
    8,
    4,
    0,
    50,
    52,
    3,
    8,
    4,
    0,
    51,
    48,
    1,
    0,
    0,
    0,
    51,
    50,
    1,
    0,
    0,
    0,
    52,
    55,
    1,
    0,
    0,
    0,
    53,
    51,
    1,
    0,
    0,
    0,
    53,
    54,
    1,
    0,
    0,
    0,
    54,
    7,
    1,
    0,
    0,
    0,
    55,
    53,
    1,
    0,
    0,
    0,
    56,
    58,
    5,
    20,
    0,
    0,
    57,
    56,
    1,
    0,
    0,
    0,
    57,
    58,
    1,
    0,
    0,
    0,
    58,
    59,
    1,
    0,
    0,
    0,
    59,
    60,
    3,
    10,
    5,
    0,
    60,
    9,
    1,
    0,
    0,
    0,
    61,
    62,
    5,
    1,
    0,
    0,
    62,
    63,
    3,
    4,
    2,
    0,
    63,
    64,
    5,
    2,
    0,
    0,
    64,
    71,
    1,
    0,
    0,
    0,
    65,
    71,
    3,
    12,
    6,
    0,
    66,
    71,
    3,
    22,
    11,
    0,
    67,
    71,
    3,
    20,
    10,
    0,
    68,
    71,
    3,
    32,
    16,
    0,
    69,
    71,
    3,
    30,
    15,
    0,
    70,
    61,
    1,
    0,
    0,
    0,
    70,
    65,
    1,
    0,
    0,
    0,
    70,
    66,
    1,
    0,
    0,
    0,
    70,
    67,
    1,
    0,
    0,
    0,
    70,
    68,
    1,
    0,
    0,
    0,
    70,
    69,
    1,
    0,
    0,
    0,
    71,
    11,
    1,
    0,
    0,
    0,
    72,
    73,
    3,
    32,
    16,
    0,
    73,
    74,
    5,
    6,
    0,
    0,
    74,
    75,
    3,
    30,
    15,
    0,
    75,
    150,
    1,
    0,
    0,
    0,
    76,
    77,
    3,
    32,
    16,
    0,
    77,
    78,
    7,
    0,
    0,
    0,
    78,
    79,
    3,
    30,
    15,
    0,
    79,
    150,
    1,
    0,
    0,
    0,
    80,
    81,
    3,
    32,
    16,
    0,
    81,
    82,
    5,
    9,
    0,
    0,
    82,
    83,
    3,
    30,
    15,
    0,
    83,
    150,
    1,
    0,
    0,
    0,
    84,
    85,
    3,
    32,
    16,
    0,
    85,
    86,
    5,
    10,
    0,
    0,
    86,
    87,
    3,
    30,
    15,
    0,
    87,
    150,
    1,
    0,
    0,
    0,
    88,
    89,
    3,
    32,
    16,
    0,
    89,
    90,
    5,
    11,
    0,
    0,
    90,
    91,
    3,
    30,
    15,
    0,
    91,
    150,
    1,
    0,
    0,
    0,
    92,
    93,
    3,
    32,
    16,
    0,
    93,
    94,
    5,
    12,
    0,
    0,
    94,
    95,
    3,
    30,
    15,
    0,
    95,
    150,
    1,
    0,
    0,
    0,
    96,
    97,
    3,
    32,
    16,
    0,
    97,
    98,
    7,
    1,
    0,
    0,
    98,
    99,
    3,
    30,
    15,
    0,
    99,
    150,
    1,
    0,
    0,
    0,
    100,
    101,
    3,
    32,
    16,
    0,
    101,
    102,
    5,
    20,
    0,
    0,
    102,
    103,
    7,
    1,
    0,
    0,
    103,
    104,
    3,
    30,
    15,
    0,
    104,
    150,
    1,
    0,
    0,
    0,
    105,
    106,
    3,
    32,
    16,
    0,
    106,
    107,
    5,
    15,
    0,
    0,
    107,
    108,
    3,
    30,
    15,
    0,
    108,
    109,
    5,
    21,
    0,
    0,
    109,
    110,
    3,
    30,
    15,
    0,
    110,
    150,
    1,
    0,
    0,
    0,
    111,
    112,
    3,
    32,
    16,
    0,
    112,
    113,
    5,
    20,
    0,
    0,
    113,
    114,
    5,
    15,
    0,
    0,
    114,
    115,
    3,
    30,
    15,
    0,
    115,
    116,
    5,
    21,
    0,
    0,
    116,
    117,
    3,
    30,
    15,
    0,
    117,
    150,
    1,
    0,
    0,
    0,
    118,
    119,
    3,
    32,
    16,
    0,
    119,
    120,
    3,
    14,
    7,
    0,
    120,
    150,
    1,
    0,
    0,
    0,
    121,
    122,
    3,
    32,
    16,
    0,
    122,
    123,
    3,
    16,
    8,
    0,
    123,
    150,
    1,
    0,
    0,
    0,
    124,
    125,
    3,
    32,
    16,
    0,
    125,
    126,
    5,
    16,
    0,
    0,
    126,
    150,
    1,
    0,
    0,
    0,
    127,
    128,
    3,
    32,
    16,
    0,
    128,
    129,
    5,
    20,
    0,
    0,
    129,
    130,
    5,
    16,
    0,
    0,
    130,
    150,
    1,
    0,
    0,
    0,
    131,
    132,
    3,
    32,
    16,
    0,
    132,
    133,
    5,
    17,
    0,
    0,
    133,
    134,
    3,
    30,
    15,
    0,
    134,
    150,
    1,
    0,
    0,
    0,
    135,
    136,
    3,
    32,
    16,
    0,
    136,
    137,
    5,
    20,
    0,
    0,
    137,
    138,
    5,
    17,
    0,
    0,
    138,
    139,
    3,
    30,
    15,
    0,
    139,
    150,
    1,
    0,
    0,
    0,
    140,
    141,
    3,
    32,
    16,
    0,
    141,
    142,
    5,
    18,
    0,
    0,
    142,
    143,
    3,
    30,
    15,
    0,
    143,
    150,
    1,
    0,
    0,
    0,
    144,
    145,
    3,
    32,
    16,
    0,
    145,
    146,
    5,
    20,
    0,
    0,
    146,
    147,
    5,
    18,
    0,
    0,
    147,
    148,
    3,
    30,
    15,
    0,
    148,
    150,
    1,
    0,
    0,
    0,
    149,
    72,
    1,
    0,
    0,
    0,
    149,
    76,
    1,
    0,
    0,
    0,
    149,
    80,
    1,
    0,
    0,
    0,
    149,
    84,
    1,
    0,
    0,
    0,
    149,
    88,
    1,
    0,
    0,
    0,
    149,
    92,
    1,
    0,
    0,
    0,
    149,
    96,
    1,
    0,
    0,
    0,
    149,
    100,
    1,
    0,
    0,
    0,
    149,
    105,
    1,
    0,
    0,
    0,
    149,
    111,
    1,
    0,
    0,
    0,
    149,
    118,
    1,
    0,
    0,
    0,
    149,
    121,
    1,
    0,
    0,
    0,
    149,
    124,
    1,
    0,
    0,
    0,
    149,
    127,
    1,
    0,
    0,
    0,
    149,
    131,
    1,
    0,
    0,
    0,
    149,
    135,
    1,
    0,
    0,
    0,
    149,
    140,
    1,
    0,
    0,
    0,
    149,
    144,
    1,
    0,
    0,
    0,
    150,
    13,
    1,
    0,
    0,
    0,
    151,
    152,
    5,
    19,
    0,
    0,
    152,
    153,
    5,
    1,
    0,
    0,
    153,
    154,
    3,
    18,
    9,
    0,
    154,
    155,
    5,
    2,
    0,
    0,
    155,
    164,
    1,
    0,
    0,
    0,
    156,
    157,
    5,
    19,
    0,
    0,
    157,
    158,
    5,
    3,
    0,
    0,
    158,
    159,
    3,
    18,
    9,
    0,
    159,
    160,
    5,
    4,
    0,
    0,
    160,
    164,
    1,
    0,
    0,
    0,
    161,
    162,
    5,
    19,
    0,
    0,
    162,
    164,
    3,
    30,
    15,
    0,
    163,
    151,
    1,
    0,
    0,
    0,
    163,
    156,
    1,
    0,
    0,
    0,
    163,
    161,
    1,
    0,
    0,
    0,
    164,
    15,
    1,
    0,
    0,
    0,
    165,
    166,
    5,
    20,
    0,
    0,
    166,
    167,
    5,
    19,
    0,
    0,
    167,
    168,
    5,
    1,
    0,
    0,
    168,
    169,
    3,
    18,
    9,
    0,
    169,
    170,
    5,
    2,
    0,
    0,
    170,
    181,
    1,
    0,
    0,
    0,
    171,
    172,
    5,
    20,
    0,
    0,
    172,
    173,
    5,
    19,
    0,
    0,
    173,
    174,
    5,
    3,
    0,
    0,
    174,
    175,
    3,
    18,
    9,
    0,
    175,
    176,
    5,
    4,
    0,
    0,
    176,
    181,
    1,
    0,
    0,
    0,
    177,
    178,
    5,
    20,
    0,
    0,
    178,
    179,
    5,
    19,
    0,
    0,
    179,
    181,
    3,
    30,
    15,
    0,
    180,
    165,
    1,
    0,
    0,
    0,
    180,
    171,
    1,
    0,
    0,
    0,
    180,
    177,
    1,
    0,
    0,
    0,
    181,
    17,
    1,
    0,
    0,
    0,
    182,
    187,
    3,
    30,
    15,
    0,
    183,
    184,
    5,
    5,
    0,
    0,
    184,
    186,
    3,
    30,
    15,
    0,
    185,
    183,
    1,
    0,
    0,
    0,
    186,
    189,
    1,
    0,
    0,
    0,
    187,
    185,
    1,
    0,
    0,
    0,
    187,
    188,
    1,
    0,
    0,
    0,
    188,
    19,
    1,
    0,
    0,
    0,
    189,
    187,
    1,
    0,
    0,
    0,
    190,
    191,
    7,
    2,
    0,
    0,
    191,
    21,
    1,
    0,
    0,
    0,
    192,
    193,
    7,
    3,
    0,
    0,
    193,
    194,
    5,
    1,
    0,
    0,
    194,
    195,
    3,
    24,
    12,
    0,
    195,
    196,
    5,
    2,
    0,
    0,
    196,
    23,
    1,
    0,
    0,
    0,
    197,
    202,
    3,
    26,
    13,
    0,
    198,
    199,
    5,
    5,
    0,
    0,
    199,
    201,
    3,
    26,
    13,
    0,
    200,
    198,
    1,
    0,
    0,
    0,
    201,
    204,
    1,
    0,
    0,
    0,
    202,
    200,
    1,
    0,
    0,
    0,
    202,
    203,
    1,
    0,
    0,
    0,
    203,
    25,
    1,
    0,
    0,
    0,
    204,
    202,
    1,
    0,
    0,
    0,
    205,
    209,
    3,
    32,
    16,
    0,
    206,
    209,
    3,
    30,
    15,
    0,
    207,
    209,
    3,
    28,
    14,
    0,
    208,
    205,
    1,
    0,
    0,
    0,
    208,
    206,
    1,
    0,
    0,
    0,
    208,
    207,
    1,
    0,
    0,
    0,
    209,
    27,
    1,
    0,
    0,
    0,
    210,
    211,
    5,
    3,
    0,
    0,
    211,
    212,
    3,
    18,
    9,
    0,
    212,
    213,
    5,
    4,
    0,
    0,
    213,
    29,
    1,
    0,
    0,
    0,
    214,
    215,
    7,
    4,
    0,
    0,
    215,
    31,
    1,
    0,
    0,
    0,
    216,
    217,
    5,
    30,
    0,
    0,
    217,
    33,
    1,
    0,
    0,
    0,
    11,
    44,
    51,
    53,
    57,
    70,
    149,
    163,
    180,
    187,
    202,
    208
  ];
  static __ATN;
  static get _ATN() {
    if (!FilterQueryParser.__ATN) {
      FilterQueryParser.__ATN = new ATNDeserializer().deserialize(FilterQueryParser._serializedATN);
    }
    return FilterQueryParser.__ATN;
  }
  static DecisionsToDFA = FilterQueryParser._ATN.decisionToState.map(
    (ds2, index2) => new DFA(ds2, index2)
  );
}
class QueryContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  expression() {
    return this.getTypedRuleContext(ExpressionContext, 0);
  }
  EOF() {
    return this.getToken(FilterQueryParser.EOF, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_query;
  }
  enterRule(listener) {
    if (listener.enterQuery) {
      listener.enterQuery(this);
    }
  }
  exitRule(listener) {
    if (listener.exitQuery) {
      listener.exitQuery(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitQuery) {
      return visitor.visitQuery(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class ExpressionContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  orExpression() {
    return this.getTypedRuleContext(OrExpressionContext, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_expression;
  }
  enterRule(listener) {
    if (listener.enterExpression) {
      listener.enterExpression(this);
    }
  }
  exitRule(listener) {
    if (listener.exitExpression) {
      listener.exitExpression(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitExpression) {
      return visitor.visitExpression(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class OrExpressionContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  andExpression_list() {
    return this.getTypedRuleContexts(AndExpressionContext);
  }
  andExpression(i) {
    return this.getTypedRuleContext(AndExpressionContext, i);
  }
  OR_list() {
    return this.getTokens(FilterQueryParser.OR);
  }
  OR(i) {
    return this.getToken(FilterQueryParser.OR, i);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_orExpression;
  }
  enterRule(listener) {
    if (listener.enterOrExpression) {
      listener.enterOrExpression(this);
    }
  }
  exitRule(listener) {
    if (listener.exitOrExpression) {
      listener.exitOrExpression(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitOrExpression) {
      return visitor.visitOrExpression(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class AndExpressionContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  unaryExpression_list() {
    return this.getTypedRuleContexts(UnaryExpressionContext);
  }
  unaryExpression(i) {
    return this.getTypedRuleContext(UnaryExpressionContext, i);
  }
  AND_list() {
    return this.getTokens(FilterQueryParser.AND);
  }
  AND(i) {
    return this.getToken(FilterQueryParser.AND, i);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_andExpression;
  }
  enterRule(listener) {
    if (listener.enterAndExpression) {
      listener.enterAndExpression(this);
    }
  }
  exitRule(listener) {
    if (listener.exitAndExpression) {
      listener.exitAndExpression(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitAndExpression) {
      return visitor.visitAndExpression(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class UnaryExpressionContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  primary() {
    return this.getTypedRuleContext(PrimaryContext, 0);
  }
  NOT() {
    return this.getToken(FilterQueryParser.NOT, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_unaryExpression;
  }
  enterRule(listener) {
    if (listener.enterUnaryExpression) {
      listener.enterUnaryExpression(this);
    }
  }
  exitRule(listener) {
    if (listener.exitUnaryExpression) {
      listener.exitUnaryExpression(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitUnaryExpression) {
      return visitor.visitUnaryExpression(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class PrimaryContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  LPAREN() {
    return this.getToken(FilterQueryParser.LPAREN, 0);
  }
  orExpression() {
    return this.getTypedRuleContext(OrExpressionContext, 0);
  }
  RPAREN() {
    return this.getToken(FilterQueryParser.RPAREN, 0);
  }
  comparison() {
    return this.getTypedRuleContext(ComparisonContext, 0);
  }
  functionCall() {
    return this.getTypedRuleContext(FunctionCallContext, 0);
  }
  fullText() {
    return this.getTypedRuleContext(FullTextContext, 0);
  }
  key() {
    return this.getTypedRuleContext(KeyContext, 0);
  }
  value() {
    return this.getTypedRuleContext(ValueContext, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_primary;
  }
  enterRule(listener) {
    if (listener.enterPrimary) {
      listener.enterPrimary(this);
    }
  }
  exitRule(listener) {
    if (listener.exitPrimary) {
      listener.exitPrimary(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitPrimary) {
      return visitor.visitPrimary(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class ComparisonContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  key() {
    return this.getTypedRuleContext(KeyContext, 0);
  }
  EQUALS() {
    return this.getToken(FilterQueryParser.EQUALS, 0);
  }
  value_list() {
    return this.getTypedRuleContexts(ValueContext);
  }
  value(i) {
    return this.getTypedRuleContext(ValueContext, i);
  }
  NOT_EQUALS() {
    return this.getToken(FilterQueryParser.NOT_EQUALS, 0);
  }
  NEQ() {
    return this.getToken(FilterQueryParser.NEQ, 0);
  }
  LT() {
    return this.getToken(FilterQueryParser.LT, 0);
  }
  LE() {
    return this.getToken(FilterQueryParser.LE, 0);
  }
  GT() {
    return this.getToken(FilterQueryParser.GT, 0);
  }
  GE() {
    return this.getToken(FilterQueryParser.GE, 0);
  }
  LIKE() {
    return this.getToken(FilterQueryParser.LIKE, 0);
  }
  ILIKE() {
    return this.getToken(FilterQueryParser.ILIKE, 0);
  }
  NOT() {
    return this.getToken(FilterQueryParser.NOT, 0);
  }
  BETWEEN() {
    return this.getToken(FilterQueryParser.BETWEEN, 0);
  }
  AND() {
    return this.getToken(FilterQueryParser.AND, 0);
  }
  inClause() {
    return this.getTypedRuleContext(InClauseContext, 0);
  }
  notInClause() {
    return this.getTypedRuleContext(NotInClauseContext, 0);
  }
  EXISTS() {
    return this.getToken(FilterQueryParser.EXISTS, 0);
  }
  REGEXP() {
    return this.getToken(FilterQueryParser.REGEXP, 0);
  }
  CONTAINS() {
    return this.getToken(FilterQueryParser.CONTAINS, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_comparison;
  }
  enterRule(listener) {
    if (listener.enterComparison) {
      listener.enterComparison(this);
    }
  }
  exitRule(listener) {
    if (listener.exitComparison) {
      listener.exitComparison(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitComparison) {
      return visitor.visitComparison(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class InClauseContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  IN() {
    return this.getToken(FilterQueryParser.IN, 0);
  }
  LPAREN() {
    return this.getToken(FilterQueryParser.LPAREN, 0);
  }
  valueList() {
    return this.getTypedRuleContext(ValueListContext, 0);
  }
  RPAREN() {
    return this.getToken(FilterQueryParser.RPAREN, 0);
  }
  LBRACK() {
    return this.getToken(FilterQueryParser.LBRACK, 0);
  }
  RBRACK() {
    return this.getToken(FilterQueryParser.RBRACK, 0);
  }
  value() {
    return this.getTypedRuleContext(ValueContext, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_inClause;
  }
  enterRule(listener) {
    if (listener.enterInClause) {
      listener.enterInClause(this);
    }
  }
  exitRule(listener) {
    if (listener.exitInClause) {
      listener.exitInClause(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitInClause) {
      return visitor.visitInClause(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class NotInClauseContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  NOT() {
    return this.getToken(FilterQueryParser.NOT, 0);
  }
  IN() {
    return this.getToken(FilterQueryParser.IN, 0);
  }
  LPAREN() {
    return this.getToken(FilterQueryParser.LPAREN, 0);
  }
  valueList() {
    return this.getTypedRuleContext(ValueListContext, 0);
  }
  RPAREN() {
    return this.getToken(FilterQueryParser.RPAREN, 0);
  }
  LBRACK() {
    return this.getToken(FilterQueryParser.LBRACK, 0);
  }
  RBRACK() {
    return this.getToken(FilterQueryParser.RBRACK, 0);
  }
  value() {
    return this.getTypedRuleContext(ValueContext, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_notInClause;
  }
  enterRule(listener) {
    if (listener.enterNotInClause) {
      listener.enterNotInClause(this);
    }
  }
  exitRule(listener) {
    if (listener.exitNotInClause) {
      listener.exitNotInClause(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitNotInClause) {
      return visitor.visitNotInClause(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class ValueListContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  value_list() {
    return this.getTypedRuleContexts(ValueContext);
  }
  value(i) {
    return this.getTypedRuleContext(ValueContext, i);
  }
  COMMA_list() {
    return this.getTokens(FilterQueryParser.COMMA);
  }
  COMMA(i) {
    return this.getToken(FilterQueryParser.COMMA, i);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_valueList;
  }
  enterRule(listener) {
    if (listener.enterValueList) {
      listener.enterValueList(this);
    }
  }
  exitRule(listener) {
    if (listener.exitValueList) {
      listener.exitValueList(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitValueList) {
      return visitor.visitValueList(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class FullTextContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  QUOTED_TEXT() {
    return this.getToken(FilterQueryParser.QUOTED_TEXT, 0);
  }
  FREETEXT() {
    return this.getToken(FilterQueryParser.FREETEXT, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_fullText;
  }
  enterRule(listener) {
    if (listener.enterFullText) {
      listener.enterFullText(this);
    }
  }
  exitRule(listener) {
    if (listener.exitFullText) {
      listener.exitFullText(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitFullText) {
      return visitor.visitFullText(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class FunctionCallContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  LPAREN() {
    return this.getToken(FilterQueryParser.LPAREN, 0);
  }
  functionParamList() {
    return this.getTypedRuleContext(FunctionParamListContext, 0);
  }
  RPAREN() {
    return this.getToken(FilterQueryParser.RPAREN, 0);
  }
  HASTOKEN() {
    return this.getToken(FilterQueryParser.HASTOKEN, 0);
  }
  HAS() {
    return this.getToken(FilterQueryParser.HAS, 0);
  }
  HASANY() {
    return this.getToken(FilterQueryParser.HASANY, 0);
  }
  HASALL() {
    return this.getToken(FilterQueryParser.HASALL, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_functionCall;
  }
  enterRule(listener) {
    if (listener.enterFunctionCall) {
      listener.enterFunctionCall(this);
    }
  }
  exitRule(listener) {
    if (listener.exitFunctionCall) {
      listener.exitFunctionCall(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitFunctionCall) {
      return visitor.visitFunctionCall(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class FunctionParamListContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  functionParam_list() {
    return this.getTypedRuleContexts(FunctionParamContext);
  }
  functionParam(i) {
    return this.getTypedRuleContext(FunctionParamContext, i);
  }
  COMMA_list() {
    return this.getTokens(FilterQueryParser.COMMA);
  }
  COMMA(i) {
    return this.getToken(FilterQueryParser.COMMA, i);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_functionParamList;
  }
  enterRule(listener) {
    if (listener.enterFunctionParamList) {
      listener.enterFunctionParamList(this);
    }
  }
  exitRule(listener) {
    if (listener.exitFunctionParamList) {
      listener.exitFunctionParamList(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitFunctionParamList) {
      return visitor.visitFunctionParamList(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class FunctionParamContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  key() {
    return this.getTypedRuleContext(KeyContext, 0);
  }
  value() {
    return this.getTypedRuleContext(ValueContext, 0);
  }
  array() {
    return this.getTypedRuleContext(ArrayContext, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_functionParam;
  }
  enterRule(listener) {
    if (listener.enterFunctionParam) {
      listener.enterFunctionParam(this);
    }
  }
  exitRule(listener) {
    if (listener.exitFunctionParam) {
      listener.exitFunctionParam(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitFunctionParam) {
      return visitor.visitFunctionParam(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class ArrayContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  LBRACK() {
    return this.getToken(FilterQueryParser.LBRACK, 0);
  }
  valueList() {
    return this.getTypedRuleContext(ValueListContext, 0);
  }
  RBRACK() {
    return this.getToken(FilterQueryParser.RBRACK, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_array;
  }
  enterRule(listener) {
    if (listener.enterArray) {
      listener.enterArray(this);
    }
  }
  exitRule(listener) {
    if (listener.exitArray) {
      listener.exitArray(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitArray) {
      return visitor.visitArray(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class ValueContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  QUOTED_TEXT() {
    return this.getToken(FilterQueryParser.QUOTED_TEXT, 0);
  }
  NUMBER() {
    return this.getToken(FilterQueryParser.NUMBER, 0);
  }
  BOOL() {
    return this.getToken(FilterQueryParser.BOOL, 0);
  }
  KEY() {
    return this.getToken(FilterQueryParser.KEY, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_value;
  }
  enterRule(listener) {
    if (listener.enterValue) {
      listener.enterValue(this);
    }
  }
  exitRule(listener) {
    if (listener.exitValue) {
      listener.exitValue(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitValue) {
      return visitor.visitValue(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class KeyContext extends ParserRuleContext {
  constructor(parser2, parent, invokingState) {
    super(parent, invokingState);
    this.parser = parser2;
  }
  KEY() {
    return this.getToken(FilterQueryParser.KEY, 0);
  }
  get ruleIndex() {
    return FilterQueryParser.RULE_key;
  }
  enterRule(listener) {
    if (listener.enterKey) {
      listener.enterKey(this);
    }
  }
  exitRule(listener) {
    if (listener.exitKey) {
      listener.exitKey(this);
    }
  }
  // @Override
  accept(visitor) {
    if (visitor.visitKey) {
      return visitor.visitKey(this);
    } else {
      return visitor.visitChildren(this);
    }
  }
}
class SilentErrorListener extends ErrorListener {
  // Truly silent — incomplete typing must not pollute console or fail harness.
  syntaxError() {
  }
}
class TypeTrackingListener {
  tokens = [];
  enterKey(ctx) {
    const token = ctx.KEY().symbol;
    this.tokens.push({
      text: token.text,
      startIndex: token.start,
      stopIndex: token.stop,
      type: "Key"
    });
  }
  enterValue(ctx) {
    const token = ctx.start;
    this.tokens.push({
      text: token.text,
      startIndex: token.start,
      stopIndex: token.stop,
      type: "Value"
    });
  }
  enterComparison(ctx) {
    const children = ctx.children || [];
    for (const child of children) {
      const token = child.symbol;
      if (token && isOperatorToken(token.type)) {
        this.tokens.push({
          text: token.text,
          startIndex: token.start,
          stopIndex: token.stop,
          type: "Operator"
        });
      }
    }
  }
  // Required no-op stubs
  enterEveryRule() {
  }
  exitEveryRule() {
  }
  exitKey() {
  }
  exitValue() {
  }
  exitComparison() {
  }
  visitTerminal() {
  }
  visitErrorNode() {
  }
}
function analyzeQuery(input, lastToken) {
  input = input.trim();
  const chars = CharStreams.fromString(input);
  const lexer = new FilterQueryLexer(chars);
  lexer.removeErrorListeners();
  lexer.addErrorListener(new SilentErrorListener());
  const tokens = new CommonTokenStream(lexer);
  const parser2 = new FilterQueryParser(tokens);
  parser2.removeErrorListeners();
  parser2.addErrorListener(new SilentErrorListener());
  const tree = parser2.query();
  const listener = new TypeTrackingListener();
  ParseTreeWalker.DEFAULT.walk(listener, tree);
  const currentToken = listener.tokens.find(
    (token) => token.text === lastToken.text && token.startIndex === lastToken.start && token.stopIndex === lastToken.stop
  );
  return currentToken;
}
class SilentAntlrErrorListener extends ErrorListener {
  syntaxError() {
  }
  reportAmbiguity() {
  }
  reportAttemptingFullContext() {
  }
  reportContextSensitivity() {
  }
}
function createLexer(input) {
  const chars = CharStreams.fromString(input);
  const lexer = new FilterQueryLexer(chars);
  lexer.removeErrorListeners();
  lexer.addErrorListener(new SilentAntlrErrorListener());
  return lexer;
}
function determineTokenContext(token, query) {
  let isInKey = false;
  let isInNegation = false;
  let isInOperator = false;
  let isInValue = false;
  let isInFunction = false;
  let isInConjunction = false;
  let isInParenthesis = false;
  const tokenType = token.type;
  const currentTokenContext = analyzeQuery(query, token);
  if (!currentTokenContext) {
    isInKey = isKeyToken(tokenType);
    isInOperator = isOperatorToken(tokenType);
    isInValue = isValueToken(tokenType);
  } else {
    switch (currentTokenContext.type) {
      case "Operator":
        isInOperator = true;
        break;
      case "Value":
        isInValue = true;
        break;
      case "Key":
        isInKey = true;
        break;
    }
  }
  isInNegation = tokenType === FilterQueryLexer.NOT;
  isInFunction = isFunctionToken(tokenType);
  isInConjunction = isConjunctionToken(tokenType);
  isInParenthesis = isBracketToken(tokenType);
  return {
    isInKey,
    isInNegation,
    isInOperator,
    isInValue,
    isInFunction,
    isInConjunction,
    isInParenthesis
  };
}
function determineContextBoundaries(query, cursorIndex, tokens, queryPairs) {
  let currentPair = null;
  if (queryPairs.length > 0) {
    currentPair = getCurrentQueryPair(queryPairs, query, cursorIndex);
  }
  let bracketContext = null;
  const openBrackets = [];
  for (let i = 0; i < tokens.length; i++) {
    const token = tokens[i];
    if (token.channel !== 0) {
      continue;
    }
    if (token.type === FilterQueryLexer.LBRACK || token.type === FilterQueryLexer.LPAREN) {
      let isForList = false;
      if (i > 0) {
        for (let j = i - 1; j >= 0; j--) {
          const prevToken = tokens[j];
          if (prevToken.channel !== 0) {
            continue;
          }
          if (prevToken.type === FilterQueryLexer.IN || prevToken.type === FilterQueryLexer.NOT && j + 1 < tokens.length && tokens[j + 1].type === FilterQueryLexer.IN) {
            isForList = true;
            break;
          } else if (prevToken.channel === 0 && !isValueToken(prevToken.type)) {
            break;
          }
        }
      }
      openBrackets.push({ token, isForList });
    } else if ((token.type === FilterQueryLexer.RBRACK || token.type === FilterQueryLexer.RPAREN) && openBrackets.length > 0) {
      const matchingOpen = openBrackets.pop();
      if (matchingOpen && matchingOpen.token.start <= cursorIndex && cursorIndex <= token.stop + 1) {
        bracketContext = {
          start: matchingOpen.token.start,
          end: token.stop,
          isForList: matchingOpen.isForList
        };
        break;
      }
      if (matchingOpen && token.stop + 1 < cursorIndex && cursorIndex <= token.stop + 2 && query[token.stop + 1] === " ") {
        bracketContext = {
          start: matchingOpen.token.start,
          end: token.stop,
          isForList: matchingOpen.isForList
        };
        break;
      }
    }
    if (token.start <= cursorIndex && cursorIndex <= token.stop + 1) {
      if (token.type === FilterQueryLexer.LBRACK || token.type === FilterQueryLexer.LPAREN) {
        let isForList = false;
        for (let j = i - 1; j >= 0; j--) {
          const prevToken = tokens[j];
          if (prevToken.channel !== 0) {
            continue;
          }
          if (prevToken.type === FilterQueryLexer.IN || prevToken.type === FilterQueryLexer.NOT && j + 1 < tokens.length && tokens[j + 1].type === FilterQueryLexer.IN) {
            isForList = true;
            break;
          } else if (prevToken.channel === 0) {
            break;
          }
        }
        bracketContext = {
          start: token.start,
          end: token.stop,
          isForList
        };
        break;
      }
      if (token.type === FilterQueryLexer.RBRACK || token.type === FilterQueryLexer.RPAREN) {
        if (openBrackets.length > 0) {
          const matchingOpen = openBrackets[openBrackets.length - 1];
          bracketContext = {
            start: matchingOpen.token.start,
            end: token.stop,
            isForList: matchingOpen.isForList
          };
        } else {
          bracketContext = {
            start: token.start,
            end: token.stop,
            isForList: false
            // We don't know, assume not list
          };
        }
        break;
      }
    }
  }
  if (currentPair) {
    const { position } = currentPair;
    const negationContext = {
      start: position.negationStart ?? 0,
      end: position.negationEnd ?? 0
    };
    const keyContext = {
      start: position.keyStart,
      end: position.keyEnd
    };
    let operatorStart = position.keyEnd + 1;
    while (operatorStart < query.length && query[operatorStart] === " ") {
      operatorStart++;
    }
    const operatorContext = {
      start: operatorStart,
      end: position.operatorEnd
    };
    let valueStart = position.operatorEnd + 1;
    while (valueStart < query.length && query[valueStart] === " ") {
      valueStart++;
    }
    const isInOperator = isMultiValueOperator(currentPair.operator);
    let valueContext = null;
    if (isInOperator && bracketContext && bracketContext.isForList) {
      valueContext = {
        start: bracketContext.start,
        end: bracketContext.end
      };
    } else if (position.valueEnd) {
      valueContext = {
        start: valueStart,
        end: position.valueEnd
      };
    }
    let conjunctionContext = null;
    if (position.valueEnd) {
      let conjunctionStart = position.valueEnd + 1;
      while (conjunctionStart < query.length && query[conjunctionStart] === " ") {
        conjunctionStart++;
      }
      for (const token of tokens) {
        if (token.start === conjunctionStart && (token.type === FilterQueryLexer.AND || token.type === FilterQueryLexer.OR)) {
          conjunctionContext = {
            start: conjunctionStart,
            end: token.stop
          };
          break;
        }
      }
    }
    return {
      keyContext,
      negationContext,
      operatorContext,
      valueContext,
      conjunctionContext,
      bracketContext
    };
  }
  const tokenAtCursor2 = tokens.find(
    (token) => token.channel === 0 && token.start <= cursorIndex && cursorIndex <= token.stop + 1
  );
  if (tokenAtCursor2) {
    if (tokenAtCursor2.type === FilterQueryLexer.KEY) {
      return {
        keyContext: { start: tokenAtCursor2.start, end: tokenAtCursor2.stop },
        negationContext: null,
        operatorContext: null,
        valueContext: null,
        conjunctionContext: null,
        bracketContext
      };
    }
    if (tokenAtCursor2.type === FilterQueryLexer.NOT) {
      return {
        keyContext: null,
        negationContext: { start: tokenAtCursor2.start, end: tokenAtCursor2.stop },
        operatorContext: null,
        valueContext: null,
        conjunctionContext: null,
        bracketContext
      };
    }
    if (isOperatorToken(tokenAtCursor2.type)) {
      return {
        keyContext: null,
        negationContext: null,
        operatorContext: { start: tokenAtCursor2.start, end: tokenAtCursor2.stop },
        valueContext: null,
        conjunctionContext: null,
        bracketContext
      };
    }
    if (isValueToken(tokenAtCursor2.type)) {
      return {
        keyContext: null,
        negationContext: null,
        operatorContext: null,
        valueContext: { start: tokenAtCursor2.start, end: tokenAtCursor2.stop },
        conjunctionContext: null,
        bracketContext
      };
    }
    if (isConjunctionToken(tokenAtCursor2.type)) {
      return {
        keyContext: null,
        negationContext: null,
        operatorContext: null,
        valueContext: null,
        conjunctionContext: { start: tokenAtCursor2.start, end: tokenAtCursor2.stop },
        bracketContext
      };
    }
  }
  return {
    keyContext: null,
    negationContext: null,
    operatorContext: null,
    valueContext: null,
    conjunctionContext: null,
    bracketContext
  };
}
function getQueryContextAtCursor(query, cursorIndex) {
  try {
    const stackTrace = new Error().stack || "";
    const callCount = (stackTrace.match(/getQueryContextAtCursor/g) || []).length;
    if (callCount > 3) {
      return {
        tokenType: -1,
        text: "",
        start: cursorIndex,
        stop: cursorIndex,
        currentToken: "",
        isInKey: true,
        isInNegation: false,
        isInOperator: false,
        isInValue: false,
        isInFunction: false,
        isInConjunction: false,
        isInParenthesis: false,
        isInBracketList: false,
        queryPairs: [],
        currentPair: null
      };
    }
    const isAtSpace = cursorIndex < query.length && query[cursorIndex] === " ";
    const isAfterSpace = cursorIndex > 0 && query[cursorIndex - 1] === " ";
    const isAfterToken = cursorIndex > 0 && query[cursorIndex - 1] !== " ";
    const isTransitionPoint = isAtSpace && isAfterToken || cursorIndex === query.length && isAfterToken;
    const input = query || "";
    const lexer = createLexer(input);
    const tokenStream = new CommonTokenStream(lexer);
    tokenStream.fill();
    const allTokens = tokenStream.tokens;
    let exactToken = null;
    let previousToken = null;
    let nextToken = null;
    let lastTokenBeforeCursor = null;
    for (const token of allTokens) {
      if (token.type === FilterQueryLexer.EOF) {
        continue;
      }
      if (token.stop < cursorIndex || token.stop + 1 === cursorIndex) {
        lastTokenBeforeCursor = token;
      }
      if (token.start > cursorIndex) {
        break;
      }
    }
    const queryPairs = extractQueryPairs(query);
    let currentPair = null;
    if (queryPairs.length > 0) {
      currentPair = getCurrentQueryPair(queryPairs, query, cursorIndex);
    }
    const contextBoundaries = determineContextBoundaries(query, cursorIndex, allTokens, queryPairs);
    const isInKeyBoundary = contextBoundaries.keyContext && (cursorIndex >= contextBoundaries.keyContext.start && cursorIndex <= contextBoundaries.keyContext.end || cursorIndex === contextBoundaries.keyContext.end + 1);
    const isInNegationBoundary = contextBoundaries.negationContext && (cursorIndex >= contextBoundaries.negationContext.start && cursorIndex <= contextBoundaries.negationContext.end || cursorIndex === contextBoundaries.negationContext.end + 1);
    const isInOperatorBoundary = contextBoundaries.operatorContext && (cursorIndex >= contextBoundaries.operatorContext.start && cursorIndex <= contextBoundaries.operatorContext.end || cursorIndex === contextBoundaries.operatorContext.end + 1);
    const isInValueBoundary = contextBoundaries.valueContext && (cursorIndex >= contextBoundaries.valueContext.start && cursorIndex <= contextBoundaries.valueContext.end || cursorIndex === contextBoundaries.valueContext.end + 1);
    const isInConjunctionBoundary = contextBoundaries.conjunctionContext && (cursorIndex >= contextBoundaries.conjunctionContext.start && cursorIndex <= contextBoundaries.conjunctionContext.end || cursorIndex === contextBoundaries.conjunctionContext.end + 1);
    const isInBracketListBoundary = contextBoundaries.bracketContext && contextBoundaries.bracketContext.isForList && cursorIndex >= contextBoundaries.bracketContext.start && cursorIndex <= contextBoundaries.bracketContext.end + 1;
    const isInParenthesisBoundary = contextBoundaries.bracketContext && !contextBoundaries.bracketContext.isForList && cursorIndex >= contextBoundaries.bracketContext.start && cursorIndex <= contextBoundaries.bracketContext.end + 1;
    const isAfterClosingBracketList = contextBoundaries.bracketContext && contextBoundaries.bracketContext.isForList && cursorIndex === contextBoundaries.bracketContext.end + 2 && query[contextBoundaries.bracketContext.end + 1] === " ";
    if (isInKeyBoundary || isInNegationBoundary || isInOperatorBoundary || isInValueBoundary || isInConjunctionBoundary || isInBracketListBoundary || isAfterClosingBracketList) {
      const keyToken = currentPair?.key || "";
      const operatorToken = currentPair?.operator || "";
      const valueToken = currentPair?.value || "";
      const isForMultiValueOperator = isMultiValueOperator(operatorToken);
      const finalIsInValue = isInValueBoundary || isInBracketListBoundary && isForMultiValueOperator;
      const finalIsInConjunction = isInConjunctionBoundary || isAfterClosingBracketList;
      return {
        tokenType: -1,
        text: "",
        start: cursorIndex,
        stop: cursorIndex,
        currentToken: "",
        isInKey: isInKeyBoundary || false,
        isInNegation: isInNegationBoundary || false,
        isInOperator: isInOperatorBoundary || false,
        isInValue: finalIsInValue || false,
        isInConjunction: finalIsInConjunction || false,
        isInFunction: false,
        isInParenthesis: isInParenthesisBoundary || false,
        isInBracketList: isInBracketListBoundary || false,
        keyToken: isInKeyBoundary ? keyToken : isInOperatorBoundary || finalIsInValue ? keyToken : void 0,
        operatorToken: isInOperatorBoundary ? operatorToken : finalIsInValue ? operatorToken : void 0,
        valueToken: finalIsInValue ? valueToken : void 0,
        queryPairs,
        currentPair
      };
    }
    if (cursorIndex >= input.length && allTokens.length > 0) {
      let lastRealToken;
      for (let i = allTokens.length - 1; i >= 0; i--) {
        if (allTokens[i].type !== FilterQueryLexer.EOF) {
          lastRealToken = allTokens[i];
          break;
        }
      }
      if (lastRealToken) {
        exactToken = lastRealToken;
        previousToken = null;
        for (let i = allTokens.length - 1; i >= 0; i--) {
          if (allTokens[i].stop < lastRealToken.start) {
            previousToken = allTokens[i];
            break;
          }
        }
      }
    } else {
      for (let i = 0; i < allTokens.length; i++) {
        const token = allTokens[i];
        if (token.type === FilterQueryLexer.EOF) {
          continue;
        }
        if (token.start <= cursorIndex && cursorIndex <= token.stop + 1) {
          exactToken = token;
          previousToken = i > 0 ? allTokens[i - 1] : null;
          nextToken = i < allTokens.length - 1 ? allTokens[i + 1] : null;
          break;
        }
      }
      if (!exactToken) {
        for (let i = 0; i < allTokens.length - 1; i++) {
          const current = allTokens[i];
          const next = allTokens[i + 1];
          if (current.type === FilterQueryLexer.EOF || next.type === FilterQueryLexer.EOF) {
            continue;
          }
          if (current.stop + 1 < cursorIndex && cursorIndex < next.start) {
            previousToken = current;
            nextToken = next;
            break;
          }
        }
      }
    }
    if (!previousToken && !nextToken && !exactToken && !lastTokenBeforeCursor) {
      return {
        tokenType: -1,
        text: "",
        start: cursorIndex,
        stop: cursorIndex,
        currentToken: "",
        isInKey: true,
        // Default to key context when input is empty
        isInNegation: false,
        isInOperator: false,
        isInValue: false,
        isInFunction: false,
        isInConjunction: false,
        isInParenthesis: false,
        isInBracketList: false,
        queryPairs,
        // Add all query pairs to the context
        currentPair: null
        // No current pair when query is empty
      };
    }
    if (lastTokenBeforeCursor && (isAtSpace || isAfterSpace || isTransitionPoint)) {
      const lastTokenContext = determineTokenContext(lastTokenBeforeCursor, input);
      if (lastTokenContext.isInKey) {
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: true,
          // After key + space, should be operator context
          isInValue: false,
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          keyToken: lastTokenBeforeCursor.text,
          queryPairs,
          currentPair
        };
      }
      if (lastTokenContext.isInNegation) {
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: true,
          // After key + space + NOT, should be operator context
          isInValue: false,
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          keyToken: lastTokenBeforeCursor.text,
          queryPairs,
          currentPair
        };
      }
      if (lastTokenContext.isInOperator) {
        const keyFromPair = currentPair?.key || "";
        const isNonValueToken = isNonValueOperatorToken(lastTokenBeforeCursor.type);
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: false,
          isInValue: !isNonValueToken,
          // After operator + space, should be value context
          isInFunction: false,
          isInConjunction: isNonValueToken,
          isInParenthesis: false,
          isInBracketList: false,
          operatorToken: lastTokenBeforeCursor.text,
          keyToken: keyFromPair,
          // Include key from current pair
          queryPairs,
          currentPair
        };
      }
      if (lastTokenContext.isInValue) {
        const keyFromPair = currentPair?.key || "";
        const operatorFromPair = currentPair?.operator || "";
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: false,
          isInValue: false,
          isInFunction: false,
          isInConjunction: true,
          // After value + space, should be conjunction context
          isInParenthesis: false,
          isInBracketList: false,
          valueToken: lastTokenBeforeCursor.text,
          keyToken: keyFromPair,
          // Include key from current pair
          operatorToken: operatorFromPair,
          // Include operator from current pair
          queryPairs,
          currentPair
        };
      }
      if (lastTokenContext.isInConjunction) {
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: true,
          // After conjunction + space, should be key context
          isInNegation: false,
          isInOperator: false,
          isInValue: false,
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          queryPairs,
          currentPair
        };
      }
      if (lastTokenContext.isInParenthesis && lastTokenBeforeCursor.type === FilterQueryLexer.RPAREN) {
        return {
          tokenType: lastTokenBeforeCursor.type,
          text: lastTokenBeforeCursor.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: lastTokenBeforeCursor.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: false,
          isInValue: false,
          isInFunction: false,
          isInConjunction: true,
          // After RPARAN + space, should be conjunction context
          isInParenthesis: false,
          isInBracketList: false,
          queryPairs,
          currentPair
        };
      }
    }
    if (exactToken && cursorIndex === exactToken.stop + 1) {
      const tokenContext = determineTokenContext(exactToken, input);
      return {
        tokenType: exactToken.type,
        text: exactToken.text,
        start: exactToken.start,
        stop: exactToken.stop,
        currentToken: exactToken.text,
        ...tokenContext,
        isInBracketList: false,
        keyToken: tokenContext.isInKey ? exactToken.text : currentPair?.key || void 0,
        operatorToken: tokenContext.isInOperator ? exactToken.text : currentPair?.operator || void 0,
        valueToken: tokenContext.isInValue ? exactToken.text : currentPair?.value || void 0,
        queryPairs,
        currentPair
      };
    }
    if (exactToken?.channel === 0) {
      const tokenContext = determineTokenContext(exactToken, input);
      const keyFromPair = currentPair?.key || "";
      const operatorFromPair = currentPair?.operator || "";
      return {
        tokenType: exactToken.type,
        text: exactToken.text,
        start: exactToken.start,
        stop: exactToken.stop,
        currentToken: exactToken.text,
        ...tokenContext,
        isInBracketList: false,
        keyToken: tokenContext.isInKey ? exactToken.text : tokenContext.isInOperator || tokenContext.isInValue ? keyFromPair : void 0,
        operatorToken: tokenContext.isInOperator ? exactToken.text : tokenContext.isInValue ? operatorFromPair : void 0,
        valueToken: tokenContext.isInValue ? exactToken.text : void 0,
        queryPairs,
        currentPair
      };
    }
    if (previousToken?.channel === 0) {
      const prevContext = determineTokenContext(previousToken, input);
      const keyFromPair = currentPair?.key || "";
      const operatorFromPair = currentPair?.operator || "";
      if (prevContext.isInOperator) {
        return {
          tokenType: previousToken.type,
          text: previousToken.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: previousToken.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: false,
          isInValue: true,
          // Always in value context after operator
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          operatorToken: previousToken.text,
          keyToken: keyFromPair,
          // Include key from current pair
          queryPairs,
          currentPair
        };
      }
      if (prevContext.isInKey) {
        return {
          tokenType: previousToken.type,
          text: previousToken.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: previousToken.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: true,
          // After key, progress to operator context
          isInValue: false,
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          keyToken: previousToken.text,
          queryPairs,
          currentPair
        };
      }
      if (prevContext.isInValue) {
        return {
          tokenType: previousToken.type,
          text: previousToken.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: previousToken.text,
          isInKey: false,
          isInNegation: false,
          isInOperator: false,
          isInValue: false,
          isInFunction: false,
          isInConjunction: true,
          // After value, progress to conjunction context
          isInParenthesis: false,
          isInBracketList: false,
          valueToken: previousToken.text,
          keyToken: keyFromPair,
          // Include key from current pair
          operatorToken: operatorFromPair,
          // Include operator from current pair
          queryPairs,
          currentPair
        };
      }
      if (prevContext.isInConjunction) {
        return {
          tokenType: previousToken.type,
          text: previousToken.text,
          start: cursorIndex,
          stop: cursorIndex,
          currentToken: previousToken.text,
          isInKey: true,
          // After conjunction, progress back to key context
          isInNegation: false,
          isInOperator: false,
          isInValue: false,
          isInFunction: false,
          isInConjunction: false,
          isInParenthesis: false,
          isInBracketList: false,
          queryPairs,
          currentPair
        };
      }
    }
    return {
      tokenType: -1,
      text: "",
      start: cursorIndex,
      stop: cursorIndex,
      currentToken: "",
      isInKey: true,
      isInNegation: false,
      isInOperator: false,
      isInValue: false,
      isInFunction: false,
      isInConjunction: false,
      isInParenthesis: false,
      isInBracketList: false,
      queryPairs,
      currentPair
    };
  } catch (error) {
    return {
      tokenType: -1,
      text: "",
      start: cursorIndex,
      stop: cursorIndex,
      currentToken: "",
      isInValue: false,
      isInKey: true,
      // Default to key context on error
      isInNegation: false,
      isInOperator: false,
      isInFunction: false,
      isInConjunction: false,
      isInParenthesis: false,
      isInBracketList: false,
      queryPairs: [],
      currentPair: null
    };
  }
}
function extractQueryPairs(query) {
  try {
    const stackTrace = new Error().stack || "";
    const callCount = (stackTrace.match(/extractQueryPairs/g) || []).length;
    if (callCount > 3) {
      return [];
    }
    const input = query || "";
    const lexer = createLexer(input);
    const tokenStream = new CommonTokenStream(lexer);
    tokenStream.fill();
    const allTokens = tokenStream.tokens;
    const queryPairs = [];
    let currentPair = null;
    let iterator = 0;
    while (iterator < allTokens.length) {
      const token = allTokens[iterator];
      iterator += 1;
      if (token.type === FilterQueryLexer.EOF || token.channel !== 0) {
        continue;
      }
      if (token.type === FilterQueryLexer.KEY && !(currentPair && currentPair.key)) {
        if (currentPair && currentPair.key) {
          queryPairs.push({
            key: currentPair.key,
            operator: currentPair.operator || "",
            value: currentPair.value,
            valueList: currentPair.valueList || [],
            valuesPosition: currentPair.valuesPosition || [],
            hasNegation: currentPair.hasNegation || false,
            isMultiValue: currentPair.isMultiValue || false,
            position: {
              keyStart: currentPair.position?.keyStart || 0,
              keyEnd: currentPair.position?.keyEnd || 0,
              operatorStart: currentPair.position?.operatorStart || 0,
              operatorEnd: currentPair.position?.operatorEnd || 0,
              valueStart: currentPair.position?.valueStart,
              valueEnd: currentPair.position?.valueEnd,
              negationStart: currentPair.position?.negationStart || 0,
              negationEnd: currentPair.position?.negationEnd || 0
            },
            isComplete: !!(currentPair.key && currentPair.operator && (currentPair.value || isNonValueOperator(currentPair.operator)))
          });
        }
        currentPair = {
          key: token.text,
          position: {
            keyStart: token.start,
            keyEnd: token.stop,
            operatorStart: 0,
            // Initialize with default values
            operatorEnd: 0
            // Initialize with default values
          }
        };
      } else if (token.type === FilterQueryLexer.NOT && currentPair) {
        currentPair.hasNegation = true;
        currentPair.position = {
          keyStart: currentPair.position?.keyStart || 0,
          keyEnd: currentPair.position?.keyEnd || 0,
          operatorStart: currentPair.position?.operatorStart || 0,
          operatorEnd: currentPair.position?.operatorEnd || 0,
          valueStart: currentPair.position?.valueStart,
          valueEnd: currentPair.position?.valueEnd,
          negationStart: token.start,
          negationEnd: token.stop
        };
      } else if (isOperatorToken(token.type) && currentPair && currentPair.key && !currentPair.operator) {
        let multiValueStart;
        let multiValueEnd;
        if (isMultiValueOperator(token.text)) {
          currentPair.isMultiValue = true;
          const valueList = [];
          const valuesPosition = [];
          if ([FilterQueryLexer.LPAREN, FilterQueryLexer.LBRACK].includes(allTokens[iterator].type)) {
            const openingTokenType = allTokens[iterator].type;
            multiValueStart = allTokens[iterator].start;
            iterator += 1;
            const closingToken = openingTokenType === FilterQueryLexer.LPAREN ? FilterQueryLexer.RPAREN : FilterQueryLexer.RBRACK;
            while (allTokens[iterator].type !== closingToken && iterator < allTokens.length) {
              if (isValueToken(allTokens[iterator].type)) {
                valueList.push(allTokens[iterator].text);
                valuesPosition.push({
                  start: allTokens[iterator].start,
                  end: allTokens[iterator].stop
                });
              }
              iterator += 1;
            }
            if (allTokens[iterator].type === closingToken) {
              multiValueEnd = allTokens[iterator].stop;
            }
          } else if (isValueToken(allTokens[iterator].type)) {
            valueList.push(allTokens[iterator].text);
            valuesPosition.push({
              start: allTokens[iterator].start,
              end: allTokens[iterator].stop
            });
            multiValueStart = allTokens[iterator].start;
            multiValueEnd = allTokens[iterator].stop;
            iterator += 1;
          }
          currentPair.valuesPosition = valuesPosition;
          currentPair.valueList = valueList;
          if (multiValueStart && multiValueEnd) {
            currentPair.value = query.substring(multiValueStart, multiValueEnd + 1);
          }
        }
        currentPair.operator = token.text;
        currentPair.position = {
          keyStart: currentPair.position?.keyStart || 0,
          keyEnd: currentPair.position?.keyEnd || 0,
          operatorStart: token.start,
          operatorEnd: token.stop,
          valueStart: multiValueStart || currentPair.position?.valueStart,
          valueEnd: multiValueEnd || currentPair.position?.valueEnd,
          negationStart: currentPair.position?.negationStart || 0,
          negationEnd: currentPair.position?.negationEnd || 0
        };
      } else if (isValueToken(token.type) && currentPair && currentPair.key && currentPair.operator && !isNonValueOperator(currentPair.operator) && !currentPair.value) {
        currentPair.value = token.text;
        currentPair.position = {
          keyStart: currentPair.position?.keyStart || 0,
          keyEnd: currentPair.position?.keyEnd || 0,
          operatorStart: currentPair.position?.operatorStart || 0,
          operatorEnd: currentPair.position?.operatorEnd || 0,
          valueStart: token.start,
          valueEnd: token.stop,
          negationStart: currentPair.position?.negationStart || 0,
          negationEnd: currentPair.position?.negationEnd || 0
        };
      } else if (currentPair && currentPair.key && (isConjunctionToken(token.type) || token.type === FilterQueryLexer.KEY)) {
        queryPairs.push({
          key: currentPair.key,
          operator: currentPair.operator || "",
          value: currentPair.value,
          valueList: currentPair.valueList || [],
          valuesPosition: currentPair.valuesPosition || [],
          hasNegation: currentPair.hasNegation || false,
          isMultiValue: currentPair.isMultiValue || false,
          position: {
            keyStart: currentPair.position?.keyStart || 0,
            keyEnd: currentPair.position?.keyEnd || 0,
            operatorStart: currentPair.position?.operatorStart || 0,
            operatorEnd: currentPair.position?.operatorEnd || 0,
            valueStart: currentPair.position?.valueStart,
            valueEnd: currentPair.position?.valueEnd,
            negationStart: currentPair.position?.negationStart || 0,
            negationEnd: currentPair.position?.negationEnd || 0
          },
          isComplete: !!(currentPair.key && currentPair.operator && (currentPair.value || isNonValueOperator(currentPair.operator)))
        });
        currentPair = null;
        if (token.type === FilterQueryLexer.KEY) {
          currentPair = {
            key: token.text,
            position: {
              keyStart: token.start,
              keyEnd: token.stop,
              operatorStart: 0,
              // Initialize with default values
              operatorEnd: 0
              // Initialize with default values
            }
          };
        }
      }
    }
    if (currentPair && currentPair.key) {
      queryPairs.push({
        key: currentPair.key,
        operator: currentPair.operator || "",
        value: currentPair.value,
        valueList: currentPair.valueList || [],
        valuesPosition: currentPair.valuesPosition || [],
        hasNegation: currentPair.hasNegation || false,
        isMultiValue: currentPair.isMultiValue || false,
        position: {
          keyStart: currentPair.position?.keyStart || 0,
          keyEnd: currentPair.position?.keyEnd || 0,
          operatorStart: currentPair.position?.operatorStart || 0,
          operatorEnd: currentPair.position?.operatorEnd || 0,
          valueStart: currentPair.position?.valueStart,
          valueEnd: currentPair.position?.valueEnd,
          negationStart: currentPair.position?.negationStart || 0,
          negationEnd: currentPair.position?.negationEnd || 0
        },
        isComplete: !!(currentPair.key && currentPair.operator && (currentPair.value || isNonValueOperator(currentPair.operator)))
      });
    }
    return queryPairs;
  } catch (error) {
    return [];
  }
}
function getEndIndexAfterSpaces(pair, query) {
  const { position } = pair;
  let pairEnd = position.valueEnd || position.operatorEnd || position.keyEnd;
  pairEnd += 1;
  while (pairEnd < query.length && query.charAt(pairEnd) === " ") {
    pairEnd += 1;
  }
  return pairEnd;
}
function getCurrentQueryPair(queryPairs, query, cursorIndex) {
  try {
    if (queryPairs.length > 0) {
      let bestMatch = null;
      for (const pair of queryPairs) {
        const { position } = pair;
        const pairEnd = position.valueEnd || position.operatorEnd || position.keyEnd;
        const pairStart = position.keyStart ?? (position.operatorStart || position.valueStart || 0);
        if ((pairEnd >= cursorIndex && pairStart <= cursorIndex || !pair.isComplete && pairStart <= cursorIndex && getEndIndexAfterSpaces(pair, query) >= cursorIndex) && (!bestMatch || pairEnd > (bestMatch.position.valueEnd || bestMatch.position.operatorEnd || bestMatch.position.keyEnd))) {
          bestMatch = pair;
        }
      }
      if (bestMatch) {
        return bestMatch;
      }
      if (cursorIndex === 0) {
        return null;
      }
      if (cursorIndex >= query.length && queryPairs.length > 0) {
        return queryPairs[queryPairs.length - 1];
      }
    }
    return null;
  } catch (error) {
    return null;
  }
}
function normalizeOp(op) {
  if (!op) return void 0;
  return op.replace(/\s+/g, " ").trim();
}
function tokenAtCursor(text, cursorPos) {
  const q = String(text ?? "");
  const pos = Math.max(0, Math.min(cursorPos, q.length));
  if (!q.trim()) return { prefix: "", mode: "key" };
  const ctx = getQueryContextAtCursor(q, pos);
  let mode2 = "key";
  if (ctx.isInConjunction) mode2 = "conj";
  else if (ctx.isInValue || ctx.isInBracketList) mode2 = "value";
  else if (ctx.isInOperator || ctx.isInNegation) mode2 = "op";
  else if (ctx.isInKey) mode2 = "key";
  else {
    const left = q.slice(0, pos);
    if (/\s+$/.test(left) && /(?:['"\]]|EXISTS)\s+$/i.test(left)) mode2 = "conj";
    else if (/=\s*$|\s(?:IN|LIKE|ILIKE|CONTAINS|REGEXP|BETWEEN)\s*$/i.test(left))
      mode2 = "value";
    else if (/[a-zA-Z0-9_.[\]/-]+\s+$/.test(left)) mode2 = "op";
    else mode2 = "key";
  }
  let prefix = "";
  if (mode2 === "key") {
    const left = q.slice(0, pos);
    const m = left.match(/(?:^|[\s(])([a-zA-Z0-9_.[\]/-]*)$/);
    prefix = m?.[1] ?? "";
  } else if (mode2 === "op") {
    const left = q.slice(0, pos);
    const m = left.match(/\s+((?:NOT\s*)?[A-Za-z!<>=]*)$/);
    prefix = m?.[1] ?? "";
  } else if (mode2 === "value") {
    const left = q.slice(0, pos);
    const m = left.match(
      /(?:!=|>=|<=|=|>|<|IN|NOT IN|LIKE|ILIKE|CONTAINS|NOT CONTAINS|REGEXP|BETWEEN)\s+(.*)$/i
    );
    if (m) {
      prefix = m[1].trim().replace(/^['"]|['"]$/g, "").replace(/^\[|\]$/g, "");
    } else {
      prefix = String(ctx.valueToken || ctx.currentToken || "").trim().replace(/^['"]|['"]$/g, "");
    }
  } else if (mode2 === "conj") {
    const left = q.slice(0, pos);
    const m = left.match(/\s+([A-Za-z]*)$/);
    prefix = m?.[1] ?? "";
  }
  return {
    prefix,
    mode: mode2,
    key: ctx.keyToken || void 0,
    op: normalizeOp(ctx.operatorToken),
    antlr: ctx
  };
}
function metadataSuggestDelayMs(prefix) {
  return String(prefix || "").trim() === "" ? 0 : 300;
}
function operatorsForFieldType(fieldType) {
  const t2 = String(fieldType || "string").toLowerCase();
  if (t2 === "bool" || t2 === "boolean") {
    return [
      { value: "=", meta: "equal" },
      { value: "!=", meta: "not equal" },
      { value: "EXISTS", meta: "present" },
      { value: "NOT EXISTS", meta: "absent" }
    ];
  }
  if (t2 === "int" || t2 === "integer" || t2 === "long" || t2 === "float" || t2 === "double" || t2 === "number") {
    return [
      { value: "=", meta: "equal" },
      { value: "!=", meta: "not equal" },
      { value: ">", meta: "gt" },
      { value: ">=", meta: "gte" },
      { value: "<", meta: "lt" },
      { value: "<=", meta: "lte" },
      { value: "IN", meta: "list" },
      { value: "NOT IN", meta: "not list" },
      { value: "EXISTS", meta: "present" },
      { value: "NOT EXISTS", meta: "absent" }
    ];
  }
  return [
    { value: "=", meta: "equal" },
    { value: "!=", meta: "not equal" },
    { value: "IN", meta: "list" },
    { value: "NOT IN", meta: "not list" },
    { value: "LIKE", meta: "like" },
    { value: "ILIKE", meta: "ilike" },
    { value: "CONTAINS", meta: "contains" },
    { value: "NOT CONTAINS", meta: "not contains" },
    { value: "EXISTS", meta: "present" },
    { value: "NOT EXISTS", meta: "absent" },
    { value: "REGEXP", meta: "regex" }
  ];
}
function quoteFilterValue(value, op) {
  const v = String(value ?? "");
  const o = String(op || "").toUpperCase();
  const isNum = /^-?\d+(?:\.\d+)?$/.test(v);
  const isBool = v === "true" || v === "false";
  const lit = isNum || isBool ? v : `'${v.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
  if (o === "IN" || o === "NOT IN") return `[${lit}]`;
  return lit;
}
class QueryErrorListener {
  errors = [];
  syntaxError(_recognizer, offendingSymbol, line, column, msg) {
    if (this.hasUnterminatedQuoteError() && msg.includes("expecting")) {
      return;
    }
    const error = {
      message: msg,
      line,
      column,
      offendingSymbol: offendingSymbol?.text || String(offendingSymbol)
    };
    if (msg.includes("expecting")) {
      const expectedTokens = msg.split("expecting")[1].trim().split(",").map((token) => token.trim());
      error.expectedTokens = expectedTokens;
    }
    const isDuplicate = this.errors.some(
      (e) => e.line === line && e.column === column && this.isSimilarError(e.message, msg)
    );
    if (!isDuplicate) {
      this.errors.push(error);
    }
  }
  hasUnterminatedQuoteError() {
    return this.errors.some(
      (error) => error.message.includes("unterminated") || error.message.includes("missing") && error.message.includes("'")
    );
  }
  isSimilarError = (msg1, msg2) => {
    const normalize = (msg) => msg.toLowerCase().replaceAll(/['"`]/g, "quote").replaceAll(/\s+/g, " ").trim();
    return normalize(msg1) === normalize(msg2);
  };
  reportAmbiguity = () => {
  };
  reportAttemptingFullContext = () => {
  };
  reportContextSensitivity = () => {
  };
  getErrors() {
    return this.errors;
  }
  hasErrors() {
    return this.errors.length > 0;
  }
  getFormattedErrors() {
    return this.errors.map((error) => {
      const { offendingSymbol, expectedTokens, message: errorMessage, line, column } = error;
      let message = `Line ${line}:${column} - ${errorMessage}`;
      if (offendingSymbol && offendingSymbol !== "undefined") {
        message += `
 Symbol: '${offendingSymbol}'`;
      }
      if (expectedTokens && expectedTokens.length > 0) {
        message += `
 Expected: ${expectedTokens.join(", ")}`;
      }
      return message;
    });
  }
}
const validateQuery = (query) => {
  if (!query.trim()) {
    return {
      isValid: true,
      message: "Query is empty",
      errors: []
    };
  }
  try {
    const errorListener = new QueryErrorListener();
    const inputStream = CharStreams.fromString(query);
    const lexer = new FilterQueryLexer(inputStream);
    lexer.removeErrorListeners();
    lexer.addErrorListener(errorListener);
    const tokenStream = new CommonTokenStream(lexer);
    const parser2 = new FilterQueryParser(tokenStream);
    parser2.removeErrorListeners();
    parser2.addErrorListener(errorListener);
    parser2.query();
    if (errorListener.hasErrors()) {
      return {
        isValid: false,
        message: "Query syntax error",
        errors: errorListener.getErrors()
      };
    }
    return {
      isValid: true,
      message: "Query is valid!",
      errors: []
    };
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : "Invalid query syntax";
    const detailedError = {
      message: errorMessage,
      line: 0,
      column: 0,
      offendingSymbol: "",
      expectedTokens: []
    };
    return {
      isValid: false,
      message: "Invalid query syntax",
      errors: [detailedError]
    };
  }
};
function validateFilterExpression(expr) {
  const s = String(expr || "");
  if (!s.trim()) return { ok: true };
  const result = validateQuery(s);
  if (result.isValid) return { ok: true };
  const first = result.errors[0];
  return {
    ok: false,
    message: first?.message || result.message || "Query syntax error",
    column: typeof first?.column === "number" ? first.column + 1 : void 0,
    line: first?.line,
    errors: result.errors.map((e) => ({
      message: e.message,
      line: e.line,
      column: e.column
    }))
  };
}
const _hoisted_1$8 = {
  class: "lqs",
  "data-testid": "signoz-log-query-search"
};
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
  ...{ name: "LogQuerySearch" },
  __name: "LogQuerySearch",
  props: {
    modelValue: {},
    placeholder: {},
    signal: { default: "logs" },
    metricName: {},
    datasourceApi: {},
    testId: {}
  },
  emits: ["update:modelValue", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const resolvedPlaceholder = computed(
      () => props.placeholder ?? t("signoz.querySearch.placeholder")
    );
    const emit = __emit;
    const keyTypeMap = ref({});
    const metaError = ref("");
    let abort = null;
    let debounceTimer = null;
    let debounceSeq = 0;
    const validation = computed(() => validateFilterExpression(props.modelValue || ""));
    const showValidation = computed(() => !validation.value.ok);
    function clearDebounce() {
      if (debounceTimer) {
        clearTimeout(debounceTimer);
        debounceTimer = null;
      }
    }
    function waitMs(ms, seq2) {
      if (ms <= 0) return Promise.resolve();
      return new Promise((resolve) => {
        clearDebounce();
        debounceTimer = setTimeout(() => {
          debounceTimer = null;
          if (seq2 === debounceSeq) resolve();
        }, ms);
      });
    }
    async function fetchKeys(prefix, signal) {
      if (!props.datasourceApi?.getMetadata) return [];
      const res = await props.datasourceApi.getMetadata(
        {
          type: "attributeKeys",
          signal: props.signal || "logs",
          metricName: props.metricName,
          search: prefix || void 0
        },
        signal
      );
      const vals = Array.isArray(res?.values) ? res.values : [];
      const nextMap = { ...keyTypeMap.value };
      const out = [];
      for (const v of vals) {
        const name = String(v?.name ?? v?.key ?? v ?? "").trim();
        if (!name) continue;
        const ft = String(
          v?.fieldDataType || v?.dataType || v?.type || "string"
        );
        nextMap[name] = ft;
        out.push({ name, fieldType: ft });
      }
      keyTypeMap.value = nextMap;
      if (prefix) {
        const p = prefix.toLowerCase();
        return out.filter((o) => o.name.toLowerCase().includes(p));
      }
      return out;
    }
    async function fetchValues(key, prefix, signal) {
      if (!props.datasourceApi?.getMetadata || !key) return [];
      const res = await props.datasourceApi.getMetadata(
        {
          type: "attributeValues",
          signal: props.signal || "logs",
          metricName: props.metricName,
          attributeKey: key,
          search: prefix || void 0
        },
        signal
      );
      const vals = Array.isArray(res?.values) ? res.values : [];
      let out = vals.map((v) => {
        if (v == null) return "";
        if (typeof v === "object") return String(v.value ?? v.name ?? "");
        return String(v);
      }).filter(Boolean);
      if (prefix) {
        const p = prefix.toLowerCase();
        out = out.filter((s) => s.toLowerCase().includes(p));
      }
      return out;
    }
    async function completionSource(context) {
      const text = context.state.doc.toString();
      const pos = context.pos;
      const ctx = tokenAtCursor(text, pos);
      const word = context.matchBefore(/[^\s]*/);
      const from = word?.from ?? pos;
      if (ctx.mode === "op") {
        const ops = operatorsForFieldType(ctx.key ? keyTypeMap.value[ctx.key] : "string");
        const q = (ctx.prefix || "").toUpperCase();
        const options = ops.filter((o) => !q || o.value.toUpperCase().includes(q)).map((o) => ({
          label: o.value,
          type: "keyword",
          detail: o.meta,
          apply: `${o.value} `
        }));
        return options.length ? { from, options } : null;
      }
      if (ctx.mode === "conj") {
        return {
          from,
          options: [
            { label: "AND", type: "keyword", apply: "AND " },
            { label: "OR", type: "keyword", apply: "OR " }
          ]
        };
      }
      const delay = metadataSuggestDelayMs(ctx.prefix || "");
      const seq2 = ++debounceSeq;
      await waitMs(delay, seq2);
      if (seq2 !== debounceSeq) return null;
      abort?.abort();
      abort = new AbortController();
      const signal = abort.signal;
      metaError.value = "";
      try {
        if (ctx.mode === "key") {
          const keys = await fetchKeys(ctx.prefix || "", signal);
          if (signal.aborted) return null;
          return {
            from,
            options: keys.map((k) => ({
              label: k.name,
              type: "variable",
              detail: k.fieldType,
              apply: `${k.name} `
            }))
          };
        }
        const key = ctx.key || "";
        if (!key) return null;
        const values = await fetchValues(key, ctx.prefix || "", signal);
        if (signal.aborted) return null;
        return {
          from,
          options: values.map((v) => {
            const lit = quoteFilterValue(v, ctx.op);
            return {
              label: v,
              type: "text",
              detail: "value",
              apply: `${lit} `
            };
          })
        };
      } catch (e) {
        if (e?.name === "AbortError") return null;
        metaError.value = e?.message || String(e);
        return {
          from,
          options: [
            {
              label: t("signoz.querySearch.metaError", "元数据加载失败"),
              type: "text",
              detail: metaError.value,
              boost: -99,
              apply: () => false
            }
          ]
        };
      }
    }
    onBeforeUnmount(() => {
      abort?.abort();
      clearDebounce();
      debounceSeq += 1;
    });
    watch(
      () => [props.signal, props.metricName],
      () => {
        abort?.abort();
        clearDebounce();
        debounceSeq += 1;
        metaError.value = "";
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$8, [
        createElementVNode(
          "div",
          {
            class: normalizeClass(["lqs-editor-wrap", { "lqs-editor-wrap--error": showValidation.value || Boolean(metaError.value) }])
          },
          [
            createVNode(unref(GIcon), {
              name: "search",
              size: 14,
              class: "lqs-lead"
            }),
            createVNode(unref(GQueryExpressionEditor), {
              class: "lqs-cm",
              embedded: true,
              "font-size": 13,
              "model-value": __props.modelValue,
              placeholder: resolvedPlaceholder.value,
              "aria-label": resolvedPlaceholder.value || unref(t)("signoz.queryBuilder.filter", "过滤条件"),
              "completion-source": completionSource,
              "run-on-enter": true,
              invalid: showValidation.value,
              "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", __props.modelValue || ""))
            }, null, 8, ["model-value", "placeholder", "aria-label", "completion-source", "invalid", "test-id"]),
            showValidation.value ? (openBlock(), createBlock(unref(_sfc_main$34), {
              key: 0,
              title: validation.value.message ? `${validation.value.column != null ? validation.value.column + ": " : ""}${validation.value.message}` : unref(t)("signoz.querySearch.unbalanced", "表达式无效")
            }, {
              default: withCtx(() => [..._cache[2] || (_cache[2] = [
                createElementVNode(
                  "span",
                  {
                    class: "lqs-status lqs-status--error",
                    "data-testid": "signoz-lqs-validation",
                    "aria-label": "validation error"
                  },
                  "!",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            }, 8, ["title"])) : metaError.value ? (openBlock(), createBlock(unref(_sfc_main$34), {
              key: 1,
              title: metaError.value
            }, {
              default: withCtx(() => [..._cache[3] || (_cache[3] = [
                createElementVNode(
                  "span",
                  {
                    class: "lqs-status lqs-status--error",
                    "data-testid": "signoz-lqs-meta-error",
                    "aria-label": "metadata error"
                  },
                  "!",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            }, 8, ["title"])) : createCommentVNode("v-if", true)
          ],
          2
          /* CLASS */
        )
      ]);
    };
  }
});
const LogQuerySearch = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-8f674246"]]);
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 t2 = String(type || "").toLowerCase();
  if (t2.includes("exp") && t2.includes("hist")) return "ExponentialHistogram";
  if (t2.includes("hist")) return "Histogram";
  if (t2 === "sum" || t2.startsWith("sum")) return "Sum";
  if (t2.includes("gauge")) return "Gauge";
  if (t2.includes("counter")) return "Sum";
  return "unknown";
}
function timeAggregationOptions(type) {
  const kind2 = normalizeCatalogKind(type);
  return METRIC_AGG_CATALOG[kind2].time.map((v) => ({ label: v, value: v }));
}
function spaceAggregationOptions(type) {
  const kind2 = normalizeCatalogKind(type);
  return METRIC_AGG_CATALOG[kind2].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$7 = {
  key: 0,
  class: "qb-metrics-hist-row",
  "data-testid": "signoz-metric-aggregation-fields"
};
const _hoisted_2$7 = { class: "qb-label" };
const _hoisted_3$6 = { class: "qb-label qb-label--gap" };
const _hoisted_4$4 = { class: "qb-label qb-label--gap" };
const _hoisted_5$4 = {
  class: "qb-metrics-agg-grid",
  "data-testid": "signoz-metric-aggregation-fields"
};
const _hoisted_6$4 = { class: "qb-metrics-agg-cell" };
const _hoisted_7$4 = { class: "qb-label" };
const _hoisted_8$1 = { class: "qb-metrics-agg-cell" };
const _hoisted_9$1 = { class: "qb-label" };
const _hoisted_10$1 = { class: "qb-metrics-agg-cell" };
const _hoisted_11$1 = { class: "qb-label" };
const _hoisted_12$1 = { class: "qb-metrics-agg-cell" };
const _hoisted_13$1 = { class: "qb-label" };
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
  __name: "MetricAggregationFields",
  props: {
    metricType: {},
    timeAggregation: {},
    spaceAggregation: {},
    stepInterval: {},
    groupBy: {},
    testIdPrefix: {}
  },
  emits: ["update:metricType", "update:timeAggregation", "update:spaceAggregation", "update:stepInterval", "update:groupBy"],
  setup(__props, { emit: __emit }) {
    const STEP_OPTS = [
      { label: "60s", value: 60 },
      { label: "300s", value: 300 },
      { label: "600s", value: 600 },
      { label: "1800s", value: 1800 },
      { label: "3600s", value: 3600 }
    ];
    const props = __props;
    const emit = __emit;
    const tid = (base) => props.testIdPrefix ? `${base}-${props.testIdPrefix}` : base;
    function titleCase(v) {
      if (!v) return v;
      if (v.startsWith("p") && /^p\d+$/.test(v)) return v;
      if (v.includes("_")) {
        return v.split("_").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
      }
      return v.charAt(0).toUpperCase() + v.slice(1);
    }
    const timeOpts = computed(
      () => timeAggregationOptions(props.metricType).map((o) => ({
        label: titleCase(o.value),
        value: o.value
      }))
    );
    const spaceOpts = computed(
      () => spaceAggregationOptions(props.metricType).map((o) => ({
        label: titleCase(o.value),
        value: o.value
      }))
    );
    const hideTime = computed(() => shouldHideTimeAggregation(props.metricType));
    const groupByText = computed(() => (props.groupBy || []).join(", "));
    watch(
      () => props.metricType,
      (mt) => {
        const c = coerceAggregationsForMetricType(mt, {
          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(
        Fragment,
        null,
        [
          createCommentVNode(" Argus histogram: single horizontal row space | groupBy | step "),
          hideTime.value ? (openBlock(), createElementBlock("div", _hoisted_1$7, [
            createElementVNode(
              "span",
              _hoisted_2$7,
              toDisplayString(unref(t)("signoz.queryBuilder.spaceAgg")),
              1
              /* TEXT */
            ),
            createVNode(unref(GSelect), {
              value: __props.spaceAggregation || void 0,
              options: spaceOpts.value,
              "show-search": false,
              "test-id": tid("signoz-space-agg"),
              class: "qb-sel-sm",
              "onUpdate:value": _cache[0] || (_cache[0] = ($event) => emit("update:spaceAggregation", String($event || "")))
            }, null, 8, ["value", "options", "test-id"]),
            createElementVNode(
              "span",
              _hoisted_3$6,
              toDisplayString(unref(t)("signoz.queryBuilder.groupBy")),
              1
              /* TEXT */
            ),
            createVNode(unref(GSelect), {
              value: groupByText.value || void 0,
              options: [],
              "allow-clear": "",
              "show-search": false,
              placeholder: unref(t)("signoz.queryBuilder.placeholderAll"),
              "test-id": tid("signoz-group-by"),
              class: "qb-sel-lg qb-sel-groupby",
              "onUpdate:value": _cache[1] || (_cache[1] = ($event) => emit(
                "update:groupBy",
                String($event || "").split(",").map((s) => s.trim()).filter(Boolean)
              ))
            }, null, 8, ["value", "placeholder", "test-id"]),
            createElementVNode(
              "span",
              _hoisted_4$4,
              toDisplayString(unref(t)("signoz.queryBuilder.step")),
              1
              /* TEXT */
            ),
            createVNode(unref(GSelect), {
              value: __props.stepInterval ?? 60,
              options: STEP_OPTS,
              "show-search": false,
              "test-id": tid("signoz-offset"),
              class: "qb-sel-xs",
              "onUpdate:value": _cache[2] || (_cache[2] = ($event) => emit(
                "update:stepInterval",
                $event == null || $event === "" ? 60 : Number($event)
              ))
            }, null, 8, ["value", "test-id"])
          ])) : (openBlock(), createElementBlock(
            Fragment,
            { key: 1 },
            [
              createCommentVNode(" Argus gauge/sum/etc: 2×2 grid [time|step] / [space|group] "),
              createElementVNode("div", _hoisted_5$4, [
                createElementVNode("div", _hoisted_6$4, [
                  createElementVNode(
                    "span",
                    _hoisted_7$4,
                    toDisplayString(unref(t)("signoz.queryBuilder.timeAgg")),
                    1
                    /* TEXT */
                  ),
                  createVNode(unref(GSelect), {
                    value: __props.timeAggregation || void 0,
                    options: timeOpts.value,
                    "show-search": false,
                    "test-id": tid("signoz-aggregation"),
                    class: "qb-flex",
                    "onUpdate:value": _cache[3] || (_cache[3] = ($event) => emit("update:timeAggregation", String($event || "")))
                  }, null, 8, ["value", "options", "test-id"])
                ]),
                createElementVNode("div", _hoisted_8$1, [
                  createElementVNode(
                    "span",
                    _hoisted_9$1,
                    toDisplayString(unref(t)("signoz.queryBuilder.step")),
                    1
                    /* TEXT */
                  ),
                  createVNode(unref(GSelect), {
                    value: __props.stepInterval ?? 60,
                    options: STEP_OPTS,
                    "show-search": false,
                    "test-id": tid("signoz-offset"),
                    class: "qb-flex",
                    "onUpdate:value": _cache[4] || (_cache[4] = ($event) => emit(
                      "update:stepInterval",
                      $event == null || $event === "" ? 60 : Number($event)
                    ))
                  }, null, 8, ["value", "test-id"])
                ]),
                createElementVNode("div", _hoisted_10$1, [
                  createElementVNode(
                    "span",
                    _hoisted_11$1,
                    toDisplayString(unref(t)("signoz.queryBuilder.spaceAgg")),
                    1
                    /* TEXT */
                  ),
                  createVNode(unref(GSelect), {
                    value: __props.spaceAggregation || void 0,
                    options: spaceOpts.value,
                    "show-search": false,
                    "test-id": tid("signoz-space-agg"),
                    class: "qb-flex",
                    "onUpdate:value": _cache[5] || (_cache[5] = ($event) => emit("update:spaceAggregation", String($event || "")))
                  }, null, 8, ["value", "options", "test-id"])
                ]),
                createElementVNode("div", _hoisted_12$1, [
                  createElementVNode(
                    "span",
                    _hoisted_13$1,
                    toDisplayString(unref(t)("signoz.queryBuilder.groupBy")),
                    1
                    /* TEXT */
                  ),
                  createVNode(unref(GSelect), {
                    value: groupByText.value || void 0,
                    options: [],
                    "allow-clear": "",
                    "show-search": false,
                    placeholder: unref(t)("signoz.queryBuilder.placeholderAll"),
                    "test-id": tid("signoz-group-by"),
                    class: "qb-flex qb-sel-groupby",
                    "onUpdate:value": _cache[6] || (_cache[6] = ($event) => emit(
                      "update:groupBy",
                      String($event || "").split(",").map((s) => s.trim()).filter(Boolean)
                    ))
                  }, null, 8, ["value", "placeholder", "test-id"])
                ])
              ])
            ],
            2112
            /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
          ))
        ],
        2112
        /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
      );
    };
  }
});
const MetricAggregationFields = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-6c5915f4"]]);
const _hoisted_1$6 = {
  class: "qb",
  "data-testid": "signoz-query-builder"
};
const _hoisted_2$6 = {
  class: "qb-content",
  "data-testid": "signoz-qb-content"
};
const _hoisted_3$5 = ["data-testid", "data-query-name"];
const _hoisted_4$3 = {
  class: "qb-row qb-row--where",
  "data-testid": "signoz-qb-query-chrome"
};
const _hoisted_5$3 = ["data-testid", "title", "aria-expanded", "onClick"];
const _hoisted_6$3 = {
  class: "qb-chip",
  "data-testid": "signoz-qb-query-name",
  "data-matrix-id": "signoz-row-name"
};
const _hoisted_7$3 = {
  hidden: "",
  "data-testid": "signoz-row-name"
};
const _hoisted_8 = {
  key: 1,
  class: "qb-row qb-row--functions",
  "data-testid": "signoz-qb-functions-row"
};
const _hoisted_9 = ["data-testid", "onClick"];
const _hoisted_10 = ["data-testid", "onClick"];
const _hoisted_11 = { class: "qb-ico-label" };
const _hoisted_12 = { class: "qb-row-actions" };
const _hoisted_13 = ["data-testid", "title", "onClick"];
const _hoisted_14 = {
  key: 0,
  hidden: "",
  "data-testid": "signoz-row-copy"
};
const _hoisted_15 = ["data-testid", "title", "onClick"];
const _hoisted_16 = ["data-testid", "title", "onClick"];
const _hoisted_17 = {
  key: 0,
  class: "qb-elements",
  "data-testid": "signoz-qb-query-body"
};
const _hoisted_18 = {
  class: "qb-row qb-row--filter",
  "data-testid": "signoz-qb-filter-row"
};
const _hoisted_19 = {
  key: 0,
  class: "qb-row qb-row--agg",
  "data-testid": "signoz-qb-agg"
};
const _hoisted_20 = { class: "qb-label" };
const _hoisted_21 = {
  key: 1,
  class: "qb-addons-content",
  "data-testid": "signoz-qb-addons-content"
};
const _hoisted_22 = {
  key: 0,
  class: "qb-addon-cell qb-addon-cell--full"
};
const _hoisted_23 = { class: "qb-label" };
const _hoisted_24 = {
  key: 1,
  class: "qb-addon-cell"
};
const _hoisted_25 = { class: "qb-label" };
const _hoisted_26 = {
  key: 2,
  class: "qb-addon-cell"
};
const _hoisted_27 = { class: "qb-label" };
const _hoisted_28 = {
  key: 3,
  class: "qb-addon-cell"
};
const _hoisted_29 = { class: "qb-label" };
const _hoisted_30 = {
  key: 4,
  class: "qb-addon-cell qb-addon-cell--full"
};
const _hoisted_31 = { class: "qb-label" };
const _hoisted_32 = {
  key: 2,
  class: "qb-addons-bar",
  "data-testid": "signoz-qb-addons-bar"
};
const _hoisted_33 = ["data-testid", "onClick"];
const _hoisted_34 = { class: "qb-ico-label" };
const _hoisted_35 = ["data-testid"];
const _hoisted_36 = { class: "qb-row qb-row--where" };
const _hoisted_37 = ["data-testid", "title", "aria-expanded", "onClick"];
const _hoisted_38 = { class: "qb-chip qb-chip--formula" };
const _hoisted_39 = { class: "qb-row-actions" };
const _hoisted_40 = ["data-testid", "title", "onClick"];
const _hoisted_41 = ["data-testid", "title", "onClick"];
const _hoisted_42 = { class: "qb-row qb-row--formula-body" };
const _hoisted_43 = { class: "qb-formula-expr-wrap" };
const _hoisted_44 = { class: "qb-label" };
const _hoisted_45 = { class: "qb-formula-legend-wrap" };
const _hoisted_46 = { class: "qb-label" };
const _hoisted_47 = {
  key: 0,
  class: "qb-addons-content"
};
const _hoisted_48 = {
  key: 0,
  class: "qb-addon-cell"
};
const _hoisted_49 = { class: "qb-label" };
const _hoisted_50 = {
  key: 1,
  class: "qb-addon-cell"
};
const _hoisted_51 = { class: "qb-label" };
const _hoisted_52 = { class: "qb-addons-bar" };
const _hoisted_53 = ["onClick"];
const _hoisted_54 = { class: "qb-ico-label" };
const _hoisted_55 = ["onClick"];
const _hoisted_56 = { class: "qb-ico-label" };
const _hoisted_57 = {
  class: "qb-footer",
  "data-testid": "signoz-qb-footer"
};
const _hoisted_58 = { "data-testid": "signoz-add-query" };
const _hoisted_59 = { class: "qb-ico-label" };
const _hoisted_60 = { "data-testid": "signoz-add-formula" };
const _hoisted_61 = { class: "qb-ico-label" };
const _hoisted_62 = {
  key: 0,
  class: "qb-nav",
  "data-testid": "signoz-qb-navigator",
  "aria-hidden": "true"
};
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
  __name: "QueryBuilder",
  props: {
    modelValue: {},
    mode: {},
    showAgg: { type: Boolean, default: false },
    simple: { type: Boolean, default: false },
    datasourceApi: {}
  },
  emits: ["change", "update:modelValue", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const clock2 = {
      mode: props.mode,
      now: () => Date.now()
    };
    const state2 = ref(
      props.modelValue ? {
        queries: props.modelValue.queries.map((q) => ({ ...q })),
        formulas: props.modelValue.formulas.map((f) => ({ ...f }))
      } : createInitialState(clock2)
    );
    watch(
      () => props.modelValue,
      (v) => {
        if (!v) return;
        state2.value = {
          queries: v.queries.map((q) => ({ ...q })),
          formulas: v.formulas.map((f) => ({ ...f }))
        };
      },
      { deep: true }
    );
    const display = computed(
      () => resolveDisplayFlags({ showAgg: props.showAgg, simple: props.simple })
    );
    const forcedMode = computed(() => props.mode);
    const signalOptions = computed(() => [
      {
        label: t("signoz.queryBuilder.signal.traces"),
        value: "traces"
      },
      {
        label: t("signoz.queryBuilder.signal.logs"),
        value: "logs"
      },
      {
        label: t("signoz.queryBuilder.signal.metrics"),
        value: "metrics"
      },
      {
        label: t("signoz.queryBuilder.signal.exceptions"),
        value: "exceptions"
      }
    ]);
    function commit(mutation, mutateLocal) {
      const result = applyMutation(state2.value, mutation);
      state2.value = result.state;
      emit("update:modelValue", state2.value);
      if (result.shouldEmit) {
        emit("change", state2.value.queries, state2.value.formulas);
      }
    }
    function updateQueryField(index2, key, value) {
      const next = {
        queries: state2.value.queries.map(
          (q, i) => i === index2 ? { ...q, [key]: value } : q
        ),
        formulas: state2.value.formulas.map((f) => ({ ...f }))
      };
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function updateFormulaField(index2, key, value) {
      const next = {
        queries: state2.value.queries.map((q) => ({ ...q })),
        formulas: state2.value.formulas.map(
          (f, i) => i === index2 ? { ...f, [key]: value } : f
        )
      };
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function currentSignal2(q) {
      return forcedMode.value ?? q.signal;
    }
    function showSignalSelector() {
      return !forcedMode.value;
    }
    function canDeleteQuery() {
      return state2.value.queries.length > 1;
    }
    function showNavigator() {
      return state2.value.queries.length > 1 || state2.value.formulas.length > 0;
    }
    function addonIconName(key) {
      switch (key) {
        case "group_by":
          return "apps";
        case "having":
          return "filter";
        case "order_by":
          return "sort";
        case "limit":
          return "compress";
        case "legend_format":
          return "tag";
        default:
          return "info";
      }
    }
    function onToggleAddOn(qi, key) {
      commit({ type: "toggleAddOn", queryIndex: qi, key });
    }
    function onToggleFormulaAddOn(fi, key) {
      commit({ type: "toggleFormulaAddOn", formulaIndex: fi, key });
    }
    function onAddFunction(qi) {
      const next = addFunction(state2.value, qi, forcedMode.value);
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function onRemoveFunction(qi, fi) {
      const next = removeFunction(state2.value, qi, fi);
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function updateFunctionField(qi, fi, patch) {
      const next = {
        queries: state2.value.queries.map((q, i) => {
          if (i !== qi) return { ...q };
          const functions = q.functions.map((fn, j) => {
            if (j !== fi) return { ...fn };
            const name = patch.name ?? fn.name;
            const arg = patch.name != null && patch.name !== fn.name ? "" : patch.arg ?? fn.arg;
            return { name, arg };
          });
          return { ...q, functions };
        }),
        formulas: state2.value.formulas.map((f) => ({ ...f }))
      };
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function onMetricTypeChange(qi, metricType) {
      const q = state2.value.queries[qi];
      if (!q) return;
      const clamped = clampAggregationsForMetricType(q, metricType);
      updateQueryField(qi, "metricType", clamped.metricType);
      const next = {
        queries: state2.value.queries.map(
          (item, i) => i === qi ? { ...clamped } : item
        ),
        formulas: state2.value.formulas.map((f) => ({ ...f }))
      };
      state2.value = next;
      emit("update:modelValue", next);
      emit("change", next.queries, next.formulas);
    }
    function fnOptions(q) {
      return functionOptionsForSignal(currentSignal2(q)).map((o) => ({
        label: o.label,
        value: o.value
      }));
    }
    function fnNeedsArg(q, name) {
      const def = functionOptionsForSignal(currentSignal2(q)).find((o) => o.value === name);
      return Boolean(def && def.showArg);
    }
    function patchSelectA11y(root = document) {
      root.querySelectorAll(".ant-select-selection-search-input").forEach((el) => {
        const select = el.closest(".ant-select");
        const labelled = select?.getAttribute("aria-label") || select?.querySelector(".ant-select-selection-item")?.textContent?.trim() || select?.querySelector(".ant-select-selection-placeholder")?.textContent?.trim() || "选择";
        if (!el.getAttribute("aria-label")) el.setAttribute("aria-label", labelled);
        if (!el.hasAttribute("aria-expanded")) el.setAttribute("aria-expanded", "false");
        el.removeAttribute("aria-owns");
        el.removeAttribute("aria-activedescendant");
      });
    }
    let selectA11yObserver = null;
    onMounted(() => {
      nextTick(() => patchSelectA11y());
      selectA11yObserver = new MutationObserver(() => patchSelectA11y());
      selectA11yObserver.observe(document.body, { childList: true, subtree: true });
    });
    onUnmounted(() => {
      selectA11yObserver?.disconnect();
      selectA11yObserver = null;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$6, [
        createElementVNode("div", _hoisted_2$6, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(state2.value.queries, (query, qi) => {
              return openBlock(), createElementBlock("div", {
                key: query.id || query.name + "-" + qi,
                class: "qb-query",
                "data-testid": `signoz-qb-query-${query.name}`,
                "data-query-name": query.name
              }, [
                createElementVNode(
                  "div",
                  {
                    class: normalizeClass(["qb-body pb-2 shadow-sm", { "qb-body--disabled": query.disabled }])
                  },
                  [
                    createCommentVNode(" WHERE chrome: collapse + chip + signal + functions + actions "),
                    createElementVNode("div", _hoisted_4$3, [
                      createElementVNode("button", {
                        type: "button",
                        class: "qb-btn-icon qb-collapse-btn",
                        "data-testid": `signoz-qb-collapse-${qi}`,
                        title: query._collapsed ? unref(t)("signoz.queryBuilder.expand") : unref(t)("signoz.queryBuilder.collapse"),
                        "aria-expanded": !query._collapsed,
                        onClick: ($event) => commit({ type: "toggleCollapse", index: qi })
                      }, [
                        createVNode(unref(GIcon), {
                          name: query._collapsed ? "angle-right" : "angle-down",
                          size: 14
                        }, null, 8, ["name"])
                      ], 8, _hoisted_5$3),
                      createElementVNode(
                        "span",
                        _hoisted_6$3,
                        toDisplayString(query.name),
                        1
                        /* TEXT */
                      ),
                      createElementVNode(
                        "span",
                        _hoisted_7$3,
                        toDisplayString(query.name),
                        1
                        /* TEXT */
                      ),
                      showSignalSelector() ? (openBlock(), createBlock(unref(GSelect), {
                        key: 0,
                        class: "qb-sel-signal",
                        value: query.signal,
                        options: signalOptions.value,
                        "show-search": false,
                        "aria-label": unref(t)("signoz.queryBuilder.signal", "信号类型"),
                        "test-id": "signoz-qb-signal",
                        "onUpdate:value": ($event) => updateQueryField(qi, "signal", $event)
                      }, null, 8, ["value", "options", "aria-label", "onUpdate:value"])) : createCommentVNode("v-if", true),
                      query.functions.length ? (openBlock(), createElementBlock("div", _hoisted_8, [
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(query.functions, (fn, fi) => {
                            return openBlock(), createElementBlock("div", {
                              key: fi,
                              class: "qb-fn-item"
                            }, [
                              createVNode(unref(GSelect), {
                                value: fn.name,
                                options: fnOptions(query),
                                "show-search": false,
                                "aria-label": unref(t)("signoz.queryBuilder.function", "函数"),
                                "test-id": `signoz-qb-fn-name-${qi}-${fi}`,
                                "onUpdate:value": ($event) => updateFunctionField(qi, fi, { name: String($event) })
                              }, null, 8, ["value", "options", "aria-label", "test-id", "onUpdate:value"]),
                              fnNeedsArg(query, fn.name) ? (openBlock(), createBlock(unref(GInput), {
                                key: 0,
                                class: "qb-fn-arg",
                                "model-value": fn.arg,
                                placeholder: unref(t)("signoz.queryBuilder.functionArg"),
                                "data-testid": `signoz-qb-fn-arg-${qi}-${fi}`,
                                "onUpdate:modelValue": ($event) => updateFunctionField(qi, fi, { arg: String($event ?? "") })
                              }, null, 8, ["model-value", "placeholder", "data-testid", "onUpdate:modelValue"])) : createCommentVNode("v-if", true),
                              createElementVNode("button", {
                                type: "button",
                                class: "qb-btn-icon",
                                "data-testid": `signoz-qb-fn-remove-${qi}-${fi}`,
                                onClick: ($event) => onRemoveFunction(qi, fi)
                              }, [..._cache[4] || (_cache[4] = [
                                createElementVNode(
                                  "span",
                                  {
                                    class: "qb-ico qb-ico--14",
                                    "aria-hidden": "true"
                                  },
                                  "×",
                                  -1
                                  /* CACHED */
                                )
                              ])], 8, _hoisted_9)
                            ]);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ])) : createCommentVNode("v-if", true),
                      query.functions.length < 3 ? (openBlock(), createElementBlock("button", {
                        key: 2,
                        type: "button",
                        class: "qb-fn-add-btn",
                        "data-testid": `signoz-qb-functions-${qi}`,
                        onClick: ($event) => onAddFunction(qi)
                      }, [
                        createElementVNode("span", null, [
                          createVNode(unref(GIcon), {
                            name: "plus",
                            size: 12
                          }),
                          createElementVNode(
                            "span",
                            _hoisted_11,
                            toDisplayString(unref(t)("signoz.queryBuilder.addFunction")),
                            1
                            /* TEXT */
                          )
                        ])
                      ], 8, _hoisted_10)) : createCommentVNode("v-if", true),
                      _cache[5] || (_cache[5] = createElementVNode(
                        "div",
                        { class: "flex-1" },
                        null,
                        -1
                        /* CACHED */
                      )),
                      createElementVNode("div", _hoisted_12, [
                        createElementVNode("button", {
                          type: "button",
                          class: "qb-btn-icon",
                          "data-testid": `signoz-qb-clone-${qi}`,
                          "data-matrix-id": "signoz-row-copy",
                          title: unref(t)("signoz.queryBuilder.cloneQuery"),
                          onClick: ($event) => commit({ type: "cloneQuery", index: qi, opts: clock2 })
                        }, [
                          qi === 0 ? (openBlock(), createElementBlock("span", _hoisted_14)) : createCommentVNode("v-if", true),
                          createVNode(unref(GIcon), {
                            name: "copy",
                            size: 14
                          })
                        ], 8, _hoisted_13),
                        createElementVNode("button", {
                          type: "button",
                          class: "qb-btn-icon",
                          "data-testid": `signoz-qb-disable-${qi}`,
                          title: query.disabled ? unref(t)("signoz.traces.enableQuery") : unref(t)("signoz.traces.disableQuery"),
                          onClick: ($event) => commit({ type: "toggleDisabled", index: qi })
                        }, [
                          createVNode(unref(GIcon), {
                            name: query.disabled ? "eye-slash" : "eye",
                            size: 14
                          }, null, 8, ["name"])
                        ], 8, _hoisted_15),
                        canDeleteQuery() ? (openBlock(), createElementBlock("button", {
                          key: 0,
                          type: "button",
                          class: "qb-btn-icon qb-btn-icon--danger",
                          "data-testid": `signoz-qb-remove-${qi}`,
                          title: unref(t)("signoz.traces.removeQuery"),
                          onClick: ($event) => commit({ type: "removeQuery", index: qi })
                        }, [
                          createVNode(unref(GIcon), {
                            name: "trash",
                            size: 14
                          })
                        ], 8, _hoisted_16)) : createCommentVNode("v-if", true)
                      ])
                    ]),
                    createCommentVNode(" Collapsible body: filter / agg / add-ons — indented tree "),
                    !query._collapsed ? (openBlock(), createElementBlock("div", _hoisted_17, [
                      createElementVNode("div", _hoisted_18, [
                        currentSignal2(query) === "metrics" ? (openBlock(), createBlock(unref(GSelect), {
                          key: 0,
                          class: "qb-sel-metric",
                          "show-search": true,
                          value: query.metricName || void 0,
                          options: (query._metricOpts || []).map((m) => ({
                            label: typeof m === "string" ? m : m.name || m.label || String(m),
                            value: typeof m === "string" ? m : m.name || m.value || String(m)
                          })),
                          placeholder: unref(t)("signoz.metrics.selectMetricPlaceholder"),
                          "allow-clear": "",
                          "test-id": "signoz-qb-metric-name",
                          "onUpdate:value": ($event) => updateQueryField(qi, "metricName", String($event ?? ""))
                        }, null, 8, ["value", "options", "placeholder", "onUpdate:value"])) : createCommentVNode("v-if", true),
                        createVNode(LogQuerySearch, {
                          class: "flex-1",
                          "model-value": query.where,
                          signal: currentSignal2(query) === "metrics" ? "metrics" : currentSignal2(query) === "logs" ? "logs" : "traces",
                          "datasource-api": __props.datasourceApi,
                          "data-testid": "signoz-qb-where",
                          "onUpdate:modelValue": ($event) => updateQueryField(qi, "where", $event),
                          onRun: _cache[0] || (_cache[0] = ($event) => emit("run"))
                        }, null, 8, ["model-value", "signal", "datasource-api", "onUpdate:modelValue"])
                      ]),
                      display.value.showAgg ? (openBlock(), createElementBlock("div", _hoisted_19, [
                        currentSignal2(query) === "metrics" ? (openBlock(), createBlock(MetricAggregationFields, {
                          key: 0,
                          "metric-type": query.metricType,
                          "time-aggregation": query.timeAggregation,
                          "space-aggregation": query.spaceAggregation,
                          "step-interval": query.step === null || query.step === void 0 ? null : query.step,
                          "group-by": query.groupBy,
                          "test-id-prefix": String(qi),
                          "onUpdate:metricType": ($event) => onMetricTypeChange(qi, $event),
                          "onUpdate:timeAggregation": ($event) => updateQueryField(qi, "timeAggregation", $event),
                          "onUpdate:spaceAggregation": ($event) => updateQueryField(qi, "spaceAggregation", $event),
                          "onUpdate:stepInterval": ($event) => updateQueryField(qi, "step", $event ?? 60),
                          "onUpdate:groupBy": ($event) => updateQueryField(qi, "groupBy", $event)
                        }, null, 8, ["metric-type", "time-aggregation", "space-aggregation", "step-interval", "group-by", "test-id-prefix", "onUpdate:metricType", "onUpdate:timeAggregation", "onUpdate:spaceAggregation", "onUpdate:stepInterval", "onUpdate:groupBy"])) : (openBlock(), createElementBlock(
                          Fragment,
                          { key: 1 },
                          [
                            createElementVNode(
                              "span",
                              _hoisted_20,
                              toDisplayString(unref(t)("signoz.queryBuilder.agg")),
                              1
                              /* TEXT */
                            ),
                            createVNode(QueryAggregationEditor, {
                              class: "flex-1",
                              "model-value": query.aggregations,
                              signal: currentSignal2(query) === "logs" ? "logs" : "traces",
                              "show-interval": true,
                              "step-interval": query.step === null || query.step === void 0 ? null : query.step,
                              "data-testid": "signoz-qb-expression-agg",
                              "onUpdate:modelValue": ($event) => updateQueryField(qi, "aggregations", $event),
                              "onUpdate:stepInterval": ($event) => updateQueryField(qi, "step", $event ?? 60),
                              onRun: _cache[1] || (_cache[1] = ($event) => emit("run"))
                            }, null, 8, ["model-value", "signal", "step-interval", "onUpdate:modelValue", "onUpdate:stepInterval"])
                          ],
                          64
                          /* STABLE_FRAGMENT */
                        ))
                      ])) : createCommentVNode("v-if", true),
                      display.value.showAgg && query._addOns.length ? (openBlock(), createElementBlock("div", _hoisted_21, [
                        query._addOns.includes("group_by") && currentSignal2(query) !== "metrics" ? (openBlock(), createElementBlock("div", _hoisted_22, [
                          createElementVNode(
                            "span",
                            _hoisted_23,
                            toDisplayString(unref(t)("signoz.queryBuilder.groupBy")),
                            1
                            /* TEXT */
                          ),
                          createVNode(unref(GSelect), {
                            class: "flex-1",
                            mode: "multiple",
                            value: query.groupBy,
                            options: [],
                            "allow-clear": "",
                            placeholder: unref(t)("signoz.queryBuilder.placeholderAll"),
                            "show-search": true,
                            "test-id": "signoz-qb-groupby",
                            "onUpdate:value": ($event) => updateQueryField(
                              qi,
                              "groupBy",
                              Array.isArray($event) ? $event : String($event ?? "").split(",").map((s) => s.trim()).filter(Boolean)
                            )
                          }, null, 8, ["value", "placeholder", "onUpdate:value"])
                        ])) : createCommentVNode("v-if", true),
                        query._addOns.includes("having") ? (openBlock(), createElementBlock("div", _hoisted_24, [
                          createElementVNode(
                            "span",
                            _hoisted_25,
                            toDisplayString(unref(t)("signoz.queryBuilder.having")),
                            1
                            /* TEXT */
                          ),
                          createVNode(unref(GInput), {
                            class: "flex-1 having-input",
                            "model-value": query.having,
                            placeholder: unref(t)("signoz.queryBuilder.havingPlaceholder"),
                            "data-testid": "signoz-qb-having",
                            "onUpdate:modelValue": ($event) => updateQueryField(qi, "having", String($event ?? ""))
                          }, null, 8, ["model-value", "placeholder", "onUpdate:modelValue"])
                        ])) : createCommentVNode("v-if", true),
                        query._addOns.includes("order_by") ? (openBlock(), createElementBlock("div", _hoisted_26, [
                          createElementVNode(
                            "span",
                            _hoisted_27,
                            toDisplayString(unref(t)("signoz.queryBuilder.orderBy")),
                            1
                            /* TEXT */
                          ),
                          createVNode(unref(GInput), {
                            class: "flex-1",
                            "model-value": query.orderBy,
                            "data-testid": "signoz-qb-orderby",
                            "onUpdate:modelValue": ($event) => updateQueryField(qi, "orderBy", String($event ?? ""))
                          }, null, 8, ["model-value", "onUpdate:modelValue"])
                        ])) : createCommentVNode("v-if", true),
                        query._addOns.includes("limit") ? (openBlock(), createElementBlock("div", _hoisted_28, [
                          createElementVNode(
                            "span",
                            _hoisted_29,
                            toDisplayString(unref(t)("signoz.queryBuilder.limit")),
                            1
                            /* TEXT */
                          ),
                          createVNode(unref(GInput), {
                            class: "flex-1",
                            "model-value": String(query.limit),
                            type: "number",
                            "data-testid": "signoz-qb-limit",
                            "onUpdate:modelValue": ($event) => updateQueryField(qi, "limit", Number($event) || 0)
                          }, null, 8, ["model-value", "onUpdate:modelValue"])
                        ])) : createCommentVNode("v-if", true),
                        query._addOns.includes("legend_format") ? (openBlock(), createElementBlock("div", _hoisted_30, [
                          createElementVNode(
                            "span",
                            _hoisted_31,
                            toDisplayString(unref(t)("signoz.queryBuilder.legend")),
                            1
                            /* TEXT */
                          ),
                          createVNode(unref(GInput), {
                            class: "qb-legend-input",
                            "model-value": query.legend,
                            placeholder: unref(t)("signoz.queryBuilder.legendPlaceholder"),
                            "data-testid": "signoz-qb-legend",
                            "onUpdate:modelValue": ($event) => updateQueryField(qi, "legend", String($event ?? ""))
                          }, null, 8, ["model-value", "placeholder", "onUpdate:modelValue"])
                        ])) : createCommentVNode("v-if", true)
                      ])) : createCommentVNode("v-if", true),
                      display.value.showAgg ? (openBlock(), createElementBlock("div", _hoisted_32, [
                        (openBlock(true), createElementBlock(
                          Fragment,
                          null,
                          renderList(unref(visibleAddOnKeys)(currentSignal2(query)), (key) => {
                            return openBlock(), createElementBlock("button", {
                              key,
                              type: "button",
                              class: normalizeClass(["qb-addon-btn", {
                                "qb-addon-btn--active": query._addOns.includes(key)
                              }]),
                              "data-testid": `signoz-qb-addon-${key}`,
                              onClick: ($event) => onToggleAddOn(qi, key)
                            }, [
                              createElementVNode("span", null, [
                                createVNode(unref(GIcon), {
                                  name: addonIconName(key),
                                  size: 14
                                }, null, 8, ["name"]),
                                createElementVNode(
                                  "span",
                                  _hoisted_34,
                                  toDisplayString(key === "group_by" ? unref(t)("signoz.queryBuilder.addOnGroupBy") : key === "having" ? unref(t)("signoz.queryBuilder.addOnHaving") : key === "order_by" ? unref(t)("signoz.queryBuilder.addOnOrderBy") : key === "limit" ? unref(t)("signoz.queryBuilder.addOnLimit") : unref(t)("signoz.queryBuilder.addOnLegend")),
                                  1
                                  /* TEXT */
                                )
                              ])
                            ], 10, _hoisted_33);
                          }),
                          128
                          /* KEYED_FRAGMENT */
                        ))
                      ])) : createCommentVNode("v-if", true)
                    ])) : createCommentVNode("v-if", true)
                  ],
                  2
                  /* CLASS */
                )
              ], 8, _hoisted_3$5);
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          !display.value.simple ? (openBlock(true), createElementBlock(
            Fragment,
            { key: 0 },
            renderList(state2.value.formulas, (formula, fi) => {
              return openBlock(), createElementBlock("div", {
                key: formula.id || formula.name + "-" + fi,
                class: "qb-formula",
                "data-testid": `signoz-qb-formula-${formula.name}`
              }, [
                createElementVNode(
                  "div",
                  {
                    class: normalizeClass(["qb-body pb-2 shadow-sm", { "qb-body--disabled": formula.disabled }])
                  },
                  [
                    createElementVNode("div", _hoisted_36, [
                      createElementVNode("button", {
                        type: "button",
                        class: "qb-btn-icon qb-collapse-btn",
                        "data-testid": `signoz-qb-formula-collapse-${fi}`,
                        title: formula._collapsed ? unref(t)("signoz.queryBuilder.expand") : unref(t)("signoz.queryBuilder.collapse"),
                        "aria-expanded": !formula._collapsed,
                        onClick: ($event) => commit({ type: "toggleFormulaCollapse", index: fi })
                      }, [
                        createVNode(unref(GIcon), {
                          name: formula._collapsed ? "angle-right" : "angle-down",
                          size: 14
                        }, null, 8, ["name"])
                      ], 8, _hoisted_37),
                      createElementVNode(
                        "span",
                        _hoisted_38,
                        toDisplayString(formula.name),
                        1
                        /* TEXT */
                      ),
                      _cache[6] || (_cache[6] = createElementVNode(
                        "div",
                        { class: "flex-1" },
                        null,
                        -1
                        /* CACHED */
                      )),
                      createElementVNode("div", _hoisted_39, [
                        createElementVNode("button", {
                          type: "button",
                          class: "qb-btn-icon",
                          "data-testid": `signoz-qb-formula-disable-${fi}`,
                          title: formula.disabled ? unref(t)("signoz.traces.enableQuery") : unref(t)("signoz.traces.disableQuery"),
                          onClick: ($event) => commit({ type: "toggleFormulaDisabled", index: fi })
                        }, [
                          createVNode(unref(GIcon), {
                            name: formula.disabled ? "eye-slash" : "eye",
                            size: 14
                          }, null, 8, ["name"])
                        ], 8, _hoisted_40),
                        createElementVNode("button", {
                          type: "button",
                          class: "qb-btn-icon qb-btn-icon--danger",
                          "data-testid": `signoz-qb-formula-remove-${fi}`,
                          title: unref(t)("signoz.traces.removeQuery"),
                          onClick: ($event) => commit({ type: "removeFormula", index: fi })
                        }, [
                          createVNode(unref(GIcon), {
                            name: "trash",
                            size: 14
                          })
                        ], 8, _hoisted_41)
                      ])
                    ]),
                    !formula._collapsed ? (openBlock(), createElementBlock(
                      Fragment,
                      { key: 0 },
                      [
                        createElementVNode("div", _hoisted_42, [
                          createElementVNode("div", _hoisted_43, [
                            createElementVNode(
                              "span",
                              _hoisted_44,
                              toDisplayString(unref(t)("signoz.queryBuilder.formulaExpr")),
                              1
                              /* TEXT */
                            ),
                            createVNode(unref(GInput), {
                              class: "flex-1",
                              "model-value": formula.expression,
                              placeholder: unref(t)("signoz.queryBuilder.formulaExprPlaceholder"),
                              "data-testid": "signoz-qb-formula-expr",
                              "onUpdate:modelValue": ($event) => updateFormulaField(fi, "expression", String($event ?? ""))
                            }, null, 8, ["model-value", "placeholder", "onUpdate:modelValue"])
                          ]),
                          createElementVNode("div", _hoisted_45, [
                            createElementVNode(
                              "span",
                              _hoisted_46,
                              toDisplayString(unref(t)("signoz.queryBuilder.legend")),
                              1
                              /* TEXT */
                            ),
                            createVNode(unref(GInput), {
                              class: "flex-1",
                              "model-value": formula.legend,
                              placeholder: unref(t)("signoz.queryBuilder.legendPlaceholder"),
                              "data-testid": "signoz-qb-formula-legend",
                              "onUpdate:modelValue": ($event) => updateFormulaField(fi, "legend", String($event ?? ""))
                            }, null, 8, ["model-value", "placeholder", "onUpdate:modelValue"])
                          ])
                        ]),
                        formula._addOns.length ? (openBlock(), createElementBlock("div", _hoisted_47, [
                          formula._addOns.includes("limit") ? (openBlock(), createElementBlock("div", _hoisted_48, [
                            createElementVNode(
                              "span",
                              _hoisted_49,
                              toDisplayString(unref(t)("signoz.queryBuilder.limit")),
                              1
                              /* TEXT */
                            ),
                            createVNode(unref(GInput), {
                              class: "flex-1",
                              "model-value": String(formula.limit),
                              type: "number",
                              "data-testid": "signoz-qb-formula-limit",
                              "onUpdate:modelValue": ($event) => updateFormulaField(fi, "limit", Number($event) || 0)
                            }, null, 8, ["model-value", "onUpdate:modelValue"])
                          ])) : createCommentVNode("v-if", true),
                          formula._addOns.includes("order_by") ? (openBlock(), createElementBlock("div", _hoisted_50, [
                            createElementVNode(
                              "span",
                              _hoisted_51,
                              toDisplayString(unref(t)("signoz.queryBuilder.orderBy")),
                              1
                              /* TEXT */
                            ),
                            createVNode(unref(GInput), {
                              class: "flex-1",
                              "model-value": formula.orderBy,
                              "data-testid": "signoz-qb-formula-orderby",
                              "onUpdate:modelValue": ($event) => updateFormulaField(fi, "orderBy", String($event ?? ""))
                            }, null, 8, ["model-value", "onUpdate:modelValue"])
                          ])) : createCommentVNode("v-if", true)
                        ])) : createCommentVNode("v-if", true),
                        createElementVNode("div", _hoisted_52, [
                          createElementVNode("button", {
                            type: "button",
                            class: normalizeClass(["qb-addon-btn", {
                              "qb-addon-btn--active": formula._addOns.includes("order_by")
                            }]),
                            "data-testid": "signoz-qb-formula-addon-order_by",
                            onClick: ($event) => onToggleFormulaAddOn(fi, "order_by")
                          }, [
                            createElementVNode("span", null, [
                              createVNode(unref(GIcon), {
                                name: "sort",
                                size: 14
                              }),
                              createElementVNode(
                                "span",
                                _hoisted_54,
                                toDisplayString(unref(t)("signoz.queryBuilder.addOnOrderBy")),
                                1
                                /* TEXT */
                              )
                            ])
                          ], 10, _hoisted_53),
                          createElementVNode("button", {
                            type: "button",
                            class: normalizeClass(["qb-addon-btn", {
                              "qb-addon-btn--active": formula._addOns.includes("limit")
                            }]),
                            "data-testid": "signoz-qb-formula-addon-limit",
                            onClick: ($event) => onToggleFormulaAddOn(fi, "limit")
                          }, [
                            createElementVNode("span", null, [
                              createVNode(unref(GIcon), {
                                name: "compress",
                                size: 14
                              }),
                              createElementVNode(
                                "span",
                                _hoisted_56,
                                toDisplayString(unref(t)("signoz.queryBuilder.addOnLimit")),
                                1
                                /* TEXT */
                              )
                            ])
                          ], 10, _hoisted_55)
                        ])
                      ],
                      64
                      /* STABLE_FRAGMENT */
                    )) : createCommentVNode("v-if", true)
                  ],
                  2
                  /* CLASS */
                )
              ], 8, _hoisted_35);
            }),
            128
            /* KEYED_FRAGMENT */
          )) : createCommentVNode("v-if", true),
          createElementVNode("div", _hoisted_57, [
            createElementVNode("button", {
              type: "button",
              class: "qb-add-btn",
              "data-testid": "signoz-qb-add-query",
              onClick: _cache[2] || (_cache[2] = ($event) => commit({ type: "addQuery", opts: clock2 }))
            }, [
              createElementVNode("span", _hoisted_58, [
                createVNode(unref(GIcon), {
                  name: "plus",
                  size: 14
                }),
                createElementVNode(
                  "span",
                  _hoisted_59,
                  toDisplayString(unref(t)("signoz.traces.addQuery")),
                  1
                  /* TEXT */
                )
              ])
            ]),
            !display.value.simple ? (openBlock(), createElementBlock("button", {
              key: 0,
              type: "button",
              class: "qb-add-btn",
              "data-testid": "signoz-qb-add-formula",
              onClick: _cache[3] || (_cache[3] = ($event) => commit({ type: "addFormula", opts: clock2 }))
            }, [
              createElementVNode("span", _hoisted_60, [
                createVNode(unref(GIcon), {
                  name: "function",
                  size: 14
                }),
                createElementVNode(
                  "span",
                  _hoisted_61,
                  toDisplayString(unref(t)("signoz.queryBuilder.addFormula")),
                  1
                  /* TEXT */
                )
              ])
            ])) : createCommentVNode("v-if", true)
          ])
        ]),
        showNavigator() ? (openBlock(), createElementBlock("div", _hoisted_62, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(state2.value.queries, (q) => {
              return openBlock(), createElementBlock(
                "div",
                {
                  key: "nav-q-" + q.id,
                  class: "qb-nav-item qb-nav-item--query"
                },
                toDisplayString(q.name),
                1
                /* TEXT */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(state2.value.formulas, (f) => {
              return openBlock(), createElementBlock(
                "div",
                {
                  key: "nav-f-" + f.id,
                  class: "qb-nav-item qb-nav-item--formula"
                },
                toDisplayString(f.name),
                1
                /* TEXT */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const QueryBuilder = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-75f98af1"]]);
const _hoisted_1$5 = {
  class: "signoz-query-type-tabs",
  "data-testid": "signoz-query-type-tabs",
  role: "tablist"
};
const _hoisted_2$5 = ["aria-selected", "aria-disabled", "disabled", "title", "data-testid", "onClick"];
const _hoisted_3$4 = {
  key: 0,
  class: "signoz-qtt-legacy",
  "data-testid": "signoz-legacy-mixed-warning",
  role: "status"
};
const _sfc_main$5 = /* @__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", labelKey: "signoz.queryBuilder.tabBuilder" },
      { value: "promql", labelKey: "signoz.queryBuilder.tabPromql" },
      { value: "clickhouse_sql", labelKey: "signoz.queryBuilder.tabClickhouse" }
    ];
    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$5, [
        (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] || unref(t)(tab.labelKey),
              "data-testid": tab.value === "builder" ? "signoz-mode" : `signoz-mode-${tab.value}`,
              onClick: ($event) => select(tab.value)
            }, toDisplayString(unref(t)(tab.labelKey)), 11, _hoisted_2$5);
          }),
          64
          /* STABLE_FRAGMENT */
        )),
        __props.legacyMixed ? (openBlock(), createElementBlock("p", _hoisted_3$4, " 检测到旧版混合查询模式。请选择全局模式以升级；未确认前仍使用原 schema 序列化。 ")) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const QueryTypeTabs = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-b0690e2c"]]);
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 t2 = buf.trim();
    if (t2) statements.push({ from: start, text: t2 });
    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$4 = {
  class: "raw-qe",
  "data-testid": "signoz-raw-query-editor"
};
const _hoisted_2$4 = { class: "row" };
const _hoisted_3$3 = ["id"];
const _sfc_main$4 = /* @__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$4, [
        createElementVNode("div", _hoisted_2$4, [
          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$3)) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const RawQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-5a564c32"]]);
function toWireSignal(signal) {
  const s = String(signal ?? "").trim().toLowerCase();
  if (s === "logs") return "logs";
  if (s === "metrics" || s === "") return "metrics";
  return "traces";
}
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 = toWireSignal(spec.signal);
  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
  };
}
const PERSISTED_QUERY_KEYS = [
  "id",
  "name",
  "signal",
  "where",
  "aggregations",
  "aggOp",
  "aggAttr",
  "metricName",
  "metricType",
  "timeAggregation",
  "spaceAggregation",
  "groupBy",
  "having",
  "orderBy",
  "limit",
  "legend",
  "step",
  "disabled",
  "spanScope",
  "expression",
  "functions",
  "_addOns"
];
const PERSISTED_FORMULA_KEYS = [
  "id",
  "name",
  "expression",
  "legend",
  "having",
  "orderBy",
  "limit",
  "disabled",
  "_addOns"
];
const RUNTIME_EPHEMERAL = /* @__PURE__ */ new Set([
  "_collapsed",
  "_keyOpts",
  "_keysLoading",
  "_metricOpts",
  "_metricLoading"
]);
function cloneValue(value) {
  if (value == null || typeof value !== "object") return value;
  if (typeof structuredClone === "function") {
    try {
      return structuredClone(value);
    } catch {
    }
  }
  if (Array.isArray(value)) {
    return value.map((v) => cloneValue(v));
  }
  const out = {};
  for (const [k, v] of Object.entries(value)) {
    out[k] = cloneValue(v);
  }
  return out;
}
function unknownSiblings(source, known) {
  const knownSet = new Set(known);
  const out = {};
  for (const [k, v] of Object.entries(source)) {
    if (knownSet.has(k)) continue;
    if (RUNTIME_EPHEMERAL.has(k)) continue;
    out[k] = cloneValue(v);
  }
  return out;
}
function parseOrderByString(orderBy) {
  const raw = String(orderBy ?? "").trim();
  if (!raw) return [];
  const space = raw.match(/^(.+?)\s+(asc|desc)$/i);
  if (space) {
    return [
      {
        key: { name: space[1].trim() },
        direction: space[2].toLowerCase()
      }
    ];
  }
  const colon = raw.indexOf(":");
  if (colon > 0) {
    const name = raw.slice(0, colon).trim();
    const dir = raw.slice(colon + 1).trim().toLowerCase();
    return [
      {
        key: { name },
        direction: dir === "asc" ? "asc" : "desc"
      }
    ];
  }
  return [{ key: { name: raw }, direction: "desc" }];
}
function formatOrderByString(order, style = "query") {
  if (!order?.length) return style === "query" ? "timestamp:desc" : "";
  const first = order[0];
  const name = String(first?.key?.name ?? "").trim();
  if (!name) return style === "query" ? "timestamp:desc" : "";
  const dir = String(first?.direction ?? "desc").toLowerCase() === "asc" ? "asc" : "desc";
  if (style === "formula") return `${name} ${dir}`;
  if (name === "timestamp" || name === "value" || name.includes(".")) {
    return `${name}:${dir}`;
  }
  if (name.includes("(") || name.includes(" ")) return `${name} ${dir}`;
  return `${name}:${dir}`;
}
function parseAggregationExpressions(aggStr) {
  if (!aggStr?.trim()) return ["count()"];
  const re = /\b([a-z_]\w*)\s*\(([^)]*)\)/gi;
  const results = [];
  let m;
  while ((m = re.exec(aggStr)) !== null) {
    results.push(m[0].trim());
  }
  return results.length ? results : ["count()"];
}
function groupByToFields(groupBy) {
  return groupBy.map((name) => ({
    name,
    fieldDataType: "string",
    fieldContext: "tag"
  }));
}
function fieldsToGroupBy(fields) {
  if (!Array.isArray(fields)) return [];
  return fields.map((f) => {
    if (typeof f === "string") return f;
    return String(f.name ?? f.key ?? "").trim();
  }).filter(Boolean);
}
function functionsToSpec(fns) {
  return fns.map((f) => {
    const name = String(f.name || "");
    const arg = f.arg != null ? String(f.arg) : "";
    const knownArgNames = normalizeFunctionArgs(name, arg ? [arg] : []);
    const base = {
      name,
      args: knownArgNames.length ? knownArgNames : arg ? [{ name: "value", value: arg }] : []
    };
    const extras = unknownSiblings(f, ["name", "arg"]);
    if (Object.keys(extras).length) {
      return { ...base, ...extras };
    }
    return base;
  });
}
function functionsFromSpec(fns) {
  if (!Array.isArray(fns)) return [];
  return fns.map((f) => {
    const name = String(f.name || "");
    const args = Array.isArray(f.args) ? f.args : [];
    const first = args[0];
    const arg = first == null ? "" : typeof first === "object" ? String(first.value ?? "") : String(first);
    const extras = unknownSiblings(f, ["name", "args"]);
    return { name, arg, ...extras };
  });
}
function isMetricsSignal(signal) {
  return String(signal).toLowerCase() === "metrics";
}
function toPersistedSignal(signal) {
  return String(signal || "traces");
}
function toStructuredSignal(signal) {
  return toWireSignal(signal);
}
function runtimeQueryToPersisted(q) {
  const src = q;
  const functions = Array.isArray(q.functions) ? q.functions.map((f) => {
    const row = {
      name: String(f.name || ""),
      arg: f.arg != null ? String(f.arg) : ""
    };
    const extras = unknownSiblings(f, ["name", "arg"]);
    return { ...row, ...extras };
  }) : [];
  const base = {
    id: q.id,
    name: q.name,
    signal: toPersistedSignal(String(q.signal || "traces")),
    where: q.where ?? "",
    aggregations: q.aggregations ?? "count()",
    aggOp: q.aggOp ?? "count",
    aggAttr: q.aggAttr ?? "",
    metricName: q.metricName ?? "",
    metricType: q.metricType ?? "",
    timeAggregation: q.timeAggregation ?? "rate",
    spaceAggregation: q.spaceAggregation ?? "sum",
    groupBy: Array.isArray(q.groupBy) ? q.groupBy.map(String) : [],
    having: q.having ?? "",
    orderBy: q.orderBy ?? "timestamp:desc",
    limit: typeof q.limit === "number" ? q.limit : 100,
    legend: q.legend ?? "",
    step: q.step === void 0 ? 60 : q.step,
    disabled: Boolean(q.disabled),
    spanScope: q.spanScope ?? "all_spans",
    expression: q.expression ?? "",
    functions,
    _addOns: Array.isArray(q._addOns) ? q._addOns.map(String) : []
  };
  return {
    ...base,
    ...unknownSiblings(src, PERSISTED_QUERY_KEYS)
  };
}
function runtimeFormulaToPersisted(f) {
  const src = f;
  const base = {
    id: f.id,
    name: f.name,
    expression: f.expression ?? "",
    legend: f.legend ?? "",
    having: f.having ?? "",
    orderBy: f.orderBy ?? "",
    limit: typeof f.limit === "number" ? f.limit : 100,
    disabled: Boolean(f.disabled),
    _addOns: Array.isArray(f._addOns) ? f._addOns.map(String) : []
  };
  return {
    ...base,
    ...unknownSiblings(src, PERSISTED_FORMULA_KEYS)
  };
}
function runtimeToPersisted(state2) {
  return {
    queries: state2.queries.map(runtimeQueryToPersisted),
    formulas: state2.formulas.map(runtimeFormulaToPersisted)
  };
}
function persistedQueryToRuntime(p, opts) {
  const name = String(p.name || "A");
  const base = makeQuery(name, opts);
  const src = p;
  const functions = Array.isArray(p.functions) ? p.functions.map((f) => ({
    name: String(f.name || ""),
    arg: f.arg != null ? String(f.arg) : "",
    ...unknownSiblings(f, ["name", "arg"])
  })) : base.functions;
  const next = {
    ...base,
    id: p.id != null ? String(p.id) : base.id,
    name,
    signal: toPersistedSignal(String(p.signal || base.signal)) || "traces",
    where: p.where != null ? String(p.where) : base.where,
    aggregations: p.aggregations != null ? String(p.aggregations) : base.aggregations,
    aggOp: p.aggOp != null ? String(p.aggOp) : base.aggOp,
    aggAttr: p.aggAttr != null ? String(p.aggAttr) : base.aggAttr,
    metricName: p.metricName != null ? String(p.metricName) : base.metricName,
    metricType: p.metricType != null ? String(p.metricType) : base.metricType,
    timeAggregation: p.timeAggregation != null ? String(p.timeAggregation) : base.timeAggregation,
    spaceAggregation: p.spaceAggregation != null ? String(p.spaceAggregation) : base.spaceAggregation,
    groupBy: Array.isArray(p.groupBy) ? p.groupBy.map(String) : base.groupBy,
    having: p.having != null ? String(p.having) : base.having,
    orderBy: p.orderBy != null ? String(p.orderBy) : base.orderBy,
    limit: typeof p.limit === "number" ? p.limit : base.limit,
    legend: p.legend != null ? String(p.legend) : base.legend,
    step: p.step === null ? null : typeof p.step === "number" ? p.step : base.step,
    disabled: p.disabled != null ? Boolean(p.disabled) : base.disabled,
    spanScope: p.spanScope != null ? String(p.spanScope) : base.spanScope,
    expression: p.expression != null ? String(p.expression) : base.expression,
    functions,
    _addOns: Array.isArray(p._addOns) ? p._addOns.map(String) : base._addOns,
    // ephemeral always reset on hydrate
    _collapsed: false,
    _keyOpts: [],
    _keysLoading: false,
    _metricOpts: [],
    _metricLoading: false,
    ...unknownSiblings(src, [
      ...PERSISTED_QUERY_KEYS,
      ...RUNTIME_EPHEMERAL
    ])
  };
  return next;
}
function persistedFormulaToRuntime(p, opts) {
  const name = String(p.name || "F1");
  const base = makeFormula(name, opts);
  const src = p;
  return {
    ...base,
    id: p.id != null ? String(p.id) : base.id,
    name,
    expression: p.expression != null ? String(p.expression) : base.expression,
    legend: p.legend != null ? String(p.legend) : base.legend,
    having: p.having != null ? String(p.having) : base.having,
    orderBy: p.orderBy != null ? String(p.orderBy) : base.orderBy,
    limit: typeof p.limit === "number" ? p.limit : base.limit,
    disabled: p.disabled != null ? Boolean(p.disabled) : base.disabled,
    _addOns: Array.isArray(p._addOns) ? p._addOns.map(String) : base._addOns,
    _collapsed: false,
    ...unknownSiblings(src, [
      ...PERSISTED_FORMULA_KEYS,
      "_collapsed"
    ])
  };
}
function persistedToRuntime(persisted, opts) {
  const queries = (persisted.queries?.length ? persisted.queries : [runtimeQueryToPersisted(makeQuery("A", opts))]).map((q) => persistedQueryToRuntime(q, opts));
  const formulas = (persisted.formulas || []).map(
    (f) => persistedFormulaToRuntime(f, opts)
  );
  return { queries, formulas };
}
function runtimeQueryToBuilderSpec(q) {
  const signal = toStructuredSignal(String(q.signal || "traces"));
  const stepInterval = q.step === null || q.step === null ? null : typeof q.step === "number" ? q.step : 60;
  let aggregations;
  if (isMetricsSignal(String(q.signal))) {
    aggregations = [
      {
        kind: "metric",
        metricName: q.metricName || "",
        timeAggregation: q.timeAggregation || "rate",
        spaceAggregation: q.spaceAggregation || "sum",
        ...q.metricType ? { metricType: q.metricType } : {}
      }
    ];
  } else {
    const exprs = parseAggregationExpressions(q.aggregations || "count()");
    aggregations = exprs.map((expression) => ({
      kind: "expression",
      expression
    }));
  }
  const base = defaultBuilderSpec(q.name || "A", signal);
  const spec = {
    ...base,
    name: q.name || "A",
    signal,
    stepInterval,
    disabled: Boolean(q.disabled),
    filter: { expression: q.where ?? "" },
    having: { expression: q.having ?? "" },
    groupBy: groupByToFields(Array.isArray(q.groupBy) ? q.groupBy : []),
    order: parseOrderByString(q.orderBy),
    limit: typeof q.limit === "number" ? q.limit : 100,
    legend: q.legend ?? "",
    functions: functionsToSpec(
      Array.isArray(q.functions) ? q.functions : []
    ),
    aggregations
  };
  const extras = unknownSiblings(q, [
    ...PERSISTED_QUERY_KEYS,
    ...RUNTIME_EPHEMERAL,
    "id"
  ]);
  for (const k of Object.keys(extras)) {
    if (k.startsWith("_")) delete extras[k];
  }
  return Object.keys(extras).length ? { ...spec, ...extras } : spec;
}
function runtimeFormulaToFormulaSpec(f) {
  const order = parseOrderByString(f.orderBy);
  return {
    name: f.name || "F1",
    expression: f.expression ?? "",
    disabled: Boolean(f.disabled),
    legend: f.legend ?? "",
    order: order.length ? order : [],
    ...typeof f.limit === "number" ? { limit: f.limit } : {}
  };
}
function builderSpecToRuntimeQuery(spec, opts) {
  const ui = {};
  const name = String(ui.name || spec.name || "A");
  const base = makeQuery(name, opts);
  const signalFromUi = ui.signal != null ? String(ui.signal) : "";
  const signal = signalFromUi || spec.signal || "traces";
  const aggs = Array.isArray(spec.aggregations) ? spec.aggregations : [];
  let aggregations = base.aggregations;
  let metricName = base.metricName;
  let metricType = ui.metricType != null ? String(ui.metricType) : base.metricType;
  let timeAggregation = base.timeAggregation;
  let spaceAggregation = base.spaceAggregation;
  let aggOp = base.aggOp;
  let aggAttr = base.aggAttr;
  if (isMetricsSignal(String(signal))) {
    const m = aggs.find((a) => a.kind === "metric" || a.metricName != null);
    if (m) {
      metricName = String(m.metricName ?? metricName);
      timeAggregation = String(m.timeAggregation ?? timeAggregation);
      spaceAggregation = String(m.spaceAggregation ?? spaceAggregation);
      if (m.metricType != null) metricType = String(m.metricType);
    }
  } else {
    const exprs = aggs.map((a) => {
      if (a.kind === "expression" || a.expression != null) {
        return String(a.expression || "");
      }
      return "";
    }).filter(Boolean);
    aggregations = exprs.length ? exprs.join(" ") : "count()";
  }
  if (ui.aggregations != null) aggregations = String(ui.aggregations);
  if (ui.metricName != null) metricName = String(ui.metricName);
  if (ui.timeAggregation != null) timeAggregation = String(ui.timeAggregation);
  if (ui.spaceAggregation != null) spaceAggregation = String(ui.spaceAggregation);
  if (ui.aggOp != null) aggOp = String(ui.aggOp);
  if (ui.aggAttr != null) aggAttr = String(ui.aggAttr);
  const step = ui.step !== void 0 ? ui.step : spec.stepInterval === null ? null : typeof spec.stepInterval === "number" ? spec.stepInterval : base.step;
  const next = {
    ...base,
    id: ui.id != null ? String(ui.id) : base.id,
    name,
    signal,
    where: ui.where != null ? String(ui.where) : spec.filter?.expression != null ? String(spec.filter.expression) : base.where,
    aggregations,
    aggOp,
    aggAttr,
    metricName,
    metricType,
    timeAggregation,
    spaceAggregation,
    groupBy: ui.groupBy != null ? ui.groupBy.map(String) : fieldsToGroupBy(spec.groupBy),
    having: ui.having != null ? String(ui.having) : spec.having?.expression != null ? String(spec.having.expression) : base.having,
    orderBy: ui.orderBy != null ? String(ui.orderBy) : formatOrderByString(spec.order, "query"),
    limit: typeof ui.limit === "number" ? ui.limit : typeof spec.limit === "number" ? spec.limit : base.limit,
    legend: ui.legend != null ? String(ui.legend) : spec.legend != null ? String(spec.legend) : base.legend,
    step,
    disabled: ui.disabled != null ? Boolean(ui.disabled) : Boolean(spec.disabled),
    spanScope: ui.spanScope != null ? String(ui.spanScope) : base.spanScope,
    expression: ui.expression != null ? String(ui.expression) : base.expression,
    functions: ui.functions != null ? ui.functions : functionsFromSpec(spec.functions),
    _addOns: Array.isArray(ui._addOns) ? ui._addOns.map(String) : base._addOns,
    _collapsed: false,
    _keyOpts: [],
    _keysLoading: false,
    _metricOpts: [],
    _metricLoading: false
  };
  const knownSpec = /* @__PURE__ */ new Set([
    "name",
    "signal",
    "source",
    "stepInterval",
    "tags",
    "disabled",
    "filter",
    "having",
    "groupBy",
    "order",
    "limit",
    "legend",
    "functions",
    "aggregations",
    "environment",
    "service",
    "operation",
    "duration",
    "selectFields",
    "limitBy",
    "offset",
    "cursor",
    "secondaryAggregations"
  ]);
  for (const [k, v] of Object.entries(spec)) {
    if (knownSpec.has(k)) continue;
    if (k in next) continue;
    next[k] = cloneValue(v);
  }
  return next;
}
function formulaSpecToRuntimeFormula(spec, opts) {
  const ui = {};
  const name = String(ui.name || spec.name || "F1");
  const base = makeFormula(name, opts);
  return {
    ...base,
    id: ui.id != null ? String(ui.id) : base.id,
    name,
    expression: ui.expression != null ? String(ui.expression) : String(spec.expression ?? ""),
    legend: ui.legend != null ? String(ui.legend) : String(spec.legend ?? ""),
    having: ui.having != null ? String(ui.having) : base.having,
    orderBy: ui.orderBy != null ? String(ui.orderBy) : formatOrderByString(spec.order, "formula"),
    limit: typeof ui.limit === "number" ? ui.limit : typeof spec.limit === "number" ? spec.limit : base.limit,
    disabled: ui.disabled != null ? Boolean(ui.disabled) : Boolean(spec.disabled),
    _addOns: Array.isArray(ui._addOns) ? ui._addOns.map(String) : base._addOns,
    _collapsed: false
  };
}
function runtimeToSigNozQuery(state2, base = {}) {
  const persisted = runtimeToPersisted(state2);
  const builderQueries = state2.queries.map(runtimeQueryToBuilderSpec);
  const builderFormulas = state2.formulas.map(runtimeFormulaToFormulaSpec);
  const queries = [
    ...builderQueries.map((spec, i) => {
      const item = {
        type: "builder_query",
        queryType: "builder",
        spec,
        queryBuilder: persisted.queries[i]
      };
      return item;
    }),
    ...builderFormulas.map((spec, i) => {
      const item = {
        type: "builder_formula",
        spec,
        queryBuilder: persisted.formulas[i]
      };
      return item;
    })
  ];
  const hostUnknown = unknownSiblings(base, [
    "refId",
    "schema",
    "apiProfile",
    "queries",
    "editor",
    "requestType",
    "noCache",
    "formatOptions",
    "signal",
    "expr",
    "query",
    "service",
    "operation",
    "formula",
    "legendFormat",
    "limit",
    "hide",
    "datasource",
    "key"
  ]);
  const editor = {
    activeQueryType: "builder",
    builder: {
      queries: builderQueries.map(cloneValue),
      formulas: builderFormulas.map(cloneValue),
      traceOperators: []
    },
    promql: [],
    clickhouseSql: [],
    queryBuilder: persisted
  };
  if (base.editor && typeof base.editor === "object") {
    const prev = base.editor;
    for (const [k, v] of Object.entries(prev)) {
      if (k === "queryBuilder" || k === "builder" || k === "activeQueryType") continue;
      if (k === "promql" || k === "clickhouseSql") continue;
      if (!(k in editor)) editor[k] = cloneValue(v);
    }
  }
  const out = {
    refId: base.refId || "A",
    schema: 2,
    apiProfile: base.apiProfile || "signoz-v5",
    requestType: base.requestType || "time_series",
    ...hostUnknown,
    ...base,
    queries,
    editor
  };
  return out;
}
function readPersistedFromQuery(query) {
  const editor = query?.editor;
  if (editor?.queryBuilder?.queries?.length) {
    return cloneValue(editor.queryBuilder);
  }
  return null;
}
function sigNozQueryToRuntime(query, opts) {
  const diagnostics = [];
  if (!query) {
    return { state: createInitialState(opts), diagnostics };
  }
  const bag = readPersistedFromQuery(query);
  if (bag) {
    return { state: persistedToRuntime(bag, opts), diagnostics };
  }
  const items = Array.isArray(query.queries) ? query.queries : [];
  const uiQueries = [];
  const uiFormulas = [];
  for (const item of items) {
    const qb = item.queryBuilder;
    if (item.type === "builder_formula") {
      if (qb && typeof qb === "object") {
        uiFormulas.push(qb);
      } else {
        uiFormulas.push(
          runtimeFormulaToPersisted(
            formulaSpecToRuntimeFormula(item.spec, opts)
          )
        );
      }
      continue;
    }
    if (item.type === "builder_trace_operator") {
      diagnostics.push({
        code: "TRACE_OPERATOR_AS_EXPRESSION",
        message: "trace operator mapped to formula-less expression field",
        path: `queries.${item.spec?.name}`
      });
      continue;
    }
    if (item.type !== "builder_query") {
      diagnostics.push({
        code: "UNKNOWN_QUERY_ITEM",
        message: `unknown query item type ${item.type}`,
        path: `queries`
      });
      continue;
    }
    if (item.queryType && item.queryType !== "builder") {
      diagnostics.push({
        code: "NON_BUILDER_MODE",
        message: `item queryType=${item.queryType} is not QueryBuilder UI state`,
        path: `queries.${item.spec?.name}`
      });
      continue;
    }
    if (qb && typeof qb === "object") {
      uiQueries.push(qb);
    } else {
      uiQueries.push(
        runtimeQueryToPersisted(
          builderSpecToRuntimeQuery(item.spec, opts)
        )
      );
    }
  }
  if (uiQueries.length || uiFormulas.length) {
    return {
      state: persistedToRuntime(
        {
          queries: uiQueries.length ? uiQueries : [runtimeQueryToPersisted(makeQuery("A", opts))],
          formulas: uiFormulas
        },
        opts
      ),
      diagnostics
    };
  }
  const editor = query.editor;
  if (editor?.builder?.queries?.length) {
    const state2 = {
      queries: editor.builder.queries.map(
        (spec) => builderSpecToRuntimeQuery(spec, opts)
      ),
      formulas: (editor.builder.formulas || []).map(
        (spec) => formulaSpecToRuntimeFormula(spec, opts)
      )
    };
    return { state: state2, diagnostics };
  }
  if (!items.length) {
    return { state: createInitialState(opts), diagnostics };
  }
  return { state: createInitialState(opts), diagnostics };
}
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 = {
  key: 2,
  class: "signoz-raw-channel",
  "data-testid": "signoz-raw-channel"
};
const _hoisted_6$2 = {
  class: "qb-name",
  "data-testid": "signoz-row-name"
};
const _hoisted_7$2 = { class: "qb-footer" };
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    datasourceApi: {}
  },
  emits: ["type-change", "change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = computed(() => migrateSigNozQuery(props.query || {}));
    const editorState = computed(() => toEditorState(query.value));
    const builderRuntime = computed(() => {
      return sigNozQueryToRuntime(query.value).state;
    });
    function onBuilderChange(queries, formulas) {
      const base = props.query;
      const converted = runtimeToSigNozQuery(
        { queries, formulas },
        {
          ...query.value,
          refId: base?.refId ?? query.value.refId,
          datasource: base?.datasource ?? query.value.datasource,
          hide: base?.hide ?? query.value.hide,
          requestType: query.value.requestType,
          apiProfile: query.value.apiProfile || jsonData.value.apiProfile
        }
      );
      const next = {
        ...query.value,
        ...converted,
        refId: base?.refId ?? query.value.refId,
        datasource: base?.datasource ?? query.value.datasource,
        hide: base?.hide ?? query.value.hide
      };
      notifyChange(next);
    }
    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((t2) => ({ label: t2, value: t2 }))
    );
    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;
      }
      notifyChange(next);
    }
    function notifyChange(next) {
      props.onChange(next);
      emit("change", 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;
      }
      notifyChange(wire);
    }
    function setGlobalMode(mode2) {
      if (modeBlocked.value[mode2]) return;
      emit("type-change", mode2);
      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 updateRawAt(index2, value) {
      const st = {
        ...editorState.value,
        promql: editorState.value.promql.map((r) => ({ ...r })),
        clickhouseSql: editorState.value.clickhouseSql.map((r) => ({ ...r }))
      };
      if (globalMode.value === "promql") {
        if (!st.promql[index2]) return;
        st.promql[index2] = { ...st.promql[index2], query: value };
      } else {
        if (!st.clickhouseSql[index2]) return;
        st.clickhouseSql[index2] = { ...st.clickhouseSql[index2], query: value };
      }
      commitEditor(st);
    }
    function addQuery2() {
      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 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]);
    }
    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 */
        )),
        createCommentVNode(" Builder: Argus QueryBuilder (Task 9). Raw modes keep GCodeEditor. "),
        globalMode.value === "builder" ? (openBlock(), createBlock(QueryBuilder, {
          key: 1,
          "model-value": builderRuntime.value,
          "show-agg": true,
          "datasource-api": metaApi.value,
          onChange: onBuilderChange,
          onRun: _cache[0] || (_cache[0] = ($event) => props.onRunQuery?.())
        }, null, 8, ["model-value", "datasource-api"])) : (openBlock(), createElementBlock("div", _hoisted_5$2, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(globalMode.value === "promql" ? editorState.value.promql : editorState.value.clickhouseSql, (raw, ri) => {
              return openBlock(), createElementBlock("div", {
                key: raw.name + "-" + ri,
                class: "signoz-raw-row"
              }, [
                createElementVNode(
                  "span",
                  _hoisted_6$2,
                  toDisplayString(raw.name),
                  1
                  /* TEXT */
                ),
                createVNode(RawQueryEditor, {
                  "model-value": raw.query,
                  mode: globalMode.value,
                  "test-id": "signoz-raw-editor",
                  "onUpdate:modelValue": ($event) => updateRawAt(ri, String($event ?? ""))
                }, null, 8, ["model-value", "mode", "onUpdate:modelValue"])
              ]);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])),
        createElementVNode("div", _hoisted_7$2, [
          globalMode.value !== "builder" ? (openBlock(), createElementBlock("button", {
            key: 0,
            type: "button",
            class: "qb-add-btn",
            "data-testid": "signoz-add-query",
            onClick: addQuery2
          }, " + 添加查询 ")) : 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-e38b3f35"]]);
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 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 evalExpr = compileArithmetic(expression);
    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(evalExpr(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 evalExpr = compileArithmetic(expression);
  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(evalExpr(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
      }
    ]
  });
}
const FORMULA_COMPILE_CACHE = /* @__PURE__ */ new Map();
const FORMULA_COMPILE_CACHE_MAX = 64;
function compileArithmetic(expr) {
  const hit = FORMULA_COMPILE_CACHE.get(expr);
  if (hit) return hit;
  const tokens = expr.match(
    /[A-Z][A-Z0-9_]*|\d+(\.\d+)?|<=|>=|==|!=|<|>|[+\-*/()]/g
  );
  if (!tokens) throw new Error("empty");
  const compiled = (env) => {
    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 t2 = next();
      if (t2 === "(") {
        const v2 = parseComparison();
        if (next() !== ")") throw new Error("paren");
        return v2;
      }
      if (t2 === "-") return -parseFactor();
      if (/^\d/.test(t2)) return Number(t2);
      if (env[t2] == null) throw new Error(`unknown ${t2}`);
      return env[t2];
    }
    const v = parseComparison();
    if (i !== tokens.length) throw new Error("trailing");
    return v;
  };
  if (FORMULA_COMPILE_CACHE.size >= FORMULA_COMPILE_CACHE_MAX) {
    const first = FORMULA_COMPILE_CACHE.keys().next().value;
    if (first != null) FORMULA_COMPILE_CACHE.delete(first);
  }
  FORMULA_COMPILE_CACHE.set(expr, compiled);
  return compiled;
}
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(t2) {
  const s = t2.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 n = rows.length;
    const colValues = {};
    for (const k of keys) colValues[k] = new Array(n);
    for (let ri = 0; ri < n; ri++) {
      const row = rows[ri];
      const o = row && typeof row === "object" ? row : {};
      for (const k of keys) {
        const arr = colValues[k];
        if (k.startsWith("data.")) {
          arr[ri] = o.data ? o.data[k.slice(5)] : null;
        } else {
          arr[ri] = 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(t2) {
  if (t2.status != null && String(t2.status).trim() !== "") {
    return normalizeStatus(t2.status);
  }
  const errCount = Number(t2.errorCount ?? 0);
  if (Number.isFinite(errCount) && errCount > 0) return "error";
  if (t2.hasError === true || t2.hasError === 1 || t2.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 unwrapSearchRow(raw) {
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
  const obj = raw;
  if (obj.data && typeof obj.data === "object" && !Array.isArray(obj.data)) {
    const data = obj.data;
    const { data: _drop, ...rest } = obj;
    return { ...data, ...rest };
  }
  return { ...obj };
}
function normalizeSearchRow(raw) {
  const t2 = unwrapSearchRow(raw);
  const durationNs = toDurationNs({
    durationNano: t2.durationNano,
    duration_nano: t2.duration_nano,
    durationNs: t2.durationNs,
    durationMs: t2.durationMs ?? t2.duration,
    duration: t2.durationNano ?? t2.duration_nano ?? t2.duration
  });
  let ns = durationNs;
  if (t2.durationNano != null || t2.duration_nano != null) {
    const v = t2.durationNano ?? t2.duration_nano;
    ns = typeof v === "bigint" ? v.toString() : String(v);
  }
  return {
    traceId: pickString(t2.traceId, t2.traceID, t2.trace_id),
    serviceName: pickString(
      t2.rootServiceName,
      t2.serviceName,
      t2.service,
      t2.rootService,
      t2["service.name"],
      t2.resource?.["service.name"],
      t2.resource?.service?.name
    ),
    operationName: pickString(
      t2.rootTraceName,
      t2.name,
      t2.operationName,
      t2.operation
    ),
    durationNs: ns,
    durationMs: toDurationMsFromNs(ns),
    spanCount: Number(t2.spanCount ?? t2.span_count ?? 0) || 0,
    status: statusFor({
      status: t2.status,
      errorCount: t2.errorCount ?? t2.error_count,
      hasError: t2.hasError
    }),
    startTimeMs: toStartTimeMs(t2)
  };
}
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)) {
      for (const item of r) rows.push(unwrapSearchRow(item));
      continue;
    }
    if (typeof r !== "object") continue;
    const obj = r;
    const list = obj.list ?? obj.traces ?? obj.rows;
    if (Array.isArray(list)) {
      for (const item of list) rows.push(unwrapSearchRow(item));
    } else if (obj.traceId || obj.traceID || obj.trace_id || obj.data && typeof obj.data === "object" && (obj.data.traceId || obj.data.traceID || obj.data.trace_id)) {
      rows.push(unwrapSearchRow(obj));
    }
  }
  return rows;
}
function isTraceSearchResult(result) {
  if (result == null) return false;
  if (Array.isArray(result)) {
    return result.some((item) => isTraceSearchResult(item));
  }
  if (typeof result !== "object") return false;
  const obj = result;
  if (Array.isArray(obj.list) || Array.isArray(obj.traces)) return true;
  if (Array.isArray(obj.spans) && obj.spans.length) return false;
  if (Array.isArray(obj.rows)) {
    if (!obj.rows.length) return true;
    const sample = unwrapSearchRow(obj.rows[0]);
    return Boolean(
      sample.traceId || sample.traceID || sample.trace_id || sample.spanCount != null || sample.span_count != null || sample["service.name"] != null || sample.rootServiceName != null || sample.rootTraceName != null
    );
  }
  return Boolean(obj.traceId || obj.traceID || obj.trace_id);
}
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 t2 = Number(p?.timestamp ?? p?.[0] ?? 0);
          return t2 > 0 && t2 < 1e12 ? t2 * 1e3 : t2;
        });
        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 t22 = Number(p[0]);
    return t22 > 0 && t22 < 1e12 ? t22 * 1e3 : t22;
  }
  const t2 = Number(p?.timestamp ?? p?.ts ?? p?.time ?? 0);
  return t2 > 0 && t2 < 1e12 ? t2 * 1e3 : t2;
}
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 === "argus-v5" || 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 = isV5WireProfile(profileId);
  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) {
    const looksLikeSearch = !envelope.results.length || envelope.results.some(
      (r) => isTraceSearchResult(r) || Array.isArray(r?.list) || Array.isArray(r?.traces) || Array.isArray(r?.rows)
    );
    const looksLikeDetail = envelope.results.some(
      (r) => Array.isArray(r?.spans) && r.spans.length
    );
    if (looksLikeSearch && !looksLikeDetail) {
      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 ttlMs2 = 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 value = await cache.getOrLoad(key, ttlMs2, loader);
    if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
    return value;
  }
  function endpointOrThrow(kind2, label) {
    const ep = profile.endpoints[kind2] || (kind2 === "metricsList" ? profile.endpoints.metadata : void 0) || (kind2 === "fieldsKeys" ? profile.endpoints.attributeKeys : void 0) || (kind2 === "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 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 = toWireSignal(item.spec.signal);
    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 (isV5WireProfile(profile.id)) {
    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 = {};
    if (profile.id !== "argus-v5") {
      variables.SIGNOZ_START = { value: String(fromMs) };
      variables.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,
        // Whitelist only — never spread editor/queryBuilder bags onto wire.
        queries: group.map(
          (g) => toTypeSpecItem(g, metricMetadata, requestType)
        )
      } : 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 buildRequestNodes(built) {
  const nodes = built.map((req, index2) => {
    if (req.localFormula) {
      return {
        index: index2,
        kind: "formula",
        req,
        produces: [req.localFormula.name, ...req.queryNames],
        dependsOn: [...req.localFormula.dependsOn || []]
      };
    }
    return {
      index: index2,
      kind: "network",
      req,
      produces: [...req.queryNames],
      dependsOn: []
    };
  });
  const produced = /* @__PURE__ */ new Set();
  for (const n of nodes) for (const p of n.produces) produced.add(p);
  const diagnostics = { cycles: [], missingDeps: [] };
  for (const n of nodes) {
    if (n.kind !== "formula") continue;
    const missing = n.dependsOn.filter((d) => !produced.has(d));
    if (missing.length) {
      diagnostics.missingDeps.push({
        formula: n.req.localFormula?.name || n.req.requestKey,
        missing
      });
    }
  }
  const byName = /* @__PURE__ */ new Map();
  for (const n of nodes) {
    for (const p of n.produces) byName.set(p, n);
  }
  const visiting = /* @__PURE__ */ new Set();
  const visited = /* @__PURE__ */ new Set();
  function dfs(name, stack) {
    if (visiting.has(name)) {
      diagnostics.cycles.push([...stack, name].join("→"));
      return;
    }
    if (visited.has(name)) return;
    visiting.add(name);
    const node = byName.get(name);
    if (node) {
      for (const d of node.dependsOn) dfs(d, [...stack, name]);
    }
    visiting.delete(name);
    visited.add(name);
  }
  for (const n of nodes) {
    for (const p of n.produces) dfs(p, []);
  }
  return { nodes, diagnostics };
}
function assertScheduleValid(diagnostics) {
  if (diagnostics.cycles.length) {
    throw new DataSourceError(
      "INVALID_QUERY",
      `formula 依赖成环: ${diagnostics.cycles[0]}`
    );
  }
  if (diagnostics.missingDeps.length) {
    const m = diagnostics.missingDeps[0];
    throw new DataSourceError(
      "INVALID_QUERY",
      `formula ${m.formula} 缺少依赖: ${m.missing.join(", ")}`
    );
  }
}
async function runRequestNodes(opts) {
  const { nodes, maxConcurrent, signal, runNode, onPartialOrdered } = opts;
  const n = nodes.length;
  const results = new Array(n);
  const done = new Array(n).fill(false);
  const completedNames = /* @__PURE__ */ new Set();
  let inFlight = 0;
  let finished = 0;
  function depsReady(node) {
    return node.dependsOn.every((d) => completedNames.has(d));
  }
  function emitPartial() {
    if (!onPartialOrdered) return;
    const ordered = [];
    for (let i = 0; i < n; i++) {
      if (!done[i] || results[i] === void 0) continue;
      ordered.push({ index: i, value: results[i] });
    }
    onPartialOrdered(ordered);
  }
  return new Promise((resolve, reject) => {
    let settled = false;
    const fail = (err) => {
      if (settled) return;
      settled = true;
      reject(err);
    };
    const succeed = () => {
      if (settled) return;
      settled = true;
      resolve(results);
    };
    const onAbort = () => {
      fail(new DOMException("Aborted", "AbortError"));
    };
    if (signal?.aborted) {
      onAbort();
      return;
    }
    signal?.addEventListener("abort", onAbort, { once: true });
    function pump() {
      if (settled) return;
      if (signal?.aborted) {
        onAbort();
        return;
      }
      let progressed = true;
      while (progressed) {
        progressed = false;
        for (let i = 0; i < n; i++) {
          if (done[i] || results[i] !== void 0) continue;
        }
        for (let i = 0; i < n; i++) {
          const node = nodes[i];
          if (done[i] || running.has(i)) continue;
          if (!depsReady(node)) continue;
          if (inFlight >= Math.max(1, maxConcurrent)) break;
          running.add(i);
          inFlight += 1;
          progressed = true;
          void Promise.resolve().then(() => runNode(node, signal)).then((value) => {
            if (settled || signal?.aborted) {
              inFlight -= 1;
              running.delete(i);
              if (signal?.aborted) onAbort();
              return;
            }
            results[i] = value;
            done[i] = true;
            finished += 1;
            for (const p of node.produces) completedNames.add(p);
            inFlight -= 1;
            running.delete(i);
            emitPartial();
            if (finished >= n) {
              signal?.removeEventListener("abort", onAbort);
              succeed();
              return;
            }
            pump();
          }).catch((err) => {
            inFlight -= 1;
            running.delete(i);
            signal?.removeEventListener("abort", onAbort);
            fail(err);
          });
        }
      }
      if (!settled && inFlight === 0 && finished < n) {
        const pending2 = nodes.filter((_, i) => !done[i]);
        fail(
          new DataSourceError(
            "INVALID_QUERY",
            `无法调度剩余查询节点: ${pending2.map((p) => p.req.requestKey).join(", ")}`
          )
        );
      }
    }
    const running = /* @__PURE__ */ new Set();
    if (n === 0) {
      succeed();
      return;
    }
    pump();
  });
}
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 t2 = 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(t2[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 h2 = 0;
  for (let i = 0; i < s.length; i++)
    h2 = Math.imul(31, h2) + s.charCodeAt(i) | 0;
  return (h2 >>> 0).toString(16);
}
function defaultSleep(ms, signal) {
  return new Promise((resolve, reject) => {
    if (signal.aborted) {
      reject(new DataSourceError("CANCELLED", "live tail aborted"));
      return;
    }
    const t2 = setTimeout(() => {
      signal.removeEventListener("abort", onAbort);
      resolve();
    }, ms);
    const onAbort = () => {
      clearTimeout(t2);
      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(config2) {
  const sessionId = sessionSeq++;
  const maxRows = Math.max(100, config2.maxRows ?? 5e3);
  const pollIntervalMs = Math.max(200, config2.pollIntervalMs ?? 2e3);
  const maxRetries = config2.maxRetries ?? 8;
  const sleep2 = config2.sleep || defaultSleep;
  let state2 = "idle";
  let transport = resolveLiveTailTransport(
    config2.capabilities
  );
  let controller = null;
  let rows = new Array(maxRows);
  let rowStart = 0;
  let rowCount = 0;
  const seen = /* @__PURE__ */ new Set();
  const materializeRows = () => {
    if (rowCount === 0) return [];
    const out = new Array(rowCount);
    for (let i = 0; i < rowCount; i++) {
      out[i] = rows[(rowStart + i) % maxRows];
    }
    return out;
  };
  let lastTimestamp = config2.startMs;
  let nextCursor = null;
  let retryCount = 0;
  let paused = false;
  let runToken = 0;
  const setState2 = (s, detail) => {
    state2 = s;
    config2.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;
    for (const r of fresh) {
      if (rowCount === maxRows) {
        const old = rows[rowStart];
        seen.delete(old.rowId);
        rowStart = (rowStart + 1) % maxRows;
        rowCount -= 1;
      }
      rows[(rowStart + rowCount) % maxRows] = r;
      rowCount += 1;
    }
    config2.onRows?.(fresh, { sessionId, transport });
  };
  const cancelActive = () => {
    runToken += 1;
    if (controller) {
      controller.abort();
      controller = null;
    }
  };
  async function runSse(token) {
    if (!config2.fetchStream) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "SSE live tail 需要 fetchStream（API key/Bearer 不可用 EventSource）"
      );
    }
    const path = config2.capabilities.sseVerified && config2.capabilities.liveTailPath ? config2.capabilities.liveTailPath : config2.capabilities.legacyLiveTailPath;
    const query = {
      start: String(lastTimestamp || config2.startMs),
      filter: config2.filterExpression || ""
    };
    setState2("connecting");
    const res = await config2.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 不可读");
    }
    setState2("live");
    retryCount = 0;
    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buf = "";
    while (isCurrent(token)) {
      if (paused) {
        setState2("paused");
        await sleep2(100, controller.signal);
        continue;
      }
      if (state2 === "paused") setState2("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 (!config2.fetchCursorPage) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "cursor poll 需要 fetchCursorPage"
      );
    }
    setState2("connecting");
    setState2("live");
    retryCount = 0;
    let firstPageDone = false;
    while (isCurrent(token)) {
      if (paused) {
        setState2("paused");
        await sleep2(100, controller.signal);
        continue;
      }
      if (state2 === "paused") setState2("live");
      const page = await config2.fetchCursorPage({
        cursor: nextCursor,
        startMs: lastTimestamp || config2.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(config2.capabilities);
    if (transport === "none") {
      setState2("error", "UNSUPPORTED_CAPABILITY");
      const err = new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "live tail 需要已验证 SSE 或 cursor poll capability"
      );
      config2.onError?.(err, sessionId);
      return;
    }
    while (isCurrent(token) && state2 !== "stopped") {
      try {
        if (transport === "sse") await runSse(token);
        else await runCursorPoll(token);
        if (isCurrent(token) && !paused) {
          setState2("retrying");
          retryCount += 1;
          if (retryCount > maxRetries) {
            setState2("error", "max retries");
            config2.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) {
          setState2("error", e?.message || "error");
          config2.onError?.(
            e instanceof Error ? e : new Error(String(e)),
            sessionId
          );
          return;
        }
        setState2("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 materializeRows();
    },
    async start() {
      cancelActive();
      paused = false;
      controller = new AbortController();
      void loop();
    },
    pause() {
      paused = true;
      if (state2 === "live" || state2 === "connecting") setState2("paused");
    },
    resume() {
      if (state2 === "stopped" || state2 === "idle") return;
      paused = false;
      if (state2 === "paused") setState2("live");
    },
    stop() {
      paused = false;
      cancelActive();
      setState2("stopped");
    },
    dispose() {
      paused = false;
      cancelActive();
      setState2("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 h2 = headers;
    return String(h2[name] || h2[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);
  const enc = new TextEncoder();
  let cursor = null;
  let pages = 0;
  let rows = 0;
  let complete = false;
  let truncatedByUpstream = false;
  let bytes = 0;
  let body = "";
  let csvHeaderWritten = false;
  let csvCols = null;
  let jsonStarted = false;
  let jsonFirstRow = true;
  let envelopeCount = 0;
  const appendChunk = (chunk) => {
    if (!chunk) return;
    body += chunk;
    bytes += enc.encode(chunk).byteLength;
    if (bytes > MAX_EXPORT_BYTES) {
      throw new DataSourceError(
        "INVALID_RESPONSE",
        `export 超过 size limit ${MAX_EXPORT_BYTES}`
      );
    }
  };
  const ensureJsonHeader = () => {
    if (jsonStarted) return;
    appendChunk(
      `{"exportMode":"cursor_pages","format":"json","data":[`
    );
    jsonStarted = true;
  };
  const appendJsonRows = (pageRows) => {
    ensureJsonHeader();
    for (const r of pageRows) {
      const piece = (jsonFirstRow ? "" : ",") + stableJson(redactSecrets(r));
      jsonFirstRow = false;
      appendChunk(piece);
    }
  };
  const appendCsvRowsFromObjects = (pageRows) => {
    if (!pageRows.length) return;
    if (!csvCols) {
      const keys = /* @__PURE__ */ new Set();
      for (const r of pageRows) {
        if (r && typeof r === "object")
          Object.keys(r).forEach((k) => keys.add(k));
      }
      csvCols = [...keys].sort();
      if (!csvCols.length) csvCols = ["value"];
      appendChunk(csvCols.map(csvEscape).join(",") + "\n");
      csvHeaderWritten = true;
    }
    for (const r of pageRows) {
      const o = r && typeof r === "object" ? r : { value: r };
      const line = csvCols.map((c) => {
        const v = o[c];
        if (v == null) return "";
        if (typeof v === "object") return csvEscape(stableJson(v));
        return csvEscape(String(v));
      }).join(",");
      appendChunk(line + "\n");
    }
  };
  const appendCsvFromFrames = (frames) => {
    for (const fr of frames) {
      const fields = fr.fields || [];
      if (!fields.length) continue;
      if (!csvHeaderWritten) {
        appendChunk(fields.map((f) => csvEscape(f.name)).join(",") + "\n");
        csvHeaderWritten = true;
        csvCols = fields.map((f) => f.name);
      }
      const n = fields[0]?.values?.length ?? fr.length ?? 0;
      for (let i = 0; i < n; i++) {
        const line = 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(",");
        appendChunk(line + "\n");
      }
    }
  };
  while (pages < maxPages) {
    if (args.signal?.aborted) {
      args.onProgress?.({
        mode: "cursor_pages",
        pages,
        rows,
        bytes,
        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;
    if (page.envelope !== void 0) envelopeCount += 1;
    if (args.format === "csv") {
      if (page.frames?.length) appendCsvFromFrames(page.frames);
      else appendCsvRowsFromObjects(pageRows);
    } else {
      appendJsonRows(pageRows);
    }
    args.onProgress?.({
      mode: "cursor_pages",
      pages,
      rows,
      bytes,
      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;
  if (args.format === "json") {
    ensureJsonHeader();
    appendChunk(
      `],"pages":${pages},"rowCount":${rows},"complete":${complete},"truncatedByUpstream":${truncatedByUpstream},"envelopeCount":${envelopeCount}}`
    );
  } else if (!csvHeaderWritten) {
    appendChunk("");
  }
  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 || getRuntimeDataSourceSettings(instance.uid)?.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 不会被自动发明）。请在 public/app/defaultObservabilityDataSources.json 配置 token/refreshToken，或 bootstrapGrafanaVue({ datasources }) / setRuntimeCredential，或使用 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$1(
              {
                ...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);
        const { nodes, diagnostics } = buildRequestNodes(built);
        assertScheduleValid(diagnostics);
        const maxConcurrent = Math.max(
          1,
          Number(options.maxConcurrentRequests ?? 4) || 4
        );
        const registerFrames = (req, mapped) => {
          for (const fr of mapped) {
            const key = String(
              fr.name || fr.refId || req.queryNames[0] || query.refId
            );
            pushNamed(key, fr);
            for (const n of req.queryNames) pushNamed(n, fr);
            if (req.localFormula) pushNamed(req.localFormula.name, fr);
          }
        };
        const runOne = async (node) => {
          const req = node.req;
          if (req.localFormula) {
            if (signal?.aborted) {
              throw new DOMException("Aborted", "AbortError");
            }
            const f = evaluateLocalFormula(
              req.localFormula.expression,
              framesByName,
              req.localFormula.name
            );
            registerFrames(req, [f]);
            return { frames: [f], req };
          }
          if (!req.path) return { frames: [], req };
          if (signal?.aborted) {
            throw new DOMException("Aborted", "AbortError");
          }
          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
          });
          if (signal?.aborted) {
            throw new DOMException("Aborted", "AbortError");
          }
          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
              }
            );
          }
          registerFrames(req, mapped);
          return { frames: mapped, req };
        };
        const orderedResults = await runRequestNodes({
          nodes,
          maxConcurrent,
          signal,
          runNode: runOne,
          onPartialOrdered: (completed) => {
            if (signal?.aborted) return;
            const partialFrames = [];
            for (const item of completed) {
              for (const fr of item.value.frames) partialFrames.push(fr);
            }
            if (partialFrames.length) {
              request.onPartialData?.(partialFrames);
            }
          }
        });
        for (const item of orderedResults) {
          if (!item) continue;
          for (const fr of item.frames) frames.push(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 (isV5WireProfile(profileId)) {
            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: t2,
            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: t2,
              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 = t2;
            }
            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 kind2 = credentialKind.value;
      if (!v) {
        setRuntimeCredential(uid, null);
        return;
      }
      if (kind2 === "apiKey" || kind2 === "signozApiKey") {
        setRuntimeCredential(uid, {
          kind: "apiKey",
          value: v,
          headerName: headerName.value || (kind2 === "signozApiKey" ? "SIGNOZ-API-KEY" : "X-API-Key")
        });
      } else if (kind2 === "headers") {
        const h2 = headerName.value || "Authorization";
        setRuntimeCredential(uid, { kind: "headers", headers: { [h2]: v } });
      } else if (kind2 === "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 (kind2 === "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$38), { 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: "argus-v5 (Argus /api/apm)", value: "argus-v5" },
                { 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-5ff5cb54"]]);
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
