detectkit 0.55.0__tar.gz → 0.55.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. {detectkit-0.55.0/detectkit.egg-info → detectkit-0.55.2}/PKG-INFO +1 -1
  2. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/__init__.py +1 -1
  3. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/cli.md +3 -1
  4. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/assets/ui.js +18 -15
  5. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/server.py +8 -2
  6. {detectkit-0.55.0 → detectkit-0.55.2/detectkit.egg-info}/PKG-INFO +1 -1
  7. {detectkit-0.55.0 → detectkit-0.55.2}/LICENSE +0 -0
  8. {detectkit-0.55.0 → detectkit-0.55.2}/MANIFEST.in +0 -0
  9. {detectkit-0.55.0 → detectkit-0.55.2}/README.md +0 -0
  10. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/__init__.py +0 -0
  11. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/__init__.py +0 -0
  12. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/base.py +0 -0
  13. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/branding.py +0 -0
  14. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/email.py +0 -0
  15. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/factory.py +0 -0
  16. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/mattermost.py +0 -0
  17. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/slack.py +0 -0
  18. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/telegram.py +0 -0
  19. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/channels/webhook.py +0 -0
  20. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/__init__.py +0 -0
  21. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_base.py +0 -0
  22. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
  23. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_decision.py +0 -0
  24. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
  25. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_recovery.py +0 -0
  26. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_replay.py +0 -0
  27. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/_types.py +0 -0
  28. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
  29. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/__init__.py +0 -0
  30. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/_base.py +0 -0
  31. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/_types.py +0 -0
  32. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/autotuner.py +0 -0
  33. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/axis_spec.py +0 -0
  34. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/config_emitter.py +0 -0
  35. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/crossval.py +0 -0
  36. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/detector_select.py +0 -0
  37. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/distribution.py +0 -0
  38. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/grid_search.py +0 -0
  39. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/labels.py +0 -0
  40. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/result.py +0 -0
  41. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/runner.py +0 -0
  42. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/scoring.py +0 -0
  43. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/seasonality_search.py +0 -0
  44. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/settings.py +0 -0
  45. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/autotune/window_select.py +0 -0
  46. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/__init__.py +0 -0
  47. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/_output.py +0 -0
  48. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
  49. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/alerting.md +0 -0
  50. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
  51. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
  52. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
  53. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/overview.md +0 -0
  54. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/rules/project.md +0 -0
  55. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +0 -0
  56. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
  57. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
  58. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
  59. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/assets/claude/skills/dtk-tune/SKILL.md +0 -0
  60. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/__init__.py +0 -0
  61. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/autotune.py +0 -0
  62. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/clean.py +0 -0
  63. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/init.py +0 -0
  64. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/init_claude.py +0 -0
  65. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/osi.py +0 -0
  66. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/run.py +0 -0
  67. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/test_alert.py +0 -0
  68. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/tune.py +0 -0
  69. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/ui.py +0 -0
  70. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/commands/unlock.py +0 -0
  71. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/cli/main.py +0 -0
  72. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/__init__.py +0 -0
  73. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/metric_config.py +0 -0
  74. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/metric_io.py +0 -0
  75. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/profile.py +0 -0
  76. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/project_config.py +0 -0
  77. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/config/validator.py +0 -0
  78. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/core/__init__.py +0 -0
  79. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/core/interval.py +0 -0
  80. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/core/models.py +0 -0
  81. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/__init__.py +0 -0
  82. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/_sql_manager.py +0 -0
  83. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/clickhouse_manager.py +0 -0
  84. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/__init__.py +0 -0
  85. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_alert_states.py +0 -0
  86. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
  87. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_base.py +0 -0
  88. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_datapoints.py +0 -0
  89. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_detections.py +0 -0
  90. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_maintenance.py +0 -0
  91. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_metrics.py +0 -0
  92. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_schema.py +0 -0
  93. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/_tasks.py +0 -0
  94. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/internal_tables/manager.py +0 -0
  95. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/manager.py +0 -0
  96. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/mysql_manager.py +0 -0
  97. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/postgres_manager.py +0 -0
  98. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/database/tables.py +0 -0
  99. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/__init__.py +0 -0
  100. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/base.py +0 -0
  101. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/factory.py +0 -0
  102. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/seasonality.py +0 -0
  103. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/__init__.py +0 -0
  104. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/_windowed.py +0 -0
  105. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/autoreg.py +0 -0
  106. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/iqr.py +0 -0
  107. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/mad.py +0 -0
  108. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/manual_bounds.py +0 -0
  109. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/detectors/statistical/zscore.py +0 -0
  110. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/loaders/__init__.py +0 -0
  111. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/loaders/metric_loader.py +0 -0
  112. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/loaders/query_template.py +0 -0
  113. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/__init__.py +0 -0
  114. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/error_dispatch.py +0 -0
  115. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/__init__.py +0 -0
  116. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
  117. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/_base.py +0 -0
  118. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
  119. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/_load_step.py +0 -0
  120. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/_types.py +0 -0
  121. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/orchestration/task_manager/manager.py +0 -0
  122. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/reporting/__init__.py +0 -0
  123. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/reporting/assets/report.js +0 -0
  124. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/reporting/builder.py +0 -0
  125. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/reporting/html_report.py +0 -0
  126. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/__init__.py +0 -0
  127. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/errors.py +0 -0
  128. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/exporter.py +0 -0
  129. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/importer.py +0 -0
  130. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/osi_model.py +0 -0
  131. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/semantic/query_gen.py +0 -0
  132. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/__init__.py +0 -0
  133. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/assets/tune.js +0 -0
  134. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/config_writer.py +0 -0
  135. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/html.py +0 -0
  136. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/payload.py +0 -0
  137. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/tuning/server.py +0 -0
  138. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/__init__.py +0 -0
  139. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/html.py +0 -0
  140. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/jobs.py +0 -0
  141. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/metric_files.py +0 -0
  142. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/ui/overview.py +0 -0
  143. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/utils/__init__.py +0 -0
  144. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/utils/datetime_utils.py +0 -0
  145. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/utils/env_interpolation.py +0 -0
  146. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/utils/json_utils.py +0 -0
  147. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit/utils/stats.py +0 -0
  148. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit.egg-info/SOURCES.txt +0 -0
  149. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit.egg-info/dependency_links.txt +0 -0
  150. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit.egg-info/entry_points.txt +0 -0
  151. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit.egg-info/requires.txt +0 -0
  152. {detectkit-0.55.0 → detectkit-0.55.2}/detectkit.egg-info/top_level.txt +0 -0
  153. {detectkit-0.55.0 → detectkit-0.55.2}/pyproject.toml +0 -0
  154. {detectkit-0.55.0 → detectkit-0.55.2}/requirements.txt +0 -0
  155. {detectkit-0.55.0 → detectkit-0.55.2}/setup.cfg +0 -0
  156. {detectkit-0.55.0 → detectkit-0.55.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.55.0
3
+ Version: 0.55.2
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
@@ -4,7 +4,7 @@ detectk - Anomaly Detection for Time-Series Metrics
4
4
  A Python library for data analysts and engineers to monitor metrics with automatic anomaly detection.
5
5
  """
6
6
 
7
- __version__ = "0.55.0"
7
+ __version__ = "0.55.2"
8
8
 
9
9
  from detectkit.core.interval import Interval
10
10
  from detectkit.core.models import ColumnDefinition, TableModel
@@ -236,7 +236,9 @@ path as `dtk osi import`) — and **YAML**, the raw text, kept for whole-config
236
236
  pastes. The last-edited tab wins, never silently: leaving an edited YAML tab
237
237
  validates server-side first and blocks the switch on error; leaving an
238
238
  edited Builder re-emits the YAML. A debounced live-validation chip re-checks
239
- the draft while typing. Keys the form doesn't model (`autotune:`, custom
239
+ the draft while typing showing the Builder's friendly checks while the
240
+ YAML tab still mirrors the form, and a one-line `field — reason` summary of
241
+ server errors otherwise. Keys the form doesn't model (`autotune:`, custom
240
242
  templates, unknown detector types/params, a multi-entry alerting list)
241
243
  round-trip verbatim, listed under "Preserved fields". Create writes
242
244
  `metrics/[<folder>/]<name>.yml`; after a create, a **next-steps strip**
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{var O=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function tt(e){let t=e/60;return e>=86400&&e%86400===0?e/86400+"d":e>=3600&&e%3600===0?e/3600+"h":t>=1&&e%60===0?t+"min":e+"s"}function ge(e){return e==null||!Number.isFinite(e)?"\u2014":(e*100).toFixed(1)+"%"}function Te(e){return e==null||!Number.isFinite(e)?"\u2014":Math.round(e).toLocaleString("en-US")}function Ce(e){return e==null||!Number.isFinite(e)?"\u2014":`\u2248${e>=9.5?e.toFixed(0):e.toFixed(1)}/day`}function $e(e,t){let n=Math.max(0,e-t),r=Math.round(n/6e4);if(r<1)return"just now";if(r<60)return`${r}m ago`;let i=Math.floor(r/60);if(i<24)return`${i}h ago`;let o=Math.floor(i/24);return o<30?`${o}d ago`:`${Math.floor(o/30)}mo ago`}function nt(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;if(r<60)return i?`${r}m ${i}s`:`${r}m`;let o=Math.floor(r/60),a=r%60;return`${o}h ${String(a).padStart(2,"0")}m`}function Fe(e){return new Date(e).toISOString().slice(0,19).replace("T"," ")}function Oe(e,t){return e===null?null:Math.max(0,e-(t!=null?t:0))}function Ne(e){let t=Math.round(e/60);if(t<60)return`${t}m`;let n=Math.floor(t/60),r=t%60;if(n<24)return n+"h"+(r?` ${r}m`:"");let i=Math.floor(n/24),o=n%24;return i+"d"+(o?` ${o}h`:"")}function ot(e,t){let n=new Map;for(let r of e){let i=t(r),o=n.get(i);o?o.push(r):n.set(i,[r])}return n}function it(e,t){let n;return()=>{n!==void 0&&window.clearTimeout(n),n=window.setTimeout(e,t)}}var Vt=new URLSearchParams(location.search).get("token")||"";function ze(e,t){let n=new URL(e,location.origin);if(n.searchParams.set("token",Vt),t)for(let[r,i]of Object.entries(t))n.searchParams.set(r,i);return n.toString()}function Be(e,t){return ze(`/metric/${encodeURIComponent(e)}`,{window:t})}async function rt(e){let t=await e.text().catch(()=>"");return new Error(t||`HTTP ${e.status}`)}async function Ie(e,t){let n=await fetch(ze(e,t));if(!n.ok)throw await rt(n);return n.json()}async function ue(e,t){let n=await fetch(ze(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw await rt(n);return n.json()}function Je(e,t){return Ie(`/api/stats/${encodeURIComponent(e)}`,{window:t})}function at(){return Ie("/api/jobs")}function st(e,t){return Ie(`/api/job/${encodeURIComponent(e)}`,{offset:String(t)})}function Ue(e){return ue("/api/run",e)}function lt(e){return ue("/api/autotune",e)}function dt(e){return ue("/api/unlock",e)}function ct(e){return ue("/api/tune",e)}function ut(e){return ue(`/api/job/${encodeURIComponent(e)}/stop`,{})}function pt(e){return Ie(`/api/metric-source/${encodeURIComponent(e)}`)}function mt(e){return ue("/api/metric-create",e)}function ft(e,t){return ue(`/api/metric/${encodeURIComponent(e)}/update`,t)}function bt(e){return ue(`/api/metric/${encodeURIComponent(e)}/delete`,{confirm:e})}function Ye(e){return ue("/api/metric-parse",{text:e})}function gt(e){return ue("/api/osi-inspect",{text:e})}function ht(e){return ue("/api/osi-import",e)}var ve="dtk-ui",vt=!1;function yt(){if(vt)return;vt=!0;let e=`
1
+ "use strict";(()=>{var O=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function tt(e){let t=e/60;return e>=86400&&e%86400===0?e/86400+"d":e>=3600&&e%3600===0?e/3600+"h":t>=1&&e%60===0?t+"min":e+"s"}function ge(e){return e==null||!Number.isFinite(e)?"\u2014":(e*100).toFixed(1)+"%"}function Te(e){return e==null||!Number.isFinite(e)?"\u2014":Math.round(e).toLocaleString("en-US")}function Ce(e){return e==null||!Number.isFinite(e)?"\u2014":`\u2248${e>=9.5?e.toFixed(0):e.toFixed(1)}/day`}function $e(e,t){let n=Math.max(0,e-t),r=Math.round(n/6e4);if(r<1)return"just now";if(r<60)return`${r}m ago`;let i=Math.floor(r/60);if(i<24)return`${i}h ago`;let o=Math.floor(i/24);return o<30?`${o}d ago`:`${Math.floor(o/30)}mo ago`}function nt(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;if(r<60)return i?`${r}m ${i}s`:`${r}m`;let o=Math.floor(r/60),a=r%60;return`${o}h ${String(a).padStart(2,"0")}m`}function Fe(e){return new Date(e).toISOString().slice(0,19).replace("T"," ")}function Oe(e,t){return e===null?null:Math.max(0,e-(t!=null?t:0))}function Ne(e){let t=Math.round(e/60);if(t<60)return`${t}m`;let n=Math.floor(t/60),r=t%60;if(n<24)return n+"h"+(r?` ${r}m`:"");let i=Math.floor(n/24),o=n%24;return i+"d"+(o?` ${o}h`:"")}function ot(e,t){let n=new Map;for(let r of e){let i=t(r),o=n.get(i);o?o.push(r):n.set(i,[r])}return n}function it(e,t){let n;return()=>{n!==void 0&&window.clearTimeout(n),n=window.setTimeout(e,t)}}var Qt=new URLSearchParams(location.search).get("token")||"";function ze(e,t){let n=new URL(e,location.origin);if(n.searchParams.set("token",Qt),t)for(let[r,i]of Object.entries(t))n.searchParams.set(r,i);return n.toString()}function Be(e,t){return ze(`/metric/${encodeURIComponent(e)}`,{window:t})}async function rt(e){let t=await e.text().catch(()=>"");return new Error(t||`HTTP ${e.status}`)}async function Ie(e,t){let n=await fetch(ze(e,t));if(!n.ok)throw await rt(n);return n.json()}async function ue(e,t){let n=await fetch(ze(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw await rt(n);return n.json()}function Je(e,t){return Ie(`/api/stats/${encodeURIComponent(e)}`,{window:t})}function at(){return Ie("/api/jobs")}function st(e,t){return Ie(`/api/job/${encodeURIComponent(e)}`,{offset:String(t)})}function Ue(e){return ue("/api/run",e)}function lt(e){return ue("/api/autotune",e)}function dt(e){return ue("/api/unlock",e)}function ct(e){return ue("/api/tune",e)}function ut(e){return ue(`/api/job/${encodeURIComponent(e)}/stop`,{})}function pt(e){return Ie(`/api/metric-source/${encodeURIComponent(e)}`)}function mt(e){return ue("/api/metric-create",e)}function ft(e,t){return ue(`/api/metric/${encodeURIComponent(e)}/update`,t)}function bt(e){return ue(`/api/metric/${encodeURIComponent(e)}/delete`,{confirm:e})}function Ye(e){return ue("/api/metric-parse",{text:e})}function gt(e){return ue("/api/osi-inspect",{text:e})}function ht(e){return ue("/api/osi-import",e)}var ve="dtk-ui",vt=!1;function yt(){if(vt)return;vt=!0;let e=`
2
2
  .${ve}{
3
3
  --clay:#d15b36;--clay-700:#b4471f;--ink:#1b1916;--paper:#f5f1e8;
4
4
  --muted:#6e675b;--faint:#9a9384;
@@ -456,19 +456,19 @@
456
456
  .dtk-ui-row2{grid-template-columns:1fr;}
457
457
  .dtk-ui-table-wrap{overflow-x:auto;}
458
458
  }
459
- `,t=document.createElement("style");t.setAttribute("data-dtk-ui",""),t.textContent=e,document.head.appendChild(t)}var ye=null;function Gt(e){return ye&&ye.isConnected||(ye=document.createElement("div"),ye.className="dtk-toasts",e.appendChild(ye)),ye}function de(e,t,n){let r=Gt(e),i=document.createElement("div");i.className=`dtk-toast dtk-toast-${t}`,i.textContent=n,r.appendChild(i),window.setTimeout(()=>{i.classList.add("dtk-toast-out"),window.setTimeout(()=>i.remove(),220)},5e3)}function ke(e,t,n,r){let i="dtk-ui-tile"+(r!=null&&r.err?" err":""),o=r!=null&&r.warn?"dtk-ui-tile-sub warn":"dtk-ui-tile-sub";return`<div class="${i}"><div class="dtk-ui-tile-val">${O(e)}</div><div class="dtk-ui-tile-label">${O(t)}</div>`+(n?`<div class="${o}">${O(n)}</div>`:"")+"</div>"}function kt(e){let t=document.createElement("div");t.className="dtk-ui-tiles";let n=e.length,r=e.filter(c=>c.enabled).length,i=e.filter(c=>!c.pending),o=0,a=0,s=0,f=0,l=!1;for(let c of i)o+=c.alerts.anomaly,a+=c.alerts.no_data,c.alerts.anomaly>0&&s++,c.alerts.per_day!==null&&(f+=c.alerts.per_day,l=!0);let p=[];for(let c of i){if(!c.enabled)continue;if(c.last_point===null){p.push({m:c,lag:1/0});continue}let v=Oe(c.lag_seconds,c.loading_delay_seconds);v!==null&&c.interval_seconds>0&&v>2*c.interval_seconds&&p.push({m:c,lag:v})}p.sort((c,v)=>v.lag-c.lag);let h=p.length===0?void 0:`worst: ${p[0].m.name}${Number.isFinite(p[0].lag)?` (${Ne(p[0].lag)})`:" (no data)"}`;t.innerHTML=ke(`${r}/${n}`,"Metrics","enabled / total")+ke(Te(o),"Alerts in window",l?Ce(f):void 0)+ke(Te(a),"No-data events")+ke(Te(s),"Metrics alerting")+ke(Te(p.length),"Stale metrics",h,{warn:p.length>0,err:p.length>0});let m=i.filter(c=>c.quality!==null);if(m.length>0){let c=0,v=0,w=0,M=0,u=0;for(let g of m){let S=g.quality;S&&(c+=S.caught,v+=S.incidents_in_window,w+=S.false_alerts,M+=g.alerts.anomaly,g.budget>u&&(u=g.budget))}let x=v>0?c/v:null,b=M>0?w/M:null,k=b!==null&&u>0&&b>u;t.innerHTML+=ke(ge(x),"Labeled recall",`${m.length} metric(s) labeled`)+ke(ge(b),"False-alert rate",k?`\u25B2 over ${ge(u)} budget`:void 0,{warn:k})}return t}var Re="untagged";function Xt(e){let t=new Map,n=(r,i)=>{let o=t.get(r);o||(o={tag:r,count:0,alerts:0,perDaySum:0,havePerDay:!1},t.set(r,o)),o.count++,o.alerts+=i.alerts.anomaly,i.alerts.per_day!==null&&(o.perDaySum+=i.alerts.per_day,o.havePerDay=!0)};for(let r of e)if(r.tags.length===0)n(Re,r);else for(let i of r.tags)n(i,r);return[...t.values()].sort((r,i)=>i.count-r.count||r.tag.localeCompare(i.tag))}function xt(e,t,n){let r=document.createElement("div");r.className="dtk-ui-tags";let i=document.createElement("button");i.type="button",i.className="dtk-ui-tag"+(t===null?" on":""),i.innerHTML=`<span class="dtk-ui-tag-name">All</span><span class="dtk-ui-tag-n">${e.length}</span>`,i.onclick=()=>n(null),r.appendChild(i);for(let o of Xt(e)){let a=document.createElement("button");a.type="button",a.className="dtk-ui-tag"+(t===o.tag?" on":"");let s=o.havePerDay?` \xB7 ${Ce(o.perDaySum)}`:"";a.innerHTML=`<span class="dtk-ui-tag-name">${O(o.tag===Re?Re:`#${o.tag}`)}</span><span class="dtk-ui-tag-n">${o.count} metric${o.count===1?"":"s"}</span><span class="dtk-ui-tag-n">${o.alerts} alert${o.alerts===1?"":"s"}</span>`+(s?`<span class="dtk-ui-tag-sub">${O(s)}</span>`:""),a.onclick=()=>n(o.tag),r.appendChild(a)}return r}var Zt={"--term-bg":"#211e1a","--clay":"#d15b36","--st-anomaly":"#d63232","--st-recovery":"#36a64f","--st-nodata":"#f0ad4e","--st-error":"#5a7a8c","--faint":"#9a9384","--muted":"#6e675b","--border":"#332f29","--term-border":"#332f29"};function Ae(e){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()||Zt[e]||"#888"}function en(e){let t=e.replace("#","").trim();t.length===3&&(t=t[0]+t[0]+t[1]+t[1]+t[2]+t[2]);let n=parseInt(t,16);return t.length!==6||Number.isNaN(n)?[209,91,54]:[n>>16&255,n>>8&255,n&255]}function wt(e,t){let[n,r,i]=en(e);return`rgba(${n},${r},${i},${t})`}var Gn=Number.isFinite;var Et=140,Ct=30;function St(e,t,n){let r=Math.max(1,window.devicePixelRatio||1);e.style.width=`${Et}px`,e.style.height=`${Ct}px`,e.width=Math.round(Et*r),e.height=Math.round(Ct*r);let i=e.getContext("2d");if(!i||(i.clearRect(0,0,e.width,e.height),t.length===0))return;let o=3*r,a=e.width,s=e.height,f=t[0].t,l=t[t.length-1].t,p=l-f||1,h=b=>o+(b-f)/p*Math.max(1,a-2*o),m=1/0,c=-1/0;for(let b of t)b.v!==null&&Number.isFinite(b.v)&&(b.v<m&&(m=b.v),b.v>c&&(c=b.v));let v=!Number.isFinite(m)||!Number.isFinite(c);v&&(m=0,c=1),c<=m&&(c=m+1);let w=b=>s-o-(b-m)/(c-m)*Math.max(1,s-2*o);if(v){let b=s/2;i.strokeStyle=wt(Ae("--faint"),.5),i.lineWidth=1*r,i.setLineDash([2*r,2*r]),i.beginPath(),i.moveTo(o,b),i.lineTo(a-o,b),i.stroke(),i.setLineDash([]);return}i.strokeStyle=Ae("--term-text"),i.lineWidth=1*r,i.lineJoin="round",i.beginPath();let M=!1;for(let b of t){if(b.v===null||!Number.isFinite(b.v)){M=!1;continue}let k=h(b.t),g=w(b.v);M?i.lineTo(k,g):(i.moveTo(k,g),M=!0)}if(i.stroke(),n.length===0)return;let u=[];for(let b of t)b.v!==null&&Number.isFinite(b.v)&&u.push([b.t,b.v]);let x=b=>{if(u.length===0)return null;if(b<=u[0][0])return u[0][1];if(b>=u[u.length-1][0])return u[u.length-1][1];for(let k=1;k<u.length;k++){let[g,S]=u[k];if(b<=g){let[N,L]=u[k-1],_=g===N?0:(b-N)/(g-N);return L+(S-L)*_}}return u[u.length-1][1]};i.fillStyle=Ae("--st-anomaly");for(let b of n){if(b<f||b>l)continue;let k=x(b);k!==null&&(i.beginPath(),i.arc(h(b),w(k),2*r,0,Math.PI*2),i.fill())}}var Pe='<span class="dtk-ui-pending">\xB7\xB7\xB7</span>';function Se(e){return{name:e.name,dir:e.dir,file:e.file,tags:e.tags,enabled:e.enabled,interval_seconds:e.interval_seconds,loading_delay_seconds:0,detectors:[],alert_rule:null,last_point:null,first_point_in_window:null,lag_seconds:null,locked:!1,points:0,flagged:0,anomaly_rate:null,alerts:{anomaly:0,recovery:0,no_data:0,per_day:null,last_ts:null},quality:null,budget:0,spark:[],spark_anoms:[],error:null,pending:!0}}var Ke={alerts:"desc",name:"asc",rate:"desc",freshness:"desc"};function Tt(e){var a,s;if(e.pending)return{color:"var(--faint)",title:"loading\u2026",rank:0};if(!e.enabled)return{color:"var(--faint)",title:"disabled",rank:-1};if(e.last_point===null)return{color:"var(--st-anomaly)",title:"no datapoints loaded yet",rank:1/0};let t=(a=e.loading_delay_seconds)!=null?a:0,n=(s=Oe(e.lag_seconds,e.loading_delay_seconds))!=null?s:0,r=e.interval_seconds>0?n/e.interval_seconds:0,i=t>0?` \xB7 maturity delay ${Ne(t)} excluded`:"",o=`lag ${Ne(n)} (${r.toFixed(1)}\xD7 interval)${i} \xB7 last point ${Fe(e.last_point)} UTC`;return r<2?{color:"var(--st-recovery)",title:o,rank:n}:r<6?{color:"var(--st-nodata)",title:o,rank:n}:{color:"var(--st-anomaly)",title:o,rank:n}}function tn(e){return e.length===0?"":`<div class="dtk-ui-tagchips">${e.map(t=>`<span class="dtk-ui-tagchip">${O(t)}</span>`).join("")}</div>`}function nn(e){let t=e.quality;if(!t)return'<span class="dtk-ui-quality empty">\u2014</span>';let n=`Incidents: ${t.incidents} (${t.incidents_in_window} in window) \xB7 caught ${t.caught} \xB7 false alerts ${t.false_alerts} \xB7 reviewed ${t.reviewed} (valid ${t.reviewed_valid}, false ${t.reviewed_false}) \xB7 ${t.labels_file}`;return`<span class="dtk-ui-quality" title="${O(n)}"><span class="dtk-ui-quality-chip">R <b>${O(ge(t.recall))}</b></span> \xB7 <span class="dtk-ui-quality-chip">FDR <b>${O(ge(t.fdr))}</b></span> \xB7 <span class="dtk-ui-quality-chip">\u2713${t.reviewed_valid}</span></span>`}function on(e){let t=e.alert_rule?`min_detectors=${e.alert_rule.min_detectors} \xB7 direction=${e.alert_rule.direction} \xB7 consecutive=${e.alert_rule.consecutive} (${e.alert_rule.enabled}/${e.alert_rule.configs} config(s) enabled)`:"no alerting configured";return`detectors: ${e.detectors.join(", ")||"\u2014"}
459
+ `,t=document.createElement("style");t.setAttribute("data-dtk-ui",""),t.textContent=e,document.head.appendChild(t)}var ye=null;function Gt(e){return ye&&ye.isConnected||(ye=document.createElement("div"),ye.className="dtk-toasts",e.appendChild(ye)),ye}function de(e,t,n){let r=Gt(e),i=document.createElement("div");i.className=`dtk-toast dtk-toast-${t}`,i.textContent=n,r.appendChild(i),window.setTimeout(()=>{i.classList.add("dtk-toast-out"),window.setTimeout(()=>i.remove(),220)},5e3)}function ke(e,t,n,r){let i="dtk-ui-tile"+(r!=null&&r.err?" err":""),o=r!=null&&r.warn?"dtk-ui-tile-sub warn":"dtk-ui-tile-sub";return`<div class="${i}"><div class="dtk-ui-tile-val">${O(e)}</div><div class="dtk-ui-tile-label">${O(t)}</div>`+(n?`<div class="${o}">${O(n)}</div>`:"")+"</div>"}function kt(e){let t=document.createElement("div");t.className="dtk-ui-tiles";let n=e.length,r=e.filter(c=>c.enabled).length,i=e.filter(c=>!c.pending),o=0,a=0,s=0,m=0,l=!1;for(let c of i)o+=c.alerts.anomaly,a+=c.alerts.no_data,c.alerts.anomaly>0&&s++,c.alerts.per_day!==null&&(m+=c.alerts.per_day,l=!0);let u=[];for(let c of i){if(!c.enabled)continue;if(c.last_point===null){u.push({m:c,lag:1/0});continue}let v=Oe(c.lag_seconds,c.loading_delay_seconds);v!==null&&c.interval_seconds>0&&v>2*c.interval_seconds&&u.push({m:c,lag:v})}u.sort((c,v)=>v.lag-c.lag);let h=u.length===0?void 0:`worst: ${u[0].m.name}${Number.isFinite(u[0].lag)?` (${Ne(u[0].lag)})`:" (no data)"}`;t.innerHTML=ke(`${r}/${n}`,"Metrics","enabled / total")+ke(Te(o),"Alerts in window",l?Ce(m):void 0)+ke(Te(a),"No-data events")+ke(Te(s),"Metrics alerting")+ke(Te(u.length),"Stale metrics",h,{warn:u.length>0,err:u.length>0});let f=i.filter(c=>c.quality!==null);if(f.length>0){let c=0,v=0,w=0,M=0,p=0;for(let g of f){let S=g.quality;S&&(c+=S.caught,v+=S.incidents_in_window,w+=S.false_alerts,M+=g.alerts.anomaly,g.budget>p&&(p=g.budget))}let x=v>0?c/v:null,b=M>0?w/M:null,k=b!==null&&p>0&&b>p;t.innerHTML+=ke(ge(x),"Labeled recall",`${f.length} metric(s) labeled`)+ke(ge(b),"False-alert rate",k?`\u25B2 over ${ge(p)} budget`:void 0,{warn:k})}return t}var Re="untagged";function Xt(e){let t=new Map,n=(r,i)=>{let o=t.get(r);o||(o={tag:r,count:0,alerts:0,perDaySum:0,havePerDay:!1},t.set(r,o)),o.count++,o.alerts+=i.alerts.anomaly,i.alerts.per_day!==null&&(o.perDaySum+=i.alerts.per_day,o.havePerDay=!0)};for(let r of e)if(r.tags.length===0)n(Re,r);else for(let i of r.tags)n(i,r);return[...t.values()].sort((r,i)=>i.count-r.count||r.tag.localeCompare(i.tag))}function xt(e,t,n){let r=document.createElement("div");r.className="dtk-ui-tags";let i=document.createElement("button");i.type="button",i.className="dtk-ui-tag"+(t===null?" on":""),i.innerHTML=`<span class="dtk-ui-tag-name">All</span><span class="dtk-ui-tag-n">${e.length}</span>`,i.onclick=()=>n(null),r.appendChild(i);for(let o of Xt(e)){let a=document.createElement("button");a.type="button",a.className="dtk-ui-tag"+(t===o.tag?" on":"");let s=o.havePerDay?` \xB7 ${Ce(o.perDaySum)}`:"";a.innerHTML=`<span class="dtk-ui-tag-name">${O(o.tag===Re?Re:`#${o.tag}`)}</span><span class="dtk-ui-tag-n">${o.count} metric${o.count===1?"":"s"}</span><span class="dtk-ui-tag-n">${o.alerts} alert${o.alerts===1?"":"s"}</span>`+(s?`<span class="dtk-ui-tag-sub">${O(s)}</span>`:""),a.onclick=()=>n(o.tag),r.appendChild(a)}return r}var Zt={"--term-bg":"#211e1a","--clay":"#d15b36","--st-anomaly":"#d63232","--st-recovery":"#36a64f","--st-nodata":"#f0ad4e","--st-error":"#5a7a8c","--faint":"#9a9384","--muted":"#6e675b","--border":"#332f29","--term-border":"#332f29"};function Ae(e){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()||Zt[e]||"#888"}function en(e){let t=e.replace("#","").trim();t.length===3&&(t=t[0]+t[0]+t[1]+t[1]+t[2]+t[2]);let n=parseInt(t,16);return t.length!==6||Number.isNaN(n)?[209,91,54]:[n>>16&255,n>>8&255,n&255]}function wt(e,t){let[n,r,i]=en(e);return`rgba(${n},${r},${i},${t})`}var Xn=Number.isFinite;var Et=140,Ct=30;function St(e,t,n){let r=Math.max(1,window.devicePixelRatio||1);e.style.width=`${Et}px`,e.style.height=`${Ct}px`,e.width=Math.round(Et*r),e.height=Math.round(Ct*r);let i=e.getContext("2d");if(!i||(i.clearRect(0,0,e.width,e.height),t.length===0))return;let o=3*r,a=e.width,s=e.height,m=t[0].t,l=t[t.length-1].t,u=l-m||1,h=b=>o+(b-m)/u*Math.max(1,a-2*o),f=1/0,c=-1/0;for(let b of t)b.v!==null&&Number.isFinite(b.v)&&(b.v<f&&(f=b.v),b.v>c&&(c=b.v));let v=!Number.isFinite(f)||!Number.isFinite(c);v&&(f=0,c=1),c<=f&&(c=f+1);let w=b=>s-o-(b-f)/(c-f)*Math.max(1,s-2*o);if(v){let b=s/2;i.strokeStyle=wt(Ae("--faint"),.5),i.lineWidth=1*r,i.setLineDash([2*r,2*r]),i.beginPath(),i.moveTo(o,b),i.lineTo(a-o,b),i.stroke(),i.setLineDash([]);return}i.strokeStyle=Ae("--term-text"),i.lineWidth=1*r,i.lineJoin="round",i.beginPath();let M=!1;for(let b of t){if(b.v===null||!Number.isFinite(b.v)){M=!1;continue}let k=h(b.t),g=w(b.v);M?i.lineTo(k,g):(i.moveTo(k,g),M=!0)}if(i.stroke(),n.length===0)return;let p=[];for(let b of t)b.v!==null&&Number.isFinite(b.v)&&p.push([b.t,b.v]);let x=b=>{if(p.length===0)return null;if(b<=p[0][0])return p[0][1];if(b>=p[p.length-1][0])return p[p.length-1][1];for(let k=1;k<p.length;k++){let[g,S]=p[k];if(b<=g){let[N,L]=p[k-1],_=g===N?0:(b-N)/(g-N);return L+(S-L)*_}}return p[p.length-1][1]};i.fillStyle=Ae("--st-anomaly");for(let b of n){if(b<m||b>l)continue;let k=x(b);k!==null&&(i.beginPath(),i.arc(h(b),w(k),2*r,0,Math.PI*2),i.fill())}}var Pe='<span class="dtk-ui-pending">\xB7\xB7\xB7</span>';function Se(e){return{name:e.name,dir:e.dir,file:e.file,tags:e.tags,enabled:e.enabled,interval_seconds:e.interval_seconds,loading_delay_seconds:0,detectors:[],alert_rule:null,last_point:null,first_point_in_window:null,lag_seconds:null,locked:!1,points:0,flagged:0,anomaly_rate:null,alerts:{anomaly:0,recovery:0,no_data:0,per_day:null,last_ts:null},quality:null,budget:0,spark:[],spark_anoms:[],error:null,pending:!0}}var Ke={alerts:"desc",name:"asc",rate:"desc",freshness:"desc"};function Tt(e){var a,s;if(e.pending)return{color:"var(--faint)",title:"loading\u2026",rank:0};if(!e.enabled)return{color:"var(--faint)",title:"disabled",rank:-1};if(e.last_point===null)return{color:"var(--st-anomaly)",title:"no datapoints loaded yet",rank:1/0};let t=(a=e.loading_delay_seconds)!=null?a:0,n=(s=Oe(e.lag_seconds,e.loading_delay_seconds))!=null?s:0,r=e.interval_seconds>0?n/e.interval_seconds:0,i=t>0?` \xB7 maturity delay ${Ne(t)} excluded`:"",o=`lag ${Ne(n)} (${r.toFixed(1)}\xD7 interval)${i} \xB7 last point ${Fe(e.last_point)} UTC`;return r<2?{color:"var(--st-recovery)",title:o,rank:n}:r<6?{color:"var(--st-nodata)",title:o,rank:n}:{color:"var(--st-anomaly)",title:o,rank:n}}function tn(e){return e.length===0?"":`<div class="dtk-ui-tagchips">${e.map(t=>`<span class="dtk-ui-tagchip">${O(t)}</span>`).join("")}</div>`}function nn(e){let t=e.quality;if(!t)return'<span class="dtk-ui-quality empty">\u2014</span>';let n=`Incidents: ${t.incidents} (${t.incidents_in_window} in window) \xB7 caught ${t.caught} \xB7 false alerts ${t.false_alerts} \xB7 reviewed ${t.reviewed} (valid ${t.reviewed_valid}, false ${t.reviewed_false}) \xB7 ${t.labels_file}`;return`<span class="dtk-ui-quality" title="${O(n)}"><span class="dtk-ui-quality-chip">R <b>${O(ge(t.recall))}</b></span> \xB7 <span class="dtk-ui-quality-chip">FDR <b>${O(ge(t.fdr))}</b></span> \xB7 <span class="dtk-ui-quality-chip">\u2713${t.reviewed_valid}</span></span>`}function on(e){let t=e.alert_rule?`min_detectors=${e.alert_rule.min_detectors} \xB7 direction=${e.alert_rule.direction} \xB7 consecutive=${e.alert_rule.consecutive} (${e.alert_rule.enabled}/${e.alert_rule.configs} config(s) enabled)`:"no alerting configured";return`detectors: ${e.detectors.join(", ")||"\u2014"}
460
460
  alert rule: ${t}
461
- file: ${e.file}`}function rn(e,t,n,r){let i=document.createElement("tr");i.className="dtk-ui-row"+(e.enabled?"":" disabled")+(e.error?" errored":"")+(e.pending?" pending":"");let o=Tt(e),a=document.createElement("td");a.className="dtk-ui-dotcell",a.innerHTML=`<span class="dtk-ui-dot" style="background:${o.color}" title="${O(o.title)}"></span>`,i.appendChild(a);let s=document.createElement("td");s.className="dtk-ui-namecell";let f=e.error?`<span class="dtk-ui-err-badge" title="${O(e.error)}">!</span>`:"";s.title=on(e),s.innerHTML=`<span class="dtk-ui-name">${O(e.name)}</span>${f}${tn(e.tags)}`,i.appendChild(s);let l=document.createElement("td");l.innerHTML=`<span class="dtk-ui-interval">${O(tt(e.interval_seconds))}</span>`,i.appendChild(l);let p=document.createElement("td");if(p.className="dtk-ui-sparkcell",e.pending)p.innerHTML='<span class="dtk-ui-spark-loading">loading\u2026</span>';else if(e.spark.length===0)p.innerHTML='<span class="dtk-ui-spark-empty">no data yet</span>';else{let g=document.createElement("canvas");g.className="dtk-spark",p.appendChild(g),r.push({canvas:g,points:e.spark.map(([S,N])=>({t:S,v:N})),anoms:e.spark_anoms})}i.appendChild(p);let h=document.createElement("td");if(h.className="dtk-ui-alertscell",e.pending)h.innerHTML=Pe;else{let g=e.quality!==null&&e.quality.fdr!==null&&e.quality.fdr>e.budget,S="dtk-ui-alerts-n"+(e.alerts.anomaly>0?" hasany":"")+(g?" overbudget":""),N=e.alerts.per_day!==null?`<span class="dtk-ui-alerts-sub">\xB7 ${O(Ce(e.alerts.per_day))}</span>`:"";h.innerHTML=`<span class="${S}">${e.alerts.anomaly}</span>${N}`}i.appendChild(h);let m=document.createElement("td");e.pending?m.innerHTML=Pe:e.alerts.last_ts!==null?m.innerHTML=`<span class="dtk-ui-lastalert" title="${O(Fe(e.alerts.last_ts))} UTC">${O($e(t,e.alerts.last_ts))}</span>`:m.innerHTML='<span class="dtk-ui-lastalert">\u2014</span>',i.appendChild(m);let c=document.createElement("td");c.innerHTML=e.pending?Pe:`<span class="dtk-ui-rate">${O(ge(e.anomaly_rate))}</span>`,i.appendChild(c);let v=document.createElement("td");v.innerHTML=e.pending?Pe:nn(e),i.appendChild(v);let w=document.createElement("td");w.innerHTML=e.locked?'<span class="dtk-ui-lock" title="pipeline lock currently held for this metric">LOCK</span>':"",i.appendChild(w);let M=document.createElement("td");M.className="dtk-ui-actionscell";let u=document.createElement("button");u.type="button",u.className="dtk-ui-actionbtn",u.textContent="Open",u.onclick=()=>n.onOpen(e.name);let x=document.createElement("button");x.type="button",x.className="dtk-ui-actionbtn",x.textContent="Tune",x.onclick=()=>n.onTune(e.name);let b=document.createElement("button");b.type="button",b.className="dtk-ui-actionbtn",b.textContent="Run",b.onclick=()=>n.onRun(e.name);let k=document.createElement("button");return k.type="button",k.className="dtk-ui-actionbtn",k.textContent="Edit",k.onclick=()=>n.onEdit(e.name),M.append(u,x,b,k),i.appendChild(M),i}function Mt(e,t){var n;switch(t){case"alerts":return e.alerts.anomaly;case"name":return e.name.toLowerCase();case"rate":return(n=e.anomaly_rate)!=null?n:-1;case"freshness":return Tt(e).rank}}function an(e,t){let n=e.filter(o=>o.enabled),r=e.filter(o=>!o.enabled),i=t.dir==="asc"?1:-1;return n.sort((o,a)=>{let s=Mt(o,t.key),f=Mt(a,t.key);return s<f?-1*i:s>f?1*i:o.name.localeCompare(a.name)}),r.sort((o,a)=>o.name.localeCompare(a.name)),[...n,...r]}var sn=[{label:"\u25CF",key:"freshness"},{label:"Name",key:"name"},{label:"Interval",key:null},{label:"Trend",key:null},{label:"Alerts",key:"alerts"},{label:"Last alert",key:null},{label:"Rate",key:"rate"},{label:"Quality",key:null},{label:"",key:null},{label:"",key:null}];function ln(e,t){let n=document.createElement("tr");for(let r of sn){let i=document.createElement("th");if(r.key){i.className="dtk-ui-th";let o=e.key===r.key?`<span class="dtk-ui-th-arrow">${e.dir==="asc"?"\u25B5":"\u25BE"}</span>`:"";i.innerHTML=`${O(r.label)}${o}`,i.onclick=()=>t.onSortChange(r.key)}else i.textContent=r.label;n.appendChild(i)}return n}function dn(e){return e===""?"metrics/":`metrics/${e}/`}function Nt(e,t,n,r){var f;let i=[],o=document.createElement("div");if(o.className="dtk-ui-table-wrap",e.length===0)return o.innerHTML='<div class="dtk-ui-empty">No metrics match the current filter.</div>',{el:o,paint:()=>{}};let a=ot(e,l=>l.dir),s=[...a.keys()].sort((l,p)=>l===p?0:l===""?-1:p===""?1:l.localeCompare(p));for(let l of s){let p=(f=a.get(l))!=null?f:[],h=document.createElement("div");h.className="dtk-ui-group";let m=p.reduce((u,x)=>u+x.alerts.anomaly,0),c=document.createElement("div");c.className="dtk-ui-group-head",c.innerHTML=`<span class="dtk-ui-group-name">${O(dn(l))}</span><span class="dtk-ui-group-sub">${p.length} metric${p.length===1?"":"s"} \xB7 ${m} alert${m===1?"":"s"}</span>`,h.appendChild(c);let v=document.createElement("table");v.className="dtk-ui-table";let w=document.createElement("thead");w.appendChild(ln(t,r)),v.appendChild(w);let M=document.createElement("tbody");for(let u of an(p,t))M.appendChild(rn(u,n,r,i));v.appendChild(M),h.appendChild(v),o.appendChild(h)}return{el:o,paint:()=>{for(let l of i)St(l.canvas,l.points,l.anoms)}}}var cn='a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function He(e,t){let n=document.createElement("div");n.className="dtk-ui-overlay";let r=document.createElement("div");r.className="dtk-ui-overlay-modal"+(t.modalClass?` ${t.modalClass}`:""),r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),n.appendChild(r);let i=document.activeElement instanceof HTMLElement?document.activeElement:null;function o(l){let p=Array.from(r.querySelectorAll(cn)).filter(w=>w.offsetParent!==null);if(p.length===0)return;let h=p[0],m=p[p.length-1],c=document.activeElement,v=c instanceof HTMLElement&&r.contains(c);l.shiftKey&&(!v||c===h)?(l.preventDefault(),m.focus()):!l.shiftKey&&(!v||c===m)&&(l.preventDefault(),h.focus())}function a(l){l.key==="Escape"?t.onRequestClose():l.key==="Tab"&&o(l)}n.addEventListener("click",l=>{l.target===n&&t.onRequestClose()}),document.addEventListener("keydown",a),e.appendChild(n);let s=!1;function f(){s||(s=!0,document.removeEventListener("keydown",a),n.remove(),i==null||i.focus())}return{backdrop:n,modal:r,close:f}}function Rt(e,t,n,r){let i=He(e,{onRequestClose:()=>c()}),{modal:o}=i,a=document.createElement("div");a.className="dtk-ui-overlay-head",a.innerHTML=`<span><span class="dtk-ui-overlay-title">${O(t)}</span><span class="dtk-ui-overlay-sub">window: ${O(n)}</span></span>`;let s=document.createElement("div");s.className="dtk-ui-overlay-actions";let f=document.createElement("button");f.type="button",f.className="dtk-ui-btn",f.textContent="Tune",f.onclick=()=>r.onTune(t);let l=document.createElement("button");l.type="button",l.className="dtk-ui-overlay-close",l.textContent="\u2715",l.title="Close (Esc)",s.append(f,l),a.appendChild(s),o.appendChild(a);let p=document.createElement("div");p.className="dtk-ui-overlay-body";let h=document.createElement("div");h.className="dtk-ui-overlay-loading",h.innerHTML=`<span class="dtk-ui-overlay-spinner"></span><span>Building the report for <b>${O(t)}</b>\u2026</span>`,p.appendChild(h);let m=document.createElement("iframe");m.title=`detectkit report \u2014 ${t}`,m.style.visibility="hidden",m.addEventListener("load",()=>{h.style.display="none",m.style.visibility="visible"}),m.src=Be(t,n),p.appendChild(m),o.appendChild(p);function c(){i.close(),r.onClose()}return l.onclick=c,{setWindow(v){let w=a.querySelector(".dtk-ui-overlay-sub");w&&(w.textContent=`window: ${v}`),h.style.display="",m.style.visibility="hidden",m.src=Be(t,v)},close:c}}var Lt=/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/,_t="dtk-ui-run-select-options";function Dt(e,t){let n=document.createElement("div");n.className="dtk-ui-drawer-backdrop";let r=document.createElement("div");r.className="dtk-ui-drawer";let i=document.createElement("div");i.className="dtk-ui-drawer-head",i.innerHTML='<span class="dtk-ui-drawer-title">Run pipeline</span>';let o=document.createElement("button");o.type="button",o.className="dtk-ui-drawer-close",o.textContent="\u2715",i.appendChild(o),r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-drawer-body",r.appendChild(a);let s=document.createElement("div");s.className="dtk-ui-field";let f=document.createElement("datalist");f.id=_t;let l=document.createElement("input");l.type="text",l.className="dtk-ui-input",l.placeholder="metric name, tag:x, glob, or *",l.value="*",l.setAttribute("list",_t),s.innerHTML='<span class="dtk-ui-field-label">Select</span>',s.append(l,f),a.appendChild(s);let p=document.createElement("div");p.className="dtk-ui-field",p.innerHTML='<span class="dtk-ui-field-label">Steps</span>';let h=document.createElement("div");h.className="dtk-ui-checks";let m={};for(let T of["load","detect","alert"]){let Y=document.createElement("label");Y.className="dtk-ui-check";let W=document.createElement("input");W.type="checkbox",W.checked=!0,W.onchange=J,Y.append(W,document.createTextNode(T)),h.appendChild(Y),m[T]=W}p.appendChild(h),a.appendChild(p);let c=document.createElement("div");c.className="dtk-ui-row2";let v=document.createElement("div");v.className="dtk-ui-field",v.innerHTML='<span class="dtk-ui-field-label">From</span>';let w=document.createElement("input");w.type="text",w.className="dtk-ui-input",w.placeholder="YYYY-MM-DD [HH:MM:SS]",w.oninput=J,v.appendChild(w);let M=document.createElement("div");M.className="dtk-ui-field",M.innerHTML='<span class="dtk-ui-field-label">To</span>';let u=document.createElement("input");u.type="text",u.className="dtk-ui-input",u.placeholder="YYYY-MM-DD [HH:MM:SS]",u.oninput=J,M.appendChild(u),c.append(v,M),a.appendChild(c);let x=document.createElement("div");x.className="dtk-ui-checks";let b=document.createElement("label");b.className="dtk-ui-check";let k=document.createElement("input");k.type="checkbox",b.append(k,document.createTextNode("force (skip lock check)"));let g=document.createElement("label");g.className="dtk-ui-check";let S=document.createElement("input");S.type="checkbox",g.append(S,document.createTextNode("full refresh")),x.append(b,g),a.appendChild(x);let N=document.createElement("div");N.className="dtk-ui-btnrow";let L=document.createElement("button");L.type="button",L.className="dtk-ui-btn primary",L.textContent="Run";let _=document.createElement("button");_.type="button",_.className="dtk-ui-btn",_.textContent="Autotune";let A=document.createElement("button");A.type="button",A.className="dtk-ui-btn danger",A.textContent="Unlock",N.append(L,_,A),a.appendChild(N);let I=document.createElement("div");I.className="dtk-ui-reason",a.appendChild(I);let z=document.createElement("div");z.className="dtk-ui-field",z.innerHTML='<span class="dtk-ui-field-label">Log</span>';let K=document.createElement("div");K.className="dtk-ui-log";let q=document.createElement("div");q.className="dtk-ui-log-body";let G=document.createElement("div");G.className="dtk-ui-log-line",K.append(q,G),z.appendChild(K),a.appendChild(z);let U=[];function B(){q.innerHTML=U.length===0?'<span class="dtk-ui-log-empty">no output yet</span>':U.map(O).join("<br>")}B();function le(){return K.scrollTop+K.clientHeight>=K.scrollHeight-24}function ne(){return Object.keys(m).filter(T=>m[T].checked)}function J(){let T=t.isPipelineBusy(),Y=l.value.trim(),W=w.value.trim()===""||Lt.test(w.value.trim()),Q=u.value.trim()===""||Lt.test(u.value.trim()),oe="";T.busy?oe=T.reason:Y===""?oe="select is required":!W||!Q?oe="from/to must be YYYY-MM-DD or YYYY-MM-DD HH:MM:SS":ne().length===0&&(oe="pick at least one step to run"),I.textContent=oe,L.disabled=oe!=="",_.disabled=T.busy||Y===""||!W||!Q,A.disabled=T.busy||Y===""}function V(){return{select:l.value.trim(),steps:ne(),from:w.value.trim()||null,to:u.value.trim()||null,full_refresh:S.checked,force:k.checked}}L.onclick=()=>t.submitRun(V()),_.onclick=()=>t.submitAutotune({select:l.value.trim(),from:w.value.trim()||null,to:u.value.trim()||null}),A.onclick=()=>{let T=l.value.trim();window.confirm(`Unlock the pipeline lock for "${T}"? Only do this if you're sure no dtk process is actually running against it.`)&&t.submitUnlock({select:T})};function E(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=E,n.onclick=E,e.append(n,r),{el:r,open(T){T&&(l.value=T),n.classList.add("open"),r.classList.add("open"),J()},close:E,isOpen(){return r.classList.contains("open")},refreshOptions(){f.innerHTML=["*",...t.getSelectOptions()].map(T=>`<option value="${O(T)}"></option>`).join("")},refreshBusyState:J,resetLog(){U=[],B(),G.textContent="",G.className="dtk-ui-log-line"},appendLog(T){if(T.length===0)return;let Y=le();U.push(...T),B(),Y&&(K.scrollTop=K.scrollHeight)},setLogStatus(T,Y){if(T==="running")return;let W=T==="done"&&Y===0?"exit-ok":T==="stopped"?"exit-stop":"exit-fail";G.className=`dtk-ui-log-line ${W}`,G.textContent=`\u2500\u2500 ${T} (exit ${Y!=null?Y:"?"}) \u2500\u2500`}}}function un(e){return e==="done"?"var(--st-recovery)":e==="failed"?"var(--st-anomaly)":e==="running"?"var(--clay)":"var(--faint)"}function $t(e,t){let n=document.createElement("div");n.className="dtk-ui-drawer-backdrop";let r=document.createElement("div");r.className="dtk-ui-drawer";let i=document.createElement("div");i.className="dtk-ui-drawer-head",i.innerHTML='<span class="dtk-ui-drawer-title">Jobs</span>';let o=document.createElement("button");o.type="button",o.className="dtk-ui-drawer-close",o.textContent="\u2715",i.appendChild(o),r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-drawer-body",r.appendChild(a);let s=document.createElement("div");s.className="dtk-ui-joblist",a.appendChild(s);function f(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=f,n.onclick=f,e.append(n,r),{el:r,open(){n.classList.add("open"),r.classList.add("open")},close:f,isOpen(){return r.classList.contains("open")},render(l,p,h){var m;if(l.length===0){s.innerHTML='<div class="dtk-ui-empty">No jobs yet.</div>';return}s.innerHTML="";for(let c of l){let v=document.createElement("div");v.className="dtk-ui-jobrow"+(c.id===h?" active":"");let w=c.status==="running"?" pulse":"",M=nt(c.started_at,(m=c.finished_at)!=null?m:p),u=document.createElement("div");u.className="dtk-ui-jobrow-top",u.innerHTML=`<span class="dtk-ui-jobrow-status"><span class="dtk-ui-jobrow-dot${w}" style="background:${un(c.status)}"></span>${O(c.kind)} \xB7 ${O(c.status)}</span><span class="dtk-ui-jobrow-meta">${O($e(p,c.started_at))} \xB7 ${O(M)}</span>`,v.appendChild(u);let x=document.createElement("div");x.className="dtk-ui-jobrow-label",x.textContent=c.label,v.appendChild(x);let b=document.createElement("div");if(b.className="dtk-ui-jobrow-actions",c.status==="running"){let k=document.createElement("button");k.type="button",k.className="dtk-ui-actionbtn",k.textContent="Stop",k.onclick=g=>{g.stopPropagation(),t.onStop(c.id)},b.appendChild(k)}if(c.kind==="tune"&&c.url){let k=document.createElement("a");k.className="dtk-ui-joblink",k.href=c.url,k.target="_blank",k.rel="noopener",k.textContent="Open tuner",k.onclick=g=>g.stopPropagation(),b.appendChild(k)}b.childElementCount>0&&v.appendChild(b),v.onclick=()=>t.onFollow(c.id),s.appendChild(v)}}}}var pn=/^(true|false|null|yes|no|on|off|~)$/i,mn=/^[A-Za-z0-9_][A-Za-z0-9_.\-]*$/,fn=/^[-+.]?\d/;function Ot(e){return!(!mn.test(e)||pn.test(e)||!Number.isNaN(Number(e))||fn.test(e))}function Le(e){return JSON.stringify(e)}function bn(e){var o;let r=(e.endsWith(`
461
+ file: ${e.file}`}function rn(e,t,n,r){let i=document.createElement("tr");i.className="dtk-ui-row"+(e.enabled?"":" disabled")+(e.error?" errored":"")+(e.pending?" pending":"");let o=Tt(e),a=document.createElement("td");a.className="dtk-ui-dotcell",a.innerHTML=`<span class="dtk-ui-dot" style="background:${o.color}" title="${O(o.title)}"></span>`,i.appendChild(a);let s=document.createElement("td");s.className="dtk-ui-namecell";let m=e.error?`<span class="dtk-ui-err-badge" title="${O(e.error)}">!</span>`:"";s.title=on(e),s.innerHTML=`<span class="dtk-ui-name">${O(e.name)}</span>${m}${tn(e.tags)}`,i.appendChild(s);let l=document.createElement("td");l.innerHTML=`<span class="dtk-ui-interval">${O(tt(e.interval_seconds))}</span>`,i.appendChild(l);let u=document.createElement("td");if(u.className="dtk-ui-sparkcell",e.pending)u.innerHTML='<span class="dtk-ui-spark-loading">loading\u2026</span>';else if(e.spark.length===0)u.innerHTML='<span class="dtk-ui-spark-empty">no data yet</span>';else{let g=document.createElement("canvas");g.className="dtk-spark",u.appendChild(g),r.push({canvas:g,points:e.spark.map(([S,N])=>({t:S,v:N})),anoms:e.spark_anoms})}i.appendChild(u);let h=document.createElement("td");if(h.className="dtk-ui-alertscell",e.pending)h.innerHTML=Pe;else{let g=e.quality!==null&&e.quality.fdr!==null&&e.quality.fdr>e.budget,S="dtk-ui-alerts-n"+(e.alerts.anomaly>0?" hasany":"")+(g?" overbudget":""),N=e.alerts.per_day!==null?`<span class="dtk-ui-alerts-sub">\xB7 ${O(Ce(e.alerts.per_day))}</span>`:"";h.innerHTML=`<span class="${S}">${e.alerts.anomaly}</span>${N}`}i.appendChild(h);let f=document.createElement("td");e.pending?f.innerHTML=Pe:e.alerts.last_ts!==null?f.innerHTML=`<span class="dtk-ui-lastalert" title="${O(Fe(e.alerts.last_ts))} UTC">${O($e(t,e.alerts.last_ts))}</span>`:f.innerHTML='<span class="dtk-ui-lastalert">\u2014</span>',i.appendChild(f);let c=document.createElement("td");c.innerHTML=e.pending?Pe:`<span class="dtk-ui-rate">${O(ge(e.anomaly_rate))}</span>`,i.appendChild(c);let v=document.createElement("td");v.innerHTML=e.pending?Pe:nn(e),i.appendChild(v);let w=document.createElement("td");w.innerHTML=e.locked?'<span class="dtk-ui-lock" title="pipeline lock currently held for this metric">LOCK</span>':"",i.appendChild(w);let M=document.createElement("td");M.className="dtk-ui-actionscell";let p=document.createElement("button");p.type="button",p.className="dtk-ui-actionbtn",p.textContent="Open",p.onclick=()=>n.onOpen(e.name);let x=document.createElement("button");x.type="button",x.className="dtk-ui-actionbtn",x.textContent="Tune",x.onclick=()=>n.onTune(e.name);let b=document.createElement("button");b.type="button",b.className="dtk-ui-actionbtn",b.textContent="Run",b.onclick=()=>n.onRun(e.name);let k=document.createElement("button");return k.type="button",k.className="dtk-ui-actionbtn",k.textContent="Edit",k.onclick=()=>n.onEdit(e.name),M.append(p,x,b,k),i.appendChild(M),i}function Mt(e,t){var n;switch(t){case"alerts":return e.alerts.anomaly;case"name":return e.name.toLowerCase();case"rate":return(n=e.anomaly_rate)!=null?n:-1;case"freshness":return Tt(e).rank}}function an(e,t){let n=e.filter(o=>o.enabled),r=e.filter(o=>!o.enabled),i=t.dir==="asc"?1:-1;return n.sort((o,a)=>{let s=Mt(o,t.key),m=Mt(a,t.key);return s<m?-1*i:s>m?1*i:o.name.localeCompare(a.name)}),r.sort((o,a)=>o.name.localeCompare(a.name)),[...n,...r]}var sn=[{label:"\u25CF",key:"freshness"},{label:"Name",key:"name"},{label:"Interval",key:null},{label:"Trend",key:null},{label:"Alerts",key:"alerts"},{label:"Last alert",key:null},{label:"Rate",key:"rate"},{label:"Quality",key:null},{label:"",key:null},{label:"",key:null}];function ln(e,t){let n=document.createElement("tr");for(let r of sn){let i=document.createElement("th");if(r.key){i.className="dtk-ui-th";let o=e.key===r.key?`<span class="dtk-ui-th-arrow">${e.dir==="asc"?"\u25B5":"\u25BE"}</span>`:"";i.innerHTML=`${O(r.label)}${o}`,i.onclick=()=>t.onSortChange(r.key)}else i.textContent=r.label;n.appendChild(i)}return n}function dn(e){return e===""?"metrics/":`metrics/${e}/`}function Nt(e,t,n,r){var m;let i=[],o=document.createElement("div");if(o.className="dtk-ui-table-wrap",e.length===0)return o.innerHTML='<div class="dtk-ui-empty">No metrics match the current filter.</div>',{el:o,paint:()=>{}};let a=ot(e,l=>l.dir),s=[...a.keys()].sort((l,u)=>l===u?0:l===""?-1:u===""?1:l.localeCompare(u));for(let l of s){let u=(m=a.get(l))!=null?m:[],h=document.createElement("div");h.className="dtk-ui-group";let f=u.reduce((p,x)=>p+x.alerts.anomaly,0),c=document.createElement("div");c.className="dtk-ui-group-head",c.innerHTML=`<span class="dtk-ui-group-name">${O(dn(l))}</span><span class="dtk-ui-group-sub">${u.length} metric${u.length===1?"":"s"} \xB7 ${f} alert${f===1?"":"s"}</span>`,h.appendChild(c);let v=document.createElement("table");v.className="dtk-ui-table";let w=document.createElement("thead");w.appendChild(ln(t,r)),v.appendChild(w);let M=document.createElement("tbody");for(let p of an(u,t))M.appendChild(rn(p,n,r,i));v.appendChild(M),h.appendChild(v),o.appendChild(h)}return{el:o,paint:()=>{for(let l of i)St(l.canvas,l.points,l.anoms)}}}var cn='a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function He(e,t){let n=document.createElement("div");n.className="dtk-ui-overlay";let r=document.createElement("div");r.className="dtk-ui-overlay-modal"+(t.modalClass?` ${t.modalClass}`:""),r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),n.appendChild(r);let i=document.activeElement instanceof HTMLElement?document.activeElement:null;function o(l){let u=Array.from(r.querySelectorAll(cn)).filter(w=>w.offsetParent!==null);if(u.length===0)return;let h=u[0],f=u[u.length-1],c=document.activeElement,v=c instanceof HTMLElement&&r.contains(c);l.shiftKey&&(!v||c===h)?(l.preventDefault(),f.focus()):!l.shiftKey&&(!v||c===f)&&(l.preventDefault(),h.focus())}function a(l){l.key==="Escape"?t.onRequestClose():l.key==="Tab"&&o(l)}n.addEventListener("click",l=>{l.target===n&&t.onRequestClose()}),document.addEventListener("keydown",a),e.appendChild(n);let s=!1;function m(){s||(s=!0,document.removeEventListener("keydown",a),n.remove(),i==null||i.focus())}return{backdrop:n,modal:r,close:m}}function Rt(e,t,n,r){let i=He(e,{onRequestClose:()=>c()}),{modal:o}=i,a=document.createElement("div");a.className="dtk-ui-overlay-head",a.innerHTML=`<span><span class="dtk-ui-overlay-title">${O(t)}</span><span class="dtk-ui-overlay-sub">window: ${O(n)}</span></span>`;let s=document.createElement("div");s.className="dtk-ui-overlay-actions";let m=document.createElement("button");m.type="button",m.className="dtk-ui-btn",m.textContent="Tune",m.onclick=()=>r.onTune(t);let l=document.createElement("button");l.type="button",l.className="dtk-ui-overlay-close",l.textContent="\u2715",l.title="Close (Esc)",s.append(m,l),a.appendChild(s),o.appendChild(a);let u=document.createElement("div");u.className="dtk-ui-overlay-body";let h=document.createElement("div");h.className="dtk-ui-overlay-loading",h.innerHTML=`<span class="dtk-ui-overlay-spinner"></span><span>Building the report for <b>${O(t)}</b>\u2026</span>`,u.appendChild(h);let f=document.createElement("iframe");f.title=`detectkit report \u2014 ${t}`,f.style.visibility="hidden",f.addEventListener("load",()=>{h.style.display="none",f.style.visibility="visible"}),f.src=Be(t,n),u.appendChild(f),o.appendChild(u);function c(){i.close(),r.onClose()}return l.onclick=c,{setWindow(v){let w=a.querySelector(".dtk-ui-overlay-sub");w&&(w.textContent=`window: ${v}`),h.style.display="",f.style.visibility="hidden",f.src=Be(t,v)},close:c}}var Lt=/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/,_t="dtk-ui-run-select-options";function Dt(e,t){let n=document.createElement("div");n.className="dtk-ui-drawer-backdrop";let r=document.createElement("div");r.className="dtk-ui-drawer";let i=document.createElement("div");i.className="dtk-ui-drawer-head",i.innerHTML='<span class="dtk-ui-drawer-title">Run pipeline</span>';let o=document.createElement("button");o.type="button",o.className="dtk-ui-drawer-close",o.textContent="\u2715",i.appendChild(o),r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-drawer-body",r.appendChild(a);let s=document.createElement("div");s.className="dtk-ui-field";let m=document.createElement("datalist");m.id=_t;let l=document.createElement("input");l.type="text",l.className="dtk-ui-input",l.placeholder="metric name, tag:x, glob, or *",l.value="*",l.setAttribute("list",_t),s.innerHTML='<span class="dtk-ui-field-label">Select</span>',s.append(l,m),a.appendChild(s);let u=document.createElement("div");u.className="dtk-ui-field",u.innerHTML='<span class="dtk-ui-field-label">Steps</span>';let h=document.createElement("div");h.className="dtk-ui-checks";let f={};for(let T of["load","detect","alert"]){let Y=document.createElement("label");Y.className="dtk-ui-check";let W=document.createElement("input");W.type="checkbox",W.checked=!0,W.onchange=J,Y.append(W,document.createTextNode(T)),h.appendChild(Y),f[T]=W}u.appendChild(h),a.appendChild(u);let c=document.createElement("div");c.className="dtk-ui-row2";let v=document.createElement("div");v.className="dtk-ui-field",v.innerHTML='<span class="dtk-ui-field-label">From</span>';let w=document.createElement("input");w.type="text",w.className="dtk-ui-input",w.placeholder="YYYY-MM-DD [HH:MM:SS]",w.oninput=J,v.appendChild(w);let M=document.createElement("div");M.className="dtk-ui-field",M.innerHTML='<span class="dtk-ui-field-label">To</span>';let p=document.createElement("input");p.type="text",p.className="dtk-ui-input",p.placeholder="YYYY-MM-DD [HH:MM:SS]",p.oninput=J,M.appendChild(p),c.append(v,M),a.appendChild(c);let x=document.createElement("div");x.className="dtk-ui-checks";let b=document.createElement("label");b.className="dtk-ui-check";let k=document.createElement("input");k.type="checkbox",b.append(k,document.createTextNode("force (skip lock check)"));let g=document.createElement("label");g.className="dtk-ui-check";let S=document.createElement("input");S.type="checkbox",g.append(S,document.createTextNode("full refresh")),x.append(b,g),a.appendChild(x);let N=document.createElement("div");N.className="dtk-ui-btnrow";let L=document.createElement("button");L.type="button",L.className="dtk-ui-btn primary",L.textContent="Run";let _=document.createElement("button");_.type="button",_.className="dtk-ui-btn",_.textContent="Autotune";let I=document.createElement("button");I.type="button",I.className="dtk-ui-btn danger",I.textContent="Unlock",N.append(L,_,I),a.appendChild(N);let A=document.createElement("div");A.className="dtk-ui-reason",a.appendChild(A);let z=document.createElement("div");z.className="dtk-ui-field",z.innerHTML='<span class="dtk-ui-field-label">Log</span>';let K=document.createElement("div");K.className="dtk-ui-log";let q=document.createElement("div");q.className="dtk-ui-log-body";let X=document.createElement("div");X.className="dtk-ui-log-line",K.append(q,X),z.appendChild(K),a.appendChild(z);let U=[];function B(){q.innerHTML=U.length===0?'<span class="dtk-ui-log-empty">no output yet</span>':U.map(O).join("<br>")}B();function le(){return K.scrollTop+K.clientHeight>=K.scrollHeight-24}function ne(){return Object.keys(f).filter(T=>f[T].checked)}function J(){let T=t.isPipelineBusy(),Y=l.value.trim(),W=w.value.trim()===""||Lt.test(w.value.trim()),V=p.value.trim()===""||Lt.test(p.value.trim()),oe="";T.busy?oe=T.reason:Y===""?oe="select is required":!W||!V?oe="from/to must be YYYY-MM-DD or YYYY-MM-DD HH:MM:SS":ne().length===0&&(oe="pick at least one step to run"),A.textContent=oe,L.disabled=oe!=="",_.disabled=T.busy||Y===""||!W||!V,I.disabled=T.busy||Y===""}function Q(){return{select:l.value.trim(),steps:ne(),from:w.value.trim()||null,to:p.value.trim()||null,full_refresh:S.checked,force:k.checked}}L.onclick=()=>t.submitRun(Q()),_.onclick=()=>t.submitAutotune({select:l.value.trim(),from:w.value.trim()||null,to:p.value.trim()||null}),I.onclick=()=>{let T=l.value.trim();window.confirm(`Unlock the pipeline lock for "${T}"? Only do this if you're sure no dtk process is actually running against it.`)&&t.submitUnlock({select:T})};function E(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=E,n.onclick=E,e.append(n,r),{el:r,open(T){T&&(l.value=T),n.classList.add("open"),r.classList.add("open"),J()},close:E,isOpen(){return r.classList.contains("open")},refreshOptions(){m.innerHTML=["*",...t.getSelectOptions()].map(T=>`<option value="${O(T)}"></option>`).join("")},refreshBusyState:J,resetLog(){U=[],B(),X.textContent="",X.className="dtk-ui-log-line"},appendLog(T){if(T.length===0)return;let Y=le();U.push(...T),B(),Y&&(K.scrollTop=K.scrollHeight)},setLogStatus(T,Y){if(T==="running")return;let W=T==="done"&&Y===0?"exit-ok":T==="stopped"?"exit-stop":"exit-fail";X.className=`dtk-ui-log-line ${W}`,X.textContent=`\u2500\u2500 ${T} (exit ${Y!=null?Y:"?"}) \u2500\u2500`}}}function un(e){return e==="done"?"var(--st-recovery)":e==="failed"?"var(--st-anomaly)":e==="running"?"var(--clay)":"var(--faint)"}function $t(e,t){let n=document.createElement("div");n.className="dtk-ui-drawer-backdrop";let r=document.createElement("div");r.className="dtk-ui-drawer";let i=document.createElement("div");i.className="dtk-ui-drawer-head",i.innerHTML='<span class="dtk-ui-drawer-title">Jobs</span>';let o=document.createElement("button");o.type="button",o.className="dtk-ui-drawer-close",o.textContent="\u2715",i.appendChild(o),r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-drawer-body",r.appendChild(a);let s=document.createElement("div");s.className="dtk-ui-joblist",a.appendChild(s);function m(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=m,n.onclick=m,e.append(n,r),{el:r,open(){n.classList.add("open"),r.classList.add("open")},close:m,isOpen(){return r.classList.contains("open")},render(l,u,h){var f;if(l.length===0){s.innerHTML='<div class="dtk-ui-empty">No jobs yet.</div>';return}s.innerHTML="";for(let c of l){let v=document.createElement("div");v.className="dtk-ui-jobrow"+(c.id===h?" active":"");let w=c.status==="running"?" pulse":"",M=nt(c.started_at,(f=c.finished_at)!=null?f:u),p=document.createElement("div");p.className="dtk-ui-jobrow-top",p.innerHTML=`<span class="dtk-ui-jobrow-status"><span class="dtk-ui-jobrow-dot${w}" style="background:${un(c.status)}"></span>${O(c.kind)} \xB7 ${O(c.status)}</span><span class="dtk-ui-jobrow-meta">${O($e(u,c.started_at))} \xB7 ${O(M)}</span>`,v.appendChild(p);let x=document.createElement("div");x.className="dtk-ui-jobrow-label",x.textContent=c.label,v.appendChild(x);let b=document.createElement("div");if(b.className="dtk-ui-jobrow-actions",c.status==="running"){let k=document.createElement("button");k.type="button",k.className="dtk-ui-actionbtn",k.textContent="Stop",k.onclick=g=>{g.stopPropagation(),t.onStop(c.id)},b.appendChild(k)}if(c.kind==="tune"&&c.url){let k=document.createElement("a");k.className="dtk-ui-joblink",k.href=c.url,k.target="_blank",k.rel="noopener",k.textContent="Open tuner",k.onclick=g=>g.stopPropagation(),b.appendChild(k)}b.childElementCount>0&&v.appendChild(b),v.onclick=()=>t.onFollow(c.id),s.appendChild(v)}}}}var pn=/^(true|false|null|yes|no|on|off|~)$/i,mn=/^[A-Za-z0-9_][A-Za-z0-9_.\-]*$/,fn=/^[-+.]?\d/;function Ot(e){return!(!mn.test(e)||pn.test(e)||!Number.isNaN(Number(e))||fn.test(e))}function Le(e){return JSON.stringify(e)}function bn(e){var o;let r=(e.endsWith(`
462
462
  `)?e.slice(0,-1):e).split(`
463
463
  `),i=(o=r[0])!=null?o:"";return!(i.length===0||/^\s/.test(i)||r.some(a=>a.trim().length===0))}function gn(e,t){let n=e.endsWith(`
464
464
  `),i=(n?e.slice(0,-1):e).split(`
465
- `).map(o=>t+o);return{indicator:n?"|":"|-",lines:i}}function It(e){if(typeof e=="string")return Ot(e)?e:Le(e);if(typeof e=="number"){if(!Number.isFinite(e))return Le(String(e));let t=String(e),n=t.indexOf("e");return n>0&&!t.slice(0,n).includes(".")?`${t.slice(0,n)}.0${t.slice(n)}`:t}return typeof e=="boolean"?e?"true":"false":e===null?"null":Le(String(e))}function hn(e){return Ot(e)?e:Le(e)}function At(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function We(e){let t={};for(let[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}function Pt(e,t,n){if(bn(t)){let{indicator:r,lines:i}=gn(t,n);return[`${e}${r}`,...i]}return[`${e}${Le(t)}`]}function Qe(e,t){let n=[],r=t+" ";for(let[i,o]of Object.entries(e)){if(o===void 0)continue;let a=hn(i);if(o===null)n.push(`${t}${a}: null`);else if(Array.isArray(o))o.length===0?n.push(`${t}${a}: []`):(n.push(`${t}${a}:`),n.push(...Ht(o,r)));else if(At(o)){let s=We(o);Object.keys(s).length===0?n.push(`${t}${a}: {}`):(n.push(`${t}${a}:`),n.push(...Qe(s,r)))}else typeof o=="string"&&o.includes(`
466
- `)?n.push(...Pt(`${t}${a}: `,o,r)):n.push(`${t}${a}: ${It(o)}`)}return n}function Ht(e,t){let n=[],r=t+" ";for(let i of e)if(i===null)n.push(`${t}- null`);else if(Array.isArray(i))i.length===0?n.push(`${t}- []`):(n.push(`${t}-`),n.push(...Ht(i,r)));else if(At(i)){let o=We(i);if(Object.keys(o).length===0)n.push(`${t}- {}`);else{let a=Qe(o,r);n.push(`${t}- ${a[0].slice(r.length)}`),n.push(...a.slice(1))}}else typeof i=="string"&&i.includes(`
465
+ `).map(o=>t+o);return{indicator:n?"|":"|-",lines:i}}function It(e){if(typeof e=="string")return Ot(e)?e:Le(e);if(typeof e=="number"){if(!Number.isFinite(e))return Le(String(e));let t=String(e),n=t.indexOf("e");return n>0&&!t.slice(0,n).includes(".")?`${t.slice(0,n)}.0${t.slice(n)}`:t}return typeof e=="boolean"?e?"true":"false":e===null?"null":Le(String(e))}function hn(e){return Ot(e)?e:Le(e)}function At(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function We(e){let t={};for(let[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}function Pt(e,t,n){if(bn(t)){let{indicator:r,lines:i}=gn(t,n);return[`${e}${r}`,...i]}return[`${e}${Le(t)}`]}function Ve(e,t){let n=[],r=t+" ";for(let[i,o]of Object.entries(e)){if(o===void 0)continue;let a=hn(i);if(o===null)n.push(`${t}${a}: null`);else if(Array.isArray(o))o.length===0?n.push(`${t}${a}: []`):(n.push(`${t}${a}:`),n.push(...Ht(o,r)));else if(At(o)){let s=We(o);Object.keys(s).length===0?n.push(`${t}${a}: {}`):(n.push(`${t}${a}:`),n.push(...Ve(s,r)))}else typeof o=="string"&&o.includes(`
466
+ `)?n.push(...Pt(`${t}${a}: `,o,r)):n.push(`${t}${a}: ${It(o)}`)}return n}function Ht(e,t){let n=[],r=t+" ";for(let i of e)if(i===null)n.push(`${t}- null`);else if(Array.isArray(i))i.length===0?n.push(`${t}- []`):(n.push(`${t}-`),n.push(...Ht(i,r)));else if(At(i)){let o=We(i);if(Object.keys(o).length===0)n.push(`${t}- {}`);else{let a=Ve(o,r);n.push(`${t}- ${a[0].slice(r.length)}`),n.push(...a.slice(1))}}else typeof i=="string"&&i.includes(`
467
467
  `)?n.push(...Pt(`${t}- `,i,r)):n.push(`${t}- ${It(i)}`);return n}function jt(e,t){let n=[];if(t)for(let i of t)for(let o of i.split(`
468
- `))n.push(`# ${o}`);let r=We(e);return Object.keys(r).length===0?n.push("{}"):n.push(...Qe(r,"")),n.join(`
468
+ `))n.push(`# ${o}`);let r=We(e);return Object.keys(r).length===0?n.push("{}"):n.push(...Ve(r,"")),n.join(`
469
469
  `)+`
470
- `}var vn=new Set("SELECT FROM WHERE GROUP BY ORDER HAVING JOIN LEFT RIGHT INNER OUTER FULL CROSS ON AS AND OR NOT IN IS BETWEEN LIKE CASE WHEN THEN ELSE END LIMIT OFFSET WITH UNION ALL DISTINCT INTERVAL SECOND MINUTE HOUR DAY CAST NULL TRUE FALSE INSERT UPDATE DELETE SET VALUES OVER PARTITION DESC ASC".split(/\s+/)),Ve=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/g,Ge=/(--[^\n]*|\/\*[\s\S]*?\*\/)|('(?:''|[^'])*')|(\b\d+(?:\.\d+)?\b)|([A-Za-z_][A-Za-z0-9_]*)/g;function qt(e){let t=[],n=0;Ge.lastIndex=0;let r;for(;r=Ge.exec(e);){r.index>n&&t.push({start:n,end:r.index,cls:null});let i=r.index,o=Ge.lastIndex;if(r[1]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-cmt"});else if(r[2]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-str"});else if(r[3]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-num"});else if(r[4]!==void 0){let a=r[4],s;vn.has(a.toUpperCase())?s="dtk-sql-kw":/^\s*\(/.test(e.slice(o))?s="dtk-sql-fn":s=null,t.push({start:i,end:o,cls:s})}n=o}return n<e.length&&t.push({start:n,end:e.length,cls:null}),t}function yn(e){let t=[];Ve.lastIndex=0;let n;for(;n=Ve.exec(e);)t.push({start:n.index,end:Ve.lastIndex,text:n[0]});if(t.length===0)return qt(e).map(s=>({text:e.slice(s.start,s.end),cls:s.cls}));let r=e;for(let s of t)r=r.slice(0,s.start)+"_".repeat(s.end-s.start)+r.slice(s.end);let i=qt(r),o=[],a=0;for(let s of i){let f=s.start;for(;a<t.length&&t[a].start<s.end;){let l=t[a];l.start>f&&o.push({text:e.slice(f,l.start),cls:s.cls}),o.push({text:l.text,cls:"dtk-sql-jinja"}),f=l.end,a++}f<s.end&&o.push({text:e.slice(f,s.end),cls:s.cls})}return o}function kn(e){return yn(e).map(n=>n.cls?`<span class="${n.cls}">${O(n.text)}</span>`:O(n.text)).join("")+`
471
- `}function Ft(e){let t=document.createElement("div");t.className="dtk-ui-sqled";let n=document.createElement("pre");n.className="dtk-ui-sqled-hl",n.setAttribute("aria-hidden","true");let r=document.createElement("code");n.appendChild(r);let i=document.createElement("textarea");i.className="dtk-ui-sqled-ta",i.spellcheck=!1,i.autocapitalize="off",e.ariaLabel&&i.setAttribute("aria-label",e.ariaLabel),t.append(n,i);function o(f){r.innerHTML=kn(f)}function a(){n.scrollTop=i.scrollTop,n.scrollLeft=i.scrollLeft}i.value=e.value,o(e.value),i.addEventListener("input",()=>{o(i.value),a(),e.onInput(i.value)}),i.addEventListener("scroll",a),i.addEventListener("keydown",f=>{if(f.key!=="Tab")return;f.preventDefault();let l=i.selectionStart,p=i.selectionEnd,h=i.value;i.value=`${h.slice(0,l)} ${h.slice(p)}`,i.selectionStart=i.selectionEnd=l+2,o(i.value),a(),e.onInput(i.value)});let s=null;return{el:t,getValue:()=>i.value,setValue:f=>{i.value=f,o(f),a()},setDisabled:(f,l)=>{i.disabled=f,f&&l?(s||(s=document.createElement("div"),s.className="dtk-ui-sqled-note",t.appendChild(s)),s.textContent=l,s.hidden=!1):s&&(s.hidden=!0)},focus:()=>i.focus()}}function $(e,t){let n=document.createElement(e);return t&&(n.className=t),n}function j(e,t,n){let r=$("div","dtk-ui-field"),i=$("span","dtk-ui-field-label");if(i.textContent=e,r.append(i,t),n){let o=$("div","dtk-ui-editor-hint");o.textContent=n,r.appendChild(o)}return r}function xe(e){let t=$("div","dtk-ui-form-sec"),n=$("div","dtk-ui-form-sec-head"),r=$("span","dtk-ui-form-sec-title");r.textContent=e,n.appendChild(r),t.appendChild(n);let i=$("div","dtk-ui-form-sec-body");return t.appendChild(i),{root:t,body:i}}function Ut(e){let t=document.createElement("details");t.className="dtk-ui-form-adv";let n=document.createElement("summary");n.className="dtk-ui-form-adv-summary",n.textContent=e,t.appendChild(n);let r=$("div","dtk-ui-form-adv-body");return t.appendChild(r),{details:t,body:r}}function Me(e,t,n){let r=$("div","dtk-ui-chipinput"),i=$("div","dtk-ui-chipinput-chips"),o=document.createElement("input");o.type="text",o.className="dtk-ui-chipinput-field",o.placeholder=t,r.append(i,o);let a=[...e];function s(){i.innerHTML="";for(let l of a){let p=$("span","dtk-ui-chip"),h=document.createElement("span");h.textContent=l;let m=document.createElement("button");m.type="button",m.className="dtk-ui-chip-x",m.textContent="\u2715",m.title=`remove ${l}`,m.onclick=()=>{a=a.filter(c=>c!==l),s(),n()},p.append(h,m),i.appendChild(p)}}s();function f(){let l=o.value.trim();o.value="",!(!l||a.includes(l))&&(a.push(l),s(),n())}return o.addEventListener("keydown",l=>{l.key==="Enter"&&(l.preventDefault(),f())}),o.addEventListener("blur",f),{el:r,get:()=>[...a],set:l=>{a=[...l],s()}}}function je(e){let t=e.trim();return/^\d+$/.test(t)?Number(t):t}var xn=new Set(["name","description","tags","profile","ai_context","query","query_file","query_columns","interval","loading_start_time","loading_delay","loading_batch_size","seasonality_columns","detectors","alerting","enabled"]);function wn(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e))xn.has(n)||(t[n]=r);return t}function En(e){let{root:t,body:n}=xe("Preserved fields"),r=$("div","dtk-ui-editor-hint");r.textContent="These config keys aren't editable in the Builder \u2014 they round-trip untouched. Use the YAML tab to change them.",n.appendChild(r);let i=$("div","dtk-ui-preschips");for(let o of Object.keys(e)){let a=$("span","dtk-ui-preschip");a.textContent=o,i.appendChild(a)}return n.appendChild(i),t}var zt=/^[A-Za-z0-9_-]+$/;function Cn(e,t,n){let{root:r,body:i}=xe("Basics"),o=document.createElement("input");o.type="text",o.className="dtk-ui-input",o.placeholder="my_metric",o.value=typeof(e==null?void 0:e.name)=="string"?e.name:"";let a=$("div","dtk-ui-form-err-inline");function s(){let x=o.value.trim();a.textContent=x===""||zt.test(x)?"":"letters, digits, _ and - only"}o.oninput=()=>{s(),n.onDirty()},s();let f=j("Name",o);f.appendChild(a),i.appendChild(f);let l=document.createElement("textarea");l.className="dtk-ui-input dtk-ui-textarea",l.rows=3,l.value=typeof(e==null?void 0:e.description)=="string"?e.description:"",l.oninput=()=>n.onDirty(),i.appendChild(j("Description",l));let p=Array.isArray(e==null?void 0:e.tags)?e.tags.map(String):[],h=Me(p,"add tag, Enter",()=>n.onDirty());i.appendChild(j("Tags",h.el));let m=document.createElement("select");m.className="dtk-ui-select";let c=document.createElement("option");c.value="",c.textContent="(project default)",m.appendChild(c);let v=typeof(e==null?void 0:e.profile)=="string"?e.profile:"",w=v&&!t.profiles.includes(v)?[v,...t.profiles]:t.profiles;for(let x of w){let b=document.createElement("option");b.value=x,b.textContent=x,m.appendChild(b)}m.value=v,m.onchange=()=>n.onDirty(),i.appendChild(j("Profile",m));let M=document.createElement("label");M.className="dtk-ui-check";let u=document.createElement("input");return u.type="checkbox",u.checked=(e==null?void 0:e.enabled)!==!1,u.onchange=()=>n.onDirty(),M.append(u,document.createTextNode("Enabled")),i.appendChild(M),{el:r,getName:()=>o.value.trim(),getDescription:()=>l.value,getTags:()=>h.get(),getEnabled:()=>u.checked,getProfile:()=>m.value.trim(),setName:x=>{o.value=x,s()},setDescription:x=>{l.value=x},focusName:()=>o.focus(),issues:()=>{let x=o.value.trim();return x===""?["name is required"]:zt.test(x)?[]:["name has invalid characters (use letters, digits, _ or -)"]}}}var Sn=["10min","1h","1d"],Mn=/^\d+(s|sec|secs|second|seconds|min|mins|minute|minutes|h|hr|hour|hours|d|day|days)?$/i;function Tn(e,t){let{root:n,body:r}=xe("Schedule & loading"),i=document.createElement("input");i.type="text",i.className="dtk-ui-input",i.placeholder="1h",i.value=(e==null?void 0:e.interval)!==void 0&&(e==null?void 0:e.interval)!==null?String(e.interval):"1h";let o=$("div","dtk-ui-form-err-inline");function a(){let g=i.value.trim();o.textContent=g===""||Mn.test(g)?"":"looks unusual \u2014 the server validates on save"}i.oninput=()=>{a(),t.onDirty()},a();let s=j("Interval",i),f=$("div","dtk-ui-chip-presets");for(let g of Sn){let S=document.createElement("button");S.type="button",S.className="dtk-ui-chip-preset",S.textContent=g,S.onclick=()=>{i.value=g,a(),t.onDirty()},f.appendChild(S)}s.appendChild(f),s.appendChild(o),r.appendChild(s);let l=document.createElement("input");l.type="text",l.className="dtk-ui-input",l.placeholder="YYYY-MM-DD HH:MM:SS",l.value=typeof(e==null?void 0:e.loading_start_time)=="string"?e.loading_start_time:"",l.oninput=()=>t.onDirty(),r.appendChild(j("Loading start time",l));let p=e!=null&&e.query_columns&&typeof e.query_columns=="object"?e.query_columns:{},h=typeof(e==null?void 0:e.loading_batch_size)=="number"?e.loading_batch_size:null,m=(e==null?void 0:e.loading_delay)!==void 0||h!==null&&h!==1e4||Object.keys(p).length>0,c=Ut("Advanced");c.details.open=m,r.appendChild(c.details);let v=document.createElement("input");v.type="text",v.className="dtk-ui-input",v.placeholder="e.g. 10min (optional)",v.value=(e==null?void 0:e.loading_delay)!==void 0&&(e==null?void 0:e.loading_delay)!==null?String(e.loading_delay):"",v.oninput=()=>t.onDirty(),c.body.appendChild(j("Loading delay",v,"Data-maturity delay before the newest interval is trusted complete."));let w=document.createElement("input");w.type="number",w.min="1",w.className="dtk-ui-input",w.placeholder="10000",w.value=h!==null&&h!==1e4?String(h):"",w.oninput=()=>t.onDirty(),c.body.appendChild(j("Loading batch size",w));let M=document.createElement("input");M.type="text",M.className="dtk-ui-input",M.placeholder="timestamp",M.value=typeof p.timestamp=="string"?p.timestamp:"",M.oninput=()=>t.onDirty();let u=document.createElement("input");u.type="text",u.className="dtk-ui-input",u.placeholder="value",u.value=typeof p.metric=="string"?p.metric:"",u.oninput=()=>t.onDirty();let x=$("div","dtk-ui-row2");x.append(j("Timestamp column",M),j("Value column",u)),c.body.appendChild(x);let b=Array.isArray(p.seasonality)?p.seasonality.map(String):[],k=Me(b,"add query column name, Enter",()=>t.onDirty());return c.body.appendChild(j("Seasonality columns (in query results)",k.el)),{el:n,getInterval:()=>i.value.trim(),getLoadingStartTime:()=>l.value.trim(),getLoadingDelay:()=>v.value.trim(),getLoadingBatchSize:()=>{let g=w.value.trim();if(!g)return null;let S=Math.round(Number(g));return Number.isFinite(S)&&S!==1e4?S:null},getQueryColumns:()=>{let g=M.value.trim(),S=u.value.trim(),N=k.get();if(!g&&!S&&N.length===0)return null;let L={};return g&&(L.timestamp=g),S&&(L.metric=S),N.length>0&&(L.seasonality=N),L},issues:()=>i.value.trim()===""?["interval is required"]:[]}}var Xe=[{key:"hour",label:"Hour"},{key:"day_of_week",label:"Day of week"},{key:"day_of_month",label:"Day of month"},{key:"month",label:"Month"},{key:"is_weekend",label:"Weekend"},{key:"is_holiday",label:"Holiday"}];function Nn(e,t){let{root:n,body:r}=xe("Seasonality"),i=new Set(Array.isArray(e==null?void 0:e.seasonality_columns)?e.seasonality_columns.map(String):[]),o={},a=$("div","dtk-ui-checks");for(let{key:s,label:f}of Xe){let l=document.createElement("label");l.className="dtk-ui-check";let p=document.createElement("input");p.type="checkbox",p.checked=i.has(s),p.onchange=()=>t.onDirty(),l.append(p,document.createTextNode(f)),a.appendChild(l),o[s]=p}return r.appendChild(a),{el:n,getColumns:()=>Xe.filter(s=>o[s.key].checked).map(s=>s.key),setColumns:s=>{let f=new Set(s);for(let{key:l}of Xe)o[l].checked=f.has(l)}}}var Yt=["mad","zscore","iqr","autoreg","manual_bounds"];function _e(e){return Yt.includes(e)}var De={mad:["threshold","window_size"],zscore:["threshold","window_size"],iqr:["threshold","window_size"],autoreg:["threshold","window_size","lags"],manual_bounds:["lower_bound","upper_bound"]},Rn={threshold:"Threshold",window_size:"Window size",lags:"Lags",lower_bound:"Lower bound",upper_bound:"Upper bound"},Ln={mad:{threshold:"3.0",window_size:"100"},zscore:{threshold:"3.0",window_size:"100"},iqr:{threshold:"3.0",window_size:"100"},autoreg:{threshold:"3.0",window_size:"200",lags:"5"},manual_bounds:{}};function Ze(e){let t=e&&typeof e=="object"?{...e}:{},n=typeof t.type=="string"?t.type:"";if(!_e(n))return{type:n,raw:t,extraParams:{},extrasOwner:n,fields:{}};let r=t.params&&typeof t.params=="object"?t.params:{},i=new Set(De[n]),o={};for(let[s,f]of Object.entries(r))i.has(s)||(o[s]=f);let a={};for(let s of De[n]){let f=r[s];f!=null&&(a[s]=String(f))}return{type:n,raw:t,extraParams:o,extrasOwner:n,fields:a}}function _n(e){if(!_e(e.type))return e.raw;let t=De[e.type],n=new Set(t),r={};if(e.type===e.extrasOwner)for(let[i,o]of Object.entries(e.extraParams))n.has(i)||(r[i]=o);for(let i of t){let o=e.fields[i];if(o===void 0||o.trim()==="")continue;let a=Number(o);r[i]=Number.isFinite(a)?a:o}return{type:e.type,params:r}}function Dn(e,t,n){let{root:r,body:i}=xe("Detectors"),o=$("div","dtk-ui-editor-hint");o.textContent="Defaults are a fine start \u2014 load data, then fine-tune in the tune cockpit (Tune button on the metric row).",i.appendChild(o);let a=$("div","dtk-ui-detrows");i.appendChild(a);let s=document.createElement("button");s.type="button",s.className="dtk-ui-btn",s.textContent="+ Add detector",i.appendChild(s);let f=Array.isArray(e==null?void 0:e.detectors)?e.detectors:[],l=f.length>0?f.map(Ze):n==="create"?[Ze({type:"mad",params:{threshold:3,window_size:100}})]:[];function p(m){var M,u,x;let c=$("div","dtk-ui-detrow"),v=$("div","dtk-ui-detrow-head");if(_e(m.type)){let b=document.createElement("select");b.className="dtk-ui-select";for(let k of Yt){let g=document.createElement("option");g.value=k,g.textContent=k,b.appendChild(g)}b.value=m.type,b.onchange=()=>{let k=b.value;if(!_e(k))return;let g={};for(let S of De[k])m.fields[S]!==void 0&&(g[S]=m.fields[S]);m.type=k,m.fields=g,t.onDirty(),h()},v.appendChild(b)}else{let b=$("span","dtk-ui-detrow-readonly");b.textContent=`${m.type||"unknown type"} \u2014 preserved as-is, edit in the YAML tab`,v.appendChild(b)}let w=document.createElement("button");if(w.type="button",w.className="dtk-ui-detrow-remove",w.textContent="\u2715",w.title="Remove detector",w.onclick=()=>{l=l.filter(b=>b!==m),t.onDirty(),h()},v.appendChild(w),c.appendChild(v),_e(m.type)){let b=$("div","dtk-ui-detrow-fields"),k=De[m.type];for(let N of k){let L=document.createElement("input");L.type="number",L.step="any",L.className="dtk-ui-input",L.placeholder=(M=Ln[m.type][N])!=null?M:"",L.value=(u=m.fields[N])!=null?u:"",L.oninput=()=>{m.fields[N]=L.value,t.onDirty()},b.appendChild(j((x=Rn[N])!=null?x:N,L))}c.appendChild(b);let g=new Set(k),S=Object.keys(m.extraParams).filter(N=>!g.has(N)).length;if(S>0){let N=$("span","dtk-ui-preschip");N.textContent=m.type===m.extrasOwner?`+${S} params preserved`:`${S} ${m.extrasOwner} param(s) withheld \u2014 switch the type back to restore`,c.appendChild(N)}}return c}function h(){a.innerHTML="";for(let m of l)a.appendChild(p(m))}return h(),s.onclick=()=>{l.push(Ze({type:"mad",params:{threshold:3,window_size:100}})),t.onDirty(),h()},{el:r,getData:()=>l.map(_n),issues:()=>{let m=[];for(let c of l)if(c.type==="manual_bounds"){let v=c.fields.lower_bound,w=c.fields.upper_bound;(!v||v.trim()==="")&&(!w||w.trim()==="")&&m.push("a manual_bounds detector needs at least a lower or upper bound")}return m}}}var Bt=new Set(["enabled","channels","consecutive_anomalies","direction","no_data_alert","notify_on_recovery","alert_cooldown","min_detectors","anomaly_window","min_anomaly_share","mentions","dashboard_url"]);function $n(e){let t=e==null?void 0:e.alerting;return t==null?{mode:"none",block:{}}:Array.isArray(t)?t.length>1?{mode:"verbatim",block:{},verbatim:t}:t.length===1&&t[0]&&typeof t[0]=="object"?{mode:"single",block:t[0]}:{mode:"none",block:{}}:typeof t=="object"?{mode:"single",block:t}:{mode:"none",block:{}}}function On(e,t,n){let{root:r,body:i}=xe("Alerting"),o=$n(e);if(o.mode==="verbatim"){let E=$("div","dtk-ui-form-warn");return E.textContent="Multiple alerting configs \u2014 edit them in the YAML tab.",i.appendChild(E),{el:r,getData:()=>o.verbatim,issues:()=>[]}}let a=o.block,s={};for(let[E,T]of Object.entries(a))Bt.has(E)||(s[E]=T);let f=document.createElement("label");f.className="dtk-ui-check";let l=document.createElement("input");l.type="checkbox",l.checked=o.mode==="single",f.append(l,document.createTextNode("Alerting")),i.appendChild(f);let p=$("div","dtk-ui-alerting-fields");i.appendChild(p);let h=document.createElement("label");h.className="dtk-ui-check";let m=document.createElement("input");m.type="checkbox",m.checked=a.enabled!==!1,m.onchange=()=>n.onDirty(),h.append(m,document.createTextNode("Enabled (uncheck to keep the config but pause sending)")),p.appendChild(h);let c=new Set(t.channels.map(E=>E.name)),v=Array.isArray(a.channels)?a.channels.map(String):[],w=new Set(v.filter(E=>c.has(E))),M=v.filter(E=>!c.has(E)),u=$("div","dtk-ui-field"),x=$("span","dtk-ui-field-label");x.textContent="Channels",u.appendChild(x);let b=$("div","dtk-ui-checks");for(let E of t.channels){let T=document.createElement("label");T.className="dtk-ui-check";let Y=document.createElement("input");Y.type="checkbox",Y.checked=w.has(E.name),Y.onchange=()=>{Y.checked?w.add(E.name):w.delete(E.name),n.onDirty()};let W=$("span","dtk-ui-check-type");W.textContent=`(${E.type})`,T.append(Y,document.createTextNode(E.name+" "),W),b.appendChild(T)}u.appendChild(b);let k=Me(M,"add channel name, Enter",()=>n.onDirty());u.appendChild(k.el),p.appendChild(u);let g=document.createElement("input");g.type="number",g.min="1",g.step="1",g.className="dtk-ui-input",g.value=String(typeof a.consecutive_anomalies=="number"?a.consecutive_anomalies:3),g.oninput=()=>n.onDirty(),p.appendChild(j("Consecutive anomalies",g));let S=document.createElement("select");S.className="dtk-ui-select";for(let E of["same","any","up","down"]){let T=document.createElement("option");T.value=E,T.textContent=E,S.appendChild(T)}S.value=typeof a.direction=="string"?a.direction:"same",S.onchange=()=>n.onDirty(),p.appendChild(j("Direction",S));let N=document.createElement("label");N.className="dtk-ui-check";let L=document.createElement("input");L.type="checkbox",L.checked=a.no_data_alert===!0,L.onchange=()=>n.onDirty(),N.append(L,document.createTextNode("Alert on missing data")),p.appendChild(N);let _=document.createElement("label");_.className="dtk-ui-check";let A=document.createElement("input");A.type="checkbox",A.checked=a.notify_on_recovery===!0,A.onchange=()=>n.onDirty(),_.append(A,document.createTextNode("Notify on recovery")),p.appendChild(_);let I=document.createElement("input");I.type="text",I.className="dtk-ui-input",I.placeholder="e.g. 30min (optional)",I.value=a.alert_cooldown!==void 0&&a.alert_cooldown!==null?String(a.alert_cooldown):"",I.oninput=()=>n.onDirty(),p.appendChild(j("Alert cooldown",I));let z=a.min_detectors!==void 0||a.anomaly_window!==void 0||a.min_anomaly_share!==void 0||Array.isArray(a.mentions)&&a.mentions.length>0||!!a.dashboard_url,K=Ut("Advanced");K.details.open=z,p.appendChild(K.details);let q=document.createElement("input");q.type="number",q.min="1",q.step="1",q.className="dtk-ui-input",q.value=String(typeof a.min_detectors=="number"?a.min_detectors:1),q.oninput=()=>n.onDirty(),K.body.appendChild(j("Min detectors",q));let G=$("div","dtk-ui-row2"),U=document.createElement("input");U.type="text",U.className="dtk-ui-input",U.placeholder="e.g. 30min",U.value=a.anomaly_window!==void 0&&a.anomaly_window!==null?String(a.anomaly_window):"",U.oninput=()=>n.onDirty();let B=document.createElement("input");B.type="number",B.min="0",B.max="1",B.step="0.05",B.className="dtk-ui-input",B.placeholder="e.g. 0.3",B.value=typeof a.min_anomaly_share=="number"?String(a.min_anomaly_share):"",B.oninput=()=>n.onDirty(),G.append(j("Anomaly window",U),j("Min anomaly share",B)),K.body.appendChild(G);let le=Array.isArray(a.mentions)?a.mentions.map(String):[],ne=Me(le,"add mention, Enter",()=>n.onDirty());K.body.appendChild(j("Mentions",ne.el));let J=document.createElement("input");if(J.type="text",J.className="dtk-ui-input",J.placeholder="https://\u2026",J.value=typeof a.dashboard_url=="string"?a.dashboard_url:"",J.oninput=()=>n.onDirty(),K.body.appendChild(j("Dashboard URL",J)),Object.keys(s).length>0){let E=$("span","dtk-ui-preschip");E.textContent=`+${Object.keys(s).length} fields preserved`,p.appendChild(E)}function V(){p.style.display=l.checked?"":"none"}return l.onchange=()=>{V(),n.onDirty()},V(),{el:r,getData:()=>{if(!l.checked)return;let E={enabled:m.checked},T=[...t.channels.filter(F=>w.has(F.name)).map(F=>F.name),...k.get()];T.length>0&&(E.channels=T);let Y=Number(g.value);E.consecutive_anomalies=g.value.trim()!==""&&Number.isFinite(Y)?Math.max(1,Math.round(Y)):3,E.direction=S.value,E.no_data_alert=L.checked,E.notify_on_recovery=A.checked;let W=I.value.trim();W&&(E.alert_cooldown=je(W));let Q=Number(q.value),oe=q.value.trim()!==""&&Number.isFinite(Q)?Math.max(1,Math.round(Q)):1;oe!==1&&(E.min_detectors=oe);let me=U.value.trim(),D=B.value.trim();me&&D&&(E.anomaly_window=je(me),E.min_anomaly_share=Number(D));let X=ne.get();X.length>0&&(E.mentions=X);let ie=J.value.trim();ie&&(E.dashboard_url=ie);for(let[F,ee]of Object.entries(s))Bt.has(F)||(E[F]=ee);return E},issues:()=>{if(!l.checked)return[];let E=U.value.trim(),T=B.value.trim();return E===""!=(T==="")?["anomaly window and min anomaly share must be set together"]:[]}}}function Jt(e){if(typeof e=="string")return{instructions:e,synonyms:[],examples:[]};if(e&&typeof e=="object"){let t=e;return{instructions:typeof t.instructions=="string"?t.instructions:"",synonyms:Array.isArray(t.synonyms)?t.synonyms.map(String):[],examples:Array.isArray(t.examples)?t.examples.map(String):[]}}return{instructions:"",synonyms:[],examples:[]}}function In(e,t){let n=Jt(e==null?void 0:e.ai_context),{root:r,body:i}=xe("AI context"),o=document.createElement("details");o.className="dtk-ui-form-adv",o.open=!!(n.instructions||n.synonyms.length>0||n.examples.length>0);let a=document.createElement("summary");a.className="dtk-ui-form-adv-summary",a.textContent="Instructions / synonyms / examples",o.appendChild(a);let s=$("div","dtk-ui-form-adv-body");o.appendChild(s),i.appendChild(o);let f=document.createElement("textarea");f.className="dtk-ui-input dtk-ui-textarea",f.rows=3,f.placeholder="Business meaning / how to interpret this metric",f.value=n.instructions,f.oninput=()=>t.onDirty(),s.appendChild(j("Instructions",f));let l=Me(n.synonyms,"add synonym, Enter",()=>t.onDirty());s.appendChild(j("Synonyms",l.el));let p=Me(n.examples,"add example, Enter",()=>t.onDirty());return s.appendChild(j("Examples",p.el)),{el:r,getData:()=>{let h=f.value.trim(),m=l.get(),c=p.get();if(!h&&m.length===0&&c.length===0)return;let v={};return h&&(v.instructions=h),m.length>0&&(v.synonyms=m),c.length>0&&(v.examples=c),v},setData:h=>{let m=Jt(h!=null?h:null);f.value=m.instructions,l.set(m.synonyms),p.set(m.examples),(m.instructions||m.synonyms.length>0||m.examples.length>0)&&(o.open=!0)}}}var An=`SELECT
470
+ `}var vn=new Set("SELECT FROM WHERE GROUP BY ORDER HAVING JOIN LEFT RIGHT INNER OUTER FULL CROSS ON AS AND OR NOT IN IS BETWEEN LIKE CASE WHEN THEN ELSE END LIMIT OFFSET WITH UNION ALL DISTINCT INTERVAL SECOND MINUTE HOUR DAY CAST NULL TRUE FALSE INSERT UPDATE DELETE SET VALUES OVER PARTITION DESC ASC".split(/\s+/)),Qe=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/g,Ge=/(--[^\n]*|\/\*[\s\S]*?\*\/)|('(?:''|[^'])*')|(\b\d+(?:\.\d+)?\b)|([A-Za-z_][A-Za-z0-9_]*)/g;function qt(e){let t=[],n=0;Ge.lastIndex=0;let r;for(;r=Ge.exec(e);){r.index>n&&t.push({start:n,end:r.index,cls:null});let i=r.index,o=Ge.lastIndex;if(r[1]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-cmt"});else if(r[2]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-str"});else if(r[3]!==void 0)t.push({start:i,end:o,cls:"dtk-sql-num"});else if(r[4]!==void 0){let a=r[4],s;vn.has(a.toUpperCase())?s="dtk-sql-kw":/^\s*\(/.test(e.slice(o))?s="dtk-sql-fn":s=null,t.push({start:i,end:o,cls:s})}n=o}return n<e.length&&t.push({start:n,end:e.length,cls:null}),t}function yn(e){let t=[];Qe.lastIndex=0;let n;for(;n=Qe.exec(e);)t.push({start:n.index,end:Qe.lastIndex,text:n[0]});if(t.length===0)return qt(e).map(s=>({text:e.slice(s.start,s.end),cls:s.cls}));let r=e;for(let s of t)r=r.slice(0,s.start)+"_".repeat(s.end-s.start)+r.slice(s.end);let i=qt(r),o=[],a=0;for(let s of i){let m=s.start;for(;a<t.length&&t[a].start<s.end;){let l=t[a];l.start>m&&o.push({text:e.slice(m,l.start),cls:s.cls}),o.push({text:l.text,cls:"dtk-sql-jinja"}),m=l.end,a++}m<s.end&&o.push({text:e.slice(m,s.end),cls:s.cls})}return o}function kn(e){return yn(e).map(n=>n.cls?`<span class="${n.cls}">${O(n.text)}</span>`:O(n.text)).join("")+`
471
+ `}function Ft(e){let t=document.createElement("div");t.className="dtk-ui-sqled";let n=document.createElement("pre");n.className="dtk-ui-sqled-hl",n.setAttribute("aria-hidden","true");let r=document.createElement("code");n.appendChild(r);let i=document.createElement("textarea");i.className="dtk-ui-sqled-ta",i.spellcheck=!1,i.autocapitalize="off",e.ariaLabel&&i.setAttribute("aria-label",e.ariaLabel),t.append(n,i);function o(m){r.innerHTML=kn(m)}function a(){n.scrollTop=i.scrollTop,n.scrollLeft=i.scrollLeft}i.value=e.value,o(e.value),i.addEventListener("input",()=>{o(i.value),a(),e.onInput(i.value)}),i.addEventListener("scroll",a),i.addEventListener("keydown",m=>{if(m.key!=="Tab")return;m.preventDefault();let l=i.selectionStart,u=i.selectionEnd,h=i.value;i.value=`${h.slice(0,l)} ${h.slice(u)}`,i.selectionStart=i.selectionEnd=l+2,o(i.value),a(),e.onInput(i.value)});let s=null;return{el:t,getValue:()=>i.value,setValue:m=>{i.value=m,o(m),a()},setDisabled:(m,l)=>{i.disabled=m,m&&l?(s||(s=document.createElement("div"),s.className="dtk-ui-sqled-note",t.appendChild(s)),s.textContent=l,s.hidden=!1):s&&(s.hidden=!0)},focus:()=>i.focus()}}function $(e,t){let n=document.createElement(e);return t&&(n.className=t),n}function j(e,t,n){let r=$("div","dtk-ui-field"),i=$("span","dtk-ui-field-label");if(i.textContent=e,r.append(i,t),n){let o=$("div","dtk-ui-editor-hint");o.textContent=n,r.appendChild(o)}return r}function xe(e){let t=$("div","dtk-ui-form-sec"),n=$("div","dtk-ui-form-sec-head"),r=$("span","dtk-ui-form-sec-title");r.textContent=e,n.appendChild(r),t.appendChild(n);let i=$("div","dtk-ui-form-sec-body");return t.appendChild(i),{root:t,body:i}}function Ut(e){let t=document.createElement("details");t.className="dtk-ui-form-adv";let n=document.createElement("summary");n.className="dtk-ui-form-adv-summary",n.textContent=e,t.appendChild(n);let r=$("div","dtk-ui-form-adv-body");return t.appendChild(r),{details:t,body:r}}function Me(e,t,n){let r=$("div","dtk-ui-chipinput"),i=$("div","dtk-ui-chipinput-chips"),o=document.createElement("input");o.type="text",o.className="dtk-ui-chipinput-field",o.placeholder=t,r.append(i,o);let a=[...e];function s(){i.innerHTML="";for(let l of a){let u=$("span","dtk-ui-chip"),h=document.createElement("span");h.textContent=l;let f=document.createElement("button");f.type="button",f.className="dtk-ui-chip-x",f.textContent="\u2715",f.title=`remove ${l}`,f.onclick=()=>{a=a.filter(c=>c!==l),s(),n()},u.append(h,f),i.appendChild(u)}}s();function m(){let l=o.value.trim();o.value="",!(!l||a.includes(l))&&(a.push(l),s(),n())}return o.addEventListener("keydown",l=>{l.key==="Enter"&&(l.preventDefault(),m())}),o.addEventListener("blur",m),{el:r,get:()=>[...a],set:l=>{a=[...l],s()}}}function je(e){let t=e.trim();return/^\d+$/.test(t)?Number(t):t}var xn=new Set(["name","description","tags","profile","ai_context","query","query_file","query_columns","interval","loading_start_time","loading_delay","loading_batch_size","seasonality_columns","detectors","alerting","enabled"]);function wn(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e))xn.has(n)||(t[n]=r);return t}function En(e){let{root:t,body:n}=xe("Preserved fields"),r=$("div","dtk-ui-editor-hint");r.textContent="These config keys aren't editable in the Builder \u2014 they round-trip untouched. Use the YAML tab to change them.",n.appendChild(r);let i=$("div","dtk-ui-preschips");for(let o of Object.keys(e)){let a=$("span","dtk-ui-preschip");a.textContent=o,i.appendChild(a)}return n.appendChild(i),t}var zt=/^[\p{L}\p{N}_-]+$/u;function Cn(e,t,n){let{root:r,body:i}=xe("Basics"),o=document.createElement("input");o.type="text",o.className="dtk-ui-input",o.placeholder="my_metric",o.value=typeof(e==null?void 0:e.name)=="string"?e.name:e===null?"my_metric":"";let a=$("div","dtk-ui-form-err-inline");function s(){let x=o.value.trim();a.textContent=x===""||zt.test(x)?"":"letters, digits, _ and - only"}o.oninput=()=>{s(),n.onDirty()},s();let m=j("Name",o);m.appendChild(a),i.appendChild(m);let l=document.createElement("textarea");l.className="dtk-ui-input dtk-ui-textarea",l.rows=3,l.value=typeof(e==null?void 0:e.description)=="string"?e.description:"",l.oninput=()=>n.onDirty(),i.appendChild(j("Description",l));let u=Array.isArray(e==null?void 0:e.tags)?e.tags.map(String):[],h=Me(u,"add tag, Enter",()=>n.onDirty());i.appendChild(j("Tags",h.el));let f=document.createElement("select");f.className="dtk-ui-select";let c=document.createElement("option");c.value="",c.textContent="(project default)",f.appendChild(c);let v=typeof(e==null?void 0:e.profile)=="string"?e.profile:"",w=v&&!t.profiles.includes(v)?[v,...t.profiles]:t.profiles;for(let x of w){let b=document.createElement("option");b.value=x,b.textContent=x,f.appendChild(b)}f.value=v,f.onchange=()=>n.onDirty(),i.appendChild(j("Profile",f));let M=document.createElement("label");M.className="dtk-ui-check";let p=document.createElement("input");return p.type="checkbox",p.checked=(e==null?void 0:e.enabled)!==!1,p.onchange=()=>n.onDirty(),M.append(p,document.createTextNode("Enabled")),i.appendChild(M),{el:r,getName:()=>o.value.trim(),getDescription:()=>l.value,getTags:()=>h.get(),getEnabled:()=>p.checked,getProfile:()=>f.value.trim(),setName:x=>{o.value=x,s()},setDescription:x=>{l.value=x},focusName:()=>o.focus(),issues:()=>{let x=o.value.trim();return x===""?["name is required"]:zt.test(x)?[]:["name has invalid characters (use letters, digits, _ or -)"]}}}var Sn=["10min","1h","1d"],Mn=/^\d+(s|sec|secs|second|seconds|min|mins|minute|minutes|h|hr|hour|hours|d|day|days)?$/i;function Tn(e,t){let{root:n,body:r}=xe("Schedule & loading"),i=document.createElement("input");i.type="text",i.className="dtk-ui-input",i.placeholder="1h",i.value=(e==null?void 0:e.interval)!==void 0&&(e==null?void 0:e.interval)!==null?String(e.interval):"1h";let o=$("div","dtk-ui-form-err-inline");function a(){let g=i.value.trim();o.textContent=g===""||Mn.test(g)?"":"looks unusual \u2014 the server validates on save"}i.oninput=()=>{a(),t.onDirty()},a();let s=j("Interval",i),m=$("div","dtk-ui-chip-presets");for(let g of Sn){let S=document.createElement("button");S.type="button",S.className="dtk-ui-chip-preset",S.textContent=g,S.onclick=()=>{i.value=g,a(),t.onDirty()},m.appendChild(S)}s.appendChild(m),s.appendChild(o),r.appendChild(s);let l=document.createElement("input");l.type="text",l.className="dtk-ui-input",l.placeholder="YYYY-MM-DD HH:MM:SS",l.value=typeof(e==null?void 0:e.loading_start_time)=="string"?e.loading_start_time:"",l.oninput=()=>t.onDirty(),r.appendChild(j("Loading start time",l));let u=e!=null&&e.query_columns&&typeof e.query_columns=="object"?e.query_columns:{},h=typeof(e==null?void 0:e.loading_batch_size)=="number"?e.loading_batch_size:null,f=(e==null?void 0:e.loading_delay)!==void 0||h!==null&&h!==1e4||Object.keys(u).length>0,c=Ut("Advanced");c.details.open=f,r.appendChild(c.details);let v=document.createElement("input");v.type="text",v.className="dtk-ui-input",v.placeholder="e.g. 10min (optional)",v.value=(e==null?void 0:e.loading_delay)!==void 0&&(e==null?void 0:e.loading_delay)!==null?String(e.loading_delay):"",v.oninput=()=>t.onDirty(),c.body.appendChild(j("Loading delay",v,"Data-maturity delay before the newest interval is trusted complete."));let w=document.createElement("input");w.type="number",w.min="1",w.className="dtk-ui-input",w.placeholder="10000",w.value=h!==null&&h!==1e4?String(h):"",w.oninput=()=>t.onDirty(),c.body.appendChild(j("Loading batch size",w));let M=document.createElement("input");M.type="text",M.className="dtk-ui-input",M.placeholder="timestamp",M.value=typeof u.timestamp=="string"?u.timestamp:"",M.oninput=()=>t.onDirty();let p=document.createElement("input");p.type="text",p.className="dtk-ui-input",p.placeholder="value",p.value=typeof u.metric=="string"?u.metric:"",p.oninput=()=>t.onDirty();let x=$("div","dtk-ui-row2");x.append(j("Timestamp column",M),j("Value column",p)),c.body.appendChild(x);let b=Array.isArray(u.seasonality)?u.seasonality.map(String):[],k=Me(b,"add query column name, Enter",()=>t.onDirty());return c.body.appendChild(j("Seasonality columns (in query results)",k.el)),{el:n,getInterval:()=>i.value.trim(),getLoadingStartTime:()=>l.value.trim(),getLoadingDelay:()=>v.value.trim(),getLoadingBatchSize:()=>{let g=w.value.trim();if(!g)return null;let S=Math.round(Number(g));return Number.isFinite(S)&&S!==1e4?S:null},getQueryColumns:()=>{let g=M.value.trim(),S=p.value.trim(),N=k.get();if(!g&&!S&&N.length===0)return null;let L={};return g&&(L.timestamp=g),S&&(L.metric=S),N.length>0&&(L.seasonality=N),L},issues:()=>i.value.trim()===""?["interval is required"]:[]}}var Xe=[{key:"hour",label:"Hour"},{key:"day_of_week",label:"Day of week"},{key:"day_of_month",label:"Day of month"},{key:"month",label:"Month"},{key:"is_weekend",label:"Weekend"},{key:"is_holiday",label:"Holiday"}];function Nn(e,t){let{root:n,body:r}=xe("Seasonality"),i=new Set(Array.isArray(e==null?void 0:e.seasonality_columns)?e.seasonality_columns.map(String):[]),o={},a=$("div","dtk-ui-checks");for(let{key:s,label:m}of Xe){let l=document.createElement("label");l.className="dtk-ui-check";let u=document.createElement("input");u.type="checkbox",u.checked=i.has(s),u.onchange=()=>t.onDirty(),l.append(u,document.createTextNode(m)),a.appendChild(l),o[s]=u}return r.appendChild(a),{el:n,getColumns:()=>Xe.filter(s=>o[s.key].checked).map(s=>s.key),setColumns:s=>{let m=new Set(s);for(let{key:l}of Xe)o[l].checked=m.has(l)}}}var Yt=["mad","zscore","iqr","autoreg","manual_bounds"];function _e(e){return Yt.includes(e)}var De={mad:["threshold","window_size"],zscore:["threshold","window_size"],iqr:["threshold","window_size"],autoreg:["threshold","window_size","lags"],manual_bounds:["lower_bound","upper_bound"]},Rn={threshold:"Threshold",window_size:"Window size",lags:"Lags",lower_bound:"Lower bound",upper_bound:"Upper bound"},Ln={mad:{threshold:"3.0",window_size:"100"},zscore:{threshold:"3.0",window_size:"100"},iqr:{threshold:"3.0",window_size:"100"},autoreg:{threshold:"3.0",window_size:"200",lags:"5"},manual_bounds:{}};function Ze(e){let t=e&&typeof e=="object"?{...e}:{},n=typeof t.type=="string"?t.type:"";if(!_e(n))return{type:n,raw:t,extraParams:{},extrasOwner:n,fields:{}};let r=t.params&&typeof t.params=="object"?t.params:{},i=new Set(De[n]),o={};for(let[s,m]of Object.entries(r))i.has(s)||(o[s]=m);let a={};for(let s of De[n]){let m=r[s];m!=null&&(a[s]=String(m))}return{type:n,raw:t,extraParams:o,extrasOwner:n,fields:a}}function _n(e){if(!_e(e.type))return e.raw;let t=De[e.type],n=new Set(t),r={};if(e.type===e.extrasOwner)for(let[i,o]of Object.entries(e.extraParams))n.has(i)||(r[i]=o);for(let i of t){let o=e.fields[i];if(o===void 0||o.trim()==="")continue;let a=Number(o);r[i]=Number.isFinite(a)?a:o}return{type:e.type,params:r}}function Dn(e,t,n){let{root:r,body:i}=xe("Detectors"),o=$("div","dtk-ui-editor-hint");o.textContent="Defaults are a fine start \u2014 load data, then fine-tune in the tune cockpit (Tune button on the metric row).",i.appendChild(o);let a=$("div","dtk-ui-detrows");i.appendChild(a);let s=document.createElement("button");s.type="button",s.className="dtk-ui-btn",s.textContent="+ Add detector",i.appendChild(s);let m=Array.isArray(e==null?void 0:e.detectors)?e.detectors:[],l=m.length>0?m.map(Ze):n==="create"?[Ze({type:"mad",params:{threshold:3,window_size:100}})]:[];function u(f){var M,p,x;let c=$("div","dtk-ui-detrow"),v=$("div","dtk-ui-detrow-head");if(_e(f.type)){let b=document.createElement("select");b.className="dtk-ui-select";for(let k of Yt){let g=document.createElement("option");g.value=k,g.textContent=k,b.appendChild(g)}b.value=f.type,b.onchange=()=>{let k=b.value;if(!_e(k))return;let g={};for(let S of De[k])f.fields[S]!==void 0&&(g[S]=f.fields[S]);f.type=k,f.fields=g,t.onDirty(),h()},v.appendChild(b)}else{let b=$("span","dtk-ui-detrow-readonly");b.textContent=`${f.type||"unknown type"} \u2014 preserved as-is, edit in the YAML tab`,v.appendChild(b)}let w=document.createElement("button");if(w.type="button",w.className="dtk-ui-detrow-remove",w.textContent="\u2715",w.title="Remove detector",w.onclick=()=>{l=l.filter(b=>b!==f),t.onDirty(),h()},v.appendChild(w),c.appendChild(v),_e(f.type)){let b=$("div","dtk-ui-detrow-fields"),k=De[f.type];for(let N of k){let L=document.createElement("input");L.type="number",L.step="any",L.className="dtk-ui-input",L.placeholder=(M=Ln[f.type][N])!=null?M:"",L.value=(p=f.fields[N])!=null?p:"",L.oninput=()=>{f.fields[N]=L.value,t.onDirty()},b.appendChild(j((x=Rn[N])!=null?x:N,L))}c.appendChild(b);let g=new Set(k),S=Object.keys(f.extraParams).filter(N=>!g.has(N)).length;if(S>0){let N=$("span","dtk-ui-preschip");N.textContent=f.type===f.extrasOwner?`+${S} params preserved`:`${S} ${f.extrasOwner} param(s) withheld \u2014 switch the type back to restore`,c.appendChild(N)}}return c}function h(){a.innerHTML="";for(let f of l)a.appendChild(u(f))}return h(),s.onclick=()=>{l.push(Ze({type:"mad",params:{threshold:3,window_size:100}})),t.onDirty(),h()},{el:r,getData:()=>l.map(_n),issues:()=>{let f=[];for(let c of l)if(c.type==="manual_bounds"){let v=c.fields.lower_bound,w=c.fields.upper_bound;(!v||v.trim()==="")&&(!w||w.trim()==="")&&f.push("a manual_bounds detector needs at least a lower or upper bound")}return f}}}var Bt=new Set(["enabled","channels","consecutive_anomalies","direction","no_data_alert","notify_on_recovery","alert_cooldown","min_detectors","anomaly_window","min_anomaly_share","mentions","dashboard_url"]);function $n(e){let t=e==null?void 0:e.alerting;return t==null?{mode:"none",block:{}}:Array.isArray(t)?t.length>1?{mode:"verbatim",block:{},verbatim:t}:t.length===1&&t[0]&&typeof t[0]=="object"?{mode:"single",block:t[0]}:{mode:"none",block:{}}:typeof t=="object"?{mode:"single",block:t}:{mode:"none",block:{}}}function On(e,t,n){let{root:r,body:i}=xe("Alerting"),o=$n(e);if(o.mode==="verbatim"){let E=$("div","dtk-ui-form-warn");return E.textContent="Multiple alerting configs \u2014 edit them in the YAML tab.",i.appendChild(E),{el:r,getData:()=>o.verbatim,issues:()=>[]}}let a=o.block,s={};for(let[E,T]of Object.entries(a))Bt.has(E)||(s[E]=T);let m=document.createElement("label");m.className="dtk-ui-check";let l=document.createElement("input");l.type="checkbox",l.checked=o.mode==="single",m.append(l,document.createTextNode("Alerting")),i.appendChild(m);let u=$("div","dtk-ui-alerting-fields");i.appendChild(u);let h=document.createElement("label");h.className="dtk-ui-check";let f=document.createElement("input");f.type="checkbox",f.checked=a.enabled!==!1,f.onchange=()=>n.onDirty(),h.append(f,document.createTextNode("Enabled (uncheck to keep the config but pause sending)")),u.appendChild(h);let c=new Set(t.channels.map(E=>E.name)),v=Array.isArray(a.channels)?a.channels.map(String):[],w=new Set(v.filter(E=>c.has(E))),M=v.filter(E=>!c.has(E)),p=$("div","dtk-ui-field"),x=$("span","dtk-ui-field-label");x.textContent="Channels",p.appendChild(x);let b=$("div","dtk-ui-checks");for(let E of t.channels){let T=document.createElement("label");T.className="dtk-ui-check";let Y=document.createElement("input");Y.type="checkbox",Y.checked=w.has(E.name),Y.onchange=()=>{Y.checked?w.add(E.name):w.delete(E.name),n.onDirty()};let W=$("span","dtk-ui-check-type");W.textContent=`(${E.type})`,T.append(Y,document.createTextNode(E.name+" "),W),b.appendChild(T)}p.appendChild(b);let k=Me(M,"add channel name, Enter",()=>n.onDirty());p.appendChild(k.el),u.appendChild(p);let g=document.createElement("input");g.type="number",g.min="1",g.step="1",g.className="dtk-ui-input",g.value=String(typeof a.consecutive_anomalies=="number"?a.consecutive_anomalies:3),g.oninput=()=>n.onDirty(),u.appendChild(j("Consecutive anomalies",g));let S=document.createElement("select");S.className="dtk-ui-select";for(let E of["same","any","up","down"]){let T=document.createElement("option");T.value=E,T.textContent=E,S.appendChild(T)}S.value=typeof a.direction=="string"?a.direction:"same",S.onchange=()=>n.onDirty(),u.appendChild(j("Direction",S));let N=document.createElement("label");N.className="dtk-ui-check";let L=document.createElement("input");L.type="checkbox",L.checked=a.no_data_alert===!0,L.onchange=()=>n.onDirty(),N.append(L,document.createTextNode("Alert on missing data")),u.appendChild(N);let _=document.createElement("label");_.className="dtk-ui-check";let I=document.createElement("input");I.type="checkbox",I.checked=a.notify_on_recovery===!0,I.onchange=()=>n.onDirty(),_.append(I,document.createTextNode("Notify on recovery")),u.appendChild(_);let A=document.createElement("input");A.type="text",A.className="dtk-ui-input",A.placeholder="e.g. 30min (optional)",A.value=a.alert_cooldown!==void 0&&a.alert_cooldown!==null?String(a.alert_cooldown):"",A.oninput=()=>n.onDirty(),u.appendChild(j("Alert cooldown",A));let z=a.min_detectors!==void 0||a.anomaly_window!==void 0||a.min_anomaly_share!==void 0||Array.isArray(a.mentions)&&a.mentions.length>0||!!a.dashboard_url,K=Ut("Advanced");K.details.open=z,u.appendChild(K.details);let q=document.createElement("input");q.type="number",q.min="1",q.step="1",q.className="dtk-ui-input",q.value=String(typeof a.min_detectors=="number"?a.min_detectors:1),q.oninput=()=>n.onDirty(),K.body.appendChild(j("Min detectors",q));let X=$("div","dtk-ui-row2"),U=document.createElement("input");U.type="text",U.className="dtk-ui-input",U.placeholder="e.g. 30min",U.value=a.anomaly_window!==void 0&&a.anomaly_window!==null?String(a.anomaly_window):"",U.oninput=()=>n.onDirty();let B=document.createElement("input");B.type="number",B.min="0",B.max="1",B.step="0.05",B.className="dtk-ui-input",B.placeholder="e.g. 0.3",B.value=typeof a.min_anomaly_share=="number"?String(a.min_anomaly_share):"",B.oninput=()=>n.onDirty(),X.append(j("Anomaly window",U),j("Min anomaly share",B)),K.body.appendChild(X);let le=Array.isArray(a.mentions)?a.mentions.map(String):[],ne=Me(le,"add mention, Enter",()=>n.onDirty());K.body.appendChild(j("Mentions",ne.el));let J=document.createElement("input");if(J.type="text",J.className="dtk-ui-input",J.placeholder="https://\u2026",J.value=typeof a.dashboard_url=="string"?a.dashboard_url:"",J.oninput=()=>n.onDirty(),K.body.appendChild(j("Dashboard URL",J)),Object.keys(s).length>0){let E=$("span","dtk-ui-preschip");E.textContent=`+${Object.keys(s).length} fields preserved`,u.appendChild(E)}function Q(){u.style.display=l.checked?"":"none"}return l.onchange=()=>{Q(),n.onDirty()},Q(),{el:r,getData:()=>{if(!l.checked)return;let E={enabled:f.checked},T=[...t.channels.filter(F=>w.has(F.name)).map(F=>F.name),...k.get()];T.length>0&&(E.channels=T);let Y=Number(g.value);E.consecutive_anomalies=g.value.trim()!==""&&Number.isFinite(Y)?Math.max(1,Math.round(Y)):3,E.direction=S.value,E.no_data_alert=L.checked,E.notify_on_recovery=I.checked;let W=A.value.trim();W&&(E.alert_cooldown=je(W));let V=Number(q.value),oe=q.value.trim()!==""&&Number.isFinite(V)?Math.max(1,Math.round(V)):1;oe!==1&&(E.min_detectors=oe);let me=U.value.trim(),D=B.value.trim();me&&D&&(E.anomaly_window=je(me),E.min_anomaly_share=Number(D));let Z=ne.get();Z.length>0&&(E.mentions=Z);let ie=J.value.trim();ie&&(E.dashboard_url=ie);for(let[F,ee]of Object.entries(s))Bt.has(F)||(E[F]=ee);return E},issues:()=>{if(!l.checked)return[];let E=U.value.trim(),T=B.value.trim();return E===""!=(T==="")?["anomaly window and min anomaly share must be set together"]:[]}}}function Jt(e){if(typeof e=="string")return{instructions:e,synonyms:[],examples:[]};if(e&&typeof e=="object"){let t=e;return{instructions:typeof t.instructions=="string"?t.instructions:"",synonyms:Array.isArray(t.synonyms)?t.synonyms.map(String):[],examples:Array.isArray(t.examples)?t.examples.map(String):[]}}return{instructions:"",synonyms:[],examples:[]}}function In(e,t){let n=Jt(e==null?void 0:e.ai_context),{root:r,body:i}=xe("AI context"),o=document.createElement("details");o.className="dtk-ui-form-adv",o.open=!!(n.instructions||n.synonyms.length>0||n.examples.length>0);let a=document.createElement("summary");a.className="dtk-ui-form-adv-summary",a.textContent="Instructions / synonyms / examples",o.appendChild(a);let s=$("div","dtk-ui-form-adv-body");o.appendChild(s),i.appendChild(o);let m=document.createElement("textarea");m.className="dtk-ui-input dtk-ui-textarea",m.rows=3,m.placeholder="Business meaning / how to interpret this metric",m.value=n.instructions,m.oninput=()=>t.onDirty(),s.appendChild(j("Instructions",m));let l=Me(n.synonyms,"add synonym, Enter",()=>t.onDirty());s.appendChild(j("Synonyms",l.el));let u=Me(n.examples,"add example, Enter",()=>t.onDirty());return s.appendChild(j("Examples",u.el)),{el:r,getData:()=>{let h=m.value.trim(),f=l.get(),c=u.get();if(!h&&f.length===0&&c.length===0)return;let v={};return h&&(v.instructions=h),f.length>0&&(v.synonyms=f),c.length>0&&(v.examples=c),v},setData:h=>{let f=Jt(h!=null?h:null);m.value=f.instructions,l.set(f.synonyms),u.set(f.examples),(f.instructions||f.synonyms.length>0||f.examples.length>0)&&(o.open=!0)}}}var An=`SELECT
472
472
  toStartOfInterval(event_time, INTERVAL {{ interval_seconds }} SECOND) AS timestamp,
473
473
  count() AS value
474
474
  FROM my_table
@@ -476,7 +476,7 @@ WHERE event_time >= '{{ dtk_start_time }}'
476
476
  AND event_time < '{{ dtk_end_time }}'
477
477
  GROUP BY timestamp
478
478
  ORDER BY timestamp
479
- `;function Pn(e){let t=e.trim();return/^\d+$/.test(t)?`${t}s`:t}function Hn(e,t,n,r,i){let o=$("div","dtk-ui-form-query"),a=$("div","dtk-ui-subtabs"),s=document.createElement("button");s.type="button",s.className="dtk-ui-subtab on",s.textContent="SQL";let f=document.createElement("button");f.type="button",f.className="dtk-ui-subtab",f.textContent="From OSI",a.append(s,f),o.appendChild(a);let l=$("div","dtk-ui-subtab-panes");o.appendChild(l);let p=$("div","dtk-ui-subtab-pane"),h=$("div","dtk-ui-subtab-pane");h.style.display="none",l.append(p,h);function m(D){s.classList.toggle("on",D==="sql"),f.classList.toggle("on",D==="osi"),p.style.display=D==="sql"?"":"none",h.style.display=D==="osi"?"":"none"}s.onclick=()=>m("sql"),f.onclick=()=>m("osi");let c=typeof(e==null?void 0:e.query_file)=="string"?e.query_file:null,v=c?"file":"inline",w=c!=null?c:"",M=typeof(e==null?void 0:e.query)=="string"?e.query:e===null&&!c?An:"",u=null;if(c){u=document.createElement("div");let D=document.createElement("input");D.type="text",D.className="dtk-ui-input",D.readOnly=!0,D.value=c,u.appendChild(j("Query file (read-only)",D)),p.appendChild(u)}let x=Ft({value:M,onInput:()=>t.onDirty(),ariaLabel:"Metric SQL query"});p.appendChild(x.el),c&&x.setDisabled(!0,`SQL lives in ${c} \u2014 edit it on disk, or switch this metric to an inline query in the YAML tab.`);let b=document.createElement("textarea");b.className="dtk-ui-input dtk-ui-textarea",b.rows=8,b.placeholder="Paste an OSI semantic model (YAML)",h.appendChild(j("OSI model",b));let k=$("div","dtk-ui-form-hint-status");h.appendChild(k);let g=document.createElement("select");g.className="dtk-ui-select",g.disabled=!0,h.appendChild(j("Metric",g));let S=document.createElement("select");S.className="dtk-ui-select";for(let D of["clickhouse","cube"]){let X=document.createElement("option");X.value=D,X.textContent=D,S.appendChild(X)}h.appendChild(j("Target",S));let N=document.createElement("select");N.className="dtk-ui-select";let L=j("Dataset (optional)",N);h.appendChild(L);let _=document.createElement("input");_.type="text",_.className="dtk-ui-input",_.placeholder="time column (auto-detected if omitted)";let A=j("Time field (optional)",_);h.appendChild(A);let I=document.createElement("input");I.type="text",I.className="dtk-ui-input",I.placeholder="extra WHERE condition (optional)",h.appendChild(j("Where (optional)",I));let z=document.createElement("input");z.type="text",z.className="dtk-ui-input",z.placeholder="cube name";let K=j("Cube (optional)",z);h.appendChild(K);let q=document.createElement("input");q.type="text",q.className="dtk-ui-input",q.placeholder="measure name (defaults to the metric name)";let G=j("Cube measure (optional)",q);h.appendChild(G);let U=document.createElement("input");U.type="text",U.className="dtk-ui-input",U.placeholder="time dimension";let B=j("Time dimension (cube)",U);h.appendChild(B);function le(){let D=S.value==="cube";L.style.display=D?"none":"",A.style.display=D?"none":"",K.style.display=D?"":"none",G.style.display=D?"":"none",B.style.display=D?"":"none"}S.onchange=()=>{le()},le();let ne=document.createElement("button");ne.type="button",ne.className="dtk-ui-btn primary",ne.textContent="Compile",h.appendChild(ne);let J=$("div","dtk-ui-form-err");h.appendChild(J);let V=$("div","dtk-ui-form-warn");h.appendChild(V);let E=[],T=null;function Y(){let D=g.value.indexOf("::");return D===-1?-1:Number(g.value.slice(0,D))}function W(){let D=g.value.indexOf("::");return D===-1?g.value:g.value.slice(D+2)}function Q(){var ie;N.innerHTML="";let D=document.createElement("option");D.value="",D.textContent="(auto)",N.appendChild(D);let X=E[Y()];for(let F of(ie=X==null?void 0:X.datasets)!=null?ie:[]){let ee=document.createElement("option");ee.value=F,ee.textContent=F,N.appendChild(ee)}}function oe(){if(g.innerHTML="",E.length===0){g.disabled=!0,Q();return}g.disabled=!1;let D=E.length>1;E.forEach((X,ie)=>{let F=D?document.createElement("optgroup"):null;F&&(F.label=X.name,g.appendChild(F));for(let ee of X.metrics){let ce=document.createElement("option");ce.value=`${ie}::${ee}`,ce.textContent=ee,(F!=null?F:g).appendChild(ce)}}),Q()}g.onchange=()=>{Q()};let me=it(()=>{let D=b.value;if(D.trim()===""){E=[],oe(),k.textContent="",J.textContent="";return}k.textContent="Inspecting\u2026",t.osiInspect(D).then(X=>{E=X.models,oe();let ie=E.reduce((F,ee)=>F+ee.metrics.length,0);k.textContent=ie>0?`Found ${ie} metric(s) across ${E.length} model(s).`:"No metrics found.",J.textContent=""}).catch(X=>{E=[],oe(),k.textContent="",J.textContent=X.message})},400);return b.addEventListener("input",()=>{me()}),ne.onclick=()=>{J.textContent="",V.innerHTML="";let D=b.value;if(D.trim()===""){J.textContent="paste an OSI model first";return}if(g.value===""){J.textContent="pick a metric to import";return}let X=n();if(!X){J.textContent="set an interval in Schedule & loading first";return}let ie=S.value,F={text:D,metric:W(),interval:Pn(X),target:ie},ee=r();ee.length>0&&(F.seasonality=ee),ie==="clickhouse"?(N.value&&(F.dataset=N.value),_.value.trim()&&(F.time_field=_.value.trim()),I.value.trim()&&(F.where=I.value.trim())):(z.value.trim()&&(F.cube=z.value.trim()),q.value.trim()&&(F.cube_measure=q.value.trim()),U.value.trim()&&(F.time_dimension=U.value.trim()),I.value.trim()&&(F.where=I.value.trim()));let ce=W();ne.disabled=!0,ne.textContent="Compiling\u2026",t.osiImport(F).then(te=>{let fe=typeof te.body.query=="string"?te.body.query:te.sql;if(x.setValue(fe),x.setDisabled(!1),u&&(u.style.display="none"),v="inline",w="",m("sql"),T={fingerprint:te.fingerprint,target:te.target,metric:ce},i(te.body,te.name||ce),te.warnings.length>0)for(let we of te.warnings){let he=document.createElement("div");he.textContent=`\u26A0 ${we}`,V.appendChild(he)}t.onDirty()}).catch(te=>{J.textContent=te.message}).finally(()=>{ne.disabled=!1,ne.textContent="Compile"})},{el:o,getMode:()=>v,getQuery:()=>x.getValue(),getFilePath:()=>w,getOsiProvenance:()=>T,issues:()=>v==="inline"&&x.getValue().trim()===""?["query is empty"]:[]}}function Kt(e,t,n,r){let i=document.createElement("div");i.className="dtk-ui-form";let o,a,s,f,l,p,h,m={};function c(u){i.innerHTML="";let x=$("div","dtk-ui-form-rail"),b=$("div","dtk-ui-form-main");i.append(x,b),m=wn(u),o=Cn(u,t,n),a=Tn(u,n),s=Nn(u,n),f=Dn(u,n,r.mode),l=On(u,t,n),p=In(u,n),x.append(o.el,a.el,s.el,f.el,l.el,p.el),Object.keys(m).length>0&&x.appendChild(En(m)),h=Hn(u,n,()=>a.getInterval(),()=>s.getColumns(),(k,g)=>{r.mode==="create"&&o.getName()===""&&o.setName(g),typeof k.description=="string"&&o.setDescription(k.description),k.ai_context&&typeof k.ai_context=="object"&&p.setData(k.ai_context),Array.isArray(k.seasonality_columns)&&s.setColumns(k.seasonality_columns.map(String))}),b.appendChild(h.el)}c(e);function v(){let u={},x=o.getName();x&&(u.name=x);let b=o.getDescription().trim();b&&(u.description=b);let k=o.getTags();k.length>0&&(u.tags=k);let g=o.getProfile();g&&(u.profile=g);let S=p.getData();S&&(u.ai_context=S),h.getMode()==="file"?u.query_file=h.getFilePath():u.query=h.getQuery();let N=a.getQueryColumns();N&&(u.query_columns=N);let L=a.getInterval();L&&(u.interval=je(L));let _=a.getLoadingStartTime();_&&(u.loading_start_time=_);let A=a.getLoadingDelay();A&&(u.loading_delay=je(A));let I=a.getLoadingBatchSize();I!==null&&(u.loading_batch_size=I);let z=s.getColumns();z.length>0&&(u.seasonality_columns=z);let K=f.getData();K.length>0&&(u.detectors=K);let q=l.getData();q!==void 0&&(u.alerting=q);for(let[G,U]of Object.entries(m))u[G]=U;return o.getEnabled()||(u.enabled=!1),u}function w(){let u=v(),x=h.getOsiProvenance(),b=x?[`Query compiled from OSI metric '${x.metric}' (target: ${x.target}, sql-fingerprint: ${x.fingerprint}).`,"Review the SQL before saving \u2014 re-compiling after the OSI model changes is a visible diff."]:void 0;return jt(u,b)}function M(){return[...o.issues(),...a.issues(),...h.issues(),...f.issues(),...l.issues()]}return{el:i,setFromData:u=>c(u),toData:v,toYaml:w,clientIssues:M,focusFirst:()=>o.focusName()}}var Wt=`# New metric \u2014 edit the query and name, then Create.
479
+ `;function Pn(e){let t=e.trim();return/^\d+$/.test(t)?`${t}s`:t}function Hn(e,t,n,r,i){let o=$("div","dtk-ui-form-query"),a=$("div","dtk-ui-subtabs"),s=document.createElement("button");s.type="button",s.className="dtk-ui-subtab on",s.textContent="SQL";let m=document.createElement("button");m.type="button",m.className="dtk-ui-subtab",m.textContent="From OSI",a.append(s,m),o.appendChild(a);let l=$("div","dtk-ui-subtab-panes");o.appendChild(l);let u=$("div","dtk-ui-subtab-pane"),h=$("div","dtk-ui-subtab-pane");h.style.display="none",l.append(u,h);function f(D){s.classList.toggle("on",D==="sql"),m.classList.toggle("on",D==="osi"),u.style.display=D==="sql"?"":"none",h.style.display=D==="osi"?"":"none"}s.onclick=()=>f("sql"),m.onclick=()=>f("osi");let c=typeof(e==null?void 0:e.query_file)=="string"?e.query_file:null,v=c?"file":"inline",w=c!=null?c:"",M=typeof(e==null?void 0:e.query)=="string"?e.query:e===null&&!c?An:"",p=null;if(c){p=document.createElement("div");let D=document.createElement("input");D.type="text",D.className="dtk-ui-input",D.readOnly=!0,D.value=c,p.appendChild(j("Query file (read-only)",D)),u.appendChild(p)}let x=Ft({value:M,onInput:()=>t.onDirty(),ariaLabel:"Metric SQL query"});u.appendChild(x.el),c&&x.setDisabled(!0,`SQL lives in ${c} \u2014 edit it on disk, or switch this metric to an inline query in the YAML tab.`);let b=document.createElement("textarea");b.className="dtk-ui-input dtk-ui-textarea",b.rows=8,b.placeholder="Paste an OSI semantic model (YAML)",h.appendChild(j("OSI model",b));let k=$("div","dtk-ui-form-hint-status");h.appendChild(k);let g=document.createElement("select");g.className="dtk-ui-select",g.disabled=!0,h.appendChild(j("Metric",g));let S=document.createElement("select");S.className="dtk-ui-select";for(let D of["clickhouse","cube"]){let Z=document.createElement("option");Z.value=D,Z.textContent=D,S.appendChild(Z)}h.appendChild(j("Target",S));let N=document.createElement("select");N.className="dtk-ui-select";let L=j("Dataset (optional)",N);h.appendChild(L);let _=document.createElement("input");_.type="text",_.className="dtk-ui-input",_.placeholder="time column (auto-detected if omitted)";let I=j("Time field (optional)",_);h.appendChild(I);let A=document.createElement("input");A.type="text",A.className="dtk-ui-input",A.placeholder="extra WHERE condition (optional)",h.appendChild(j("Where (optional)",A));let z=document.createElement("input");z.type="text",z.className="dtk-ui-input",z.placeholder="cube name";let K=j("Cube (optional)",z);h.appendChild(K);let q=document.createElement("input");q.type="text",q.className="dtk-ui-input",q.placeholder="measure name (defaults to the metric name)";let X=j("Cube measure (optional)",q);h.appendChild(X);let U=document.createElement("input");U.type="text",U.className="dtk-ui-input",U.placeholder="time dimension";let B=j("Time dimension (cube)",U);h.appendChild(B);function le(){let D=S.value==="cube";L.style.display=D?"none":"",I.style.display=D?"none":"",K.style.display=D?"":"none",X.style.display=D?"":"none",B.style.display=D?"":"none"}S.onchange=()=>{le()},le();let ne=document.createElement("button");ne.type="button",ne.className="dtk-ui-btn primary",ne.textContent="Compile",h.appendChild(ne);let J=$("div","dtk-ui-form-err");h.appendChild(J);let Q=$("div","dtk-ui-form-warn");h.appendChild(Q);let E=[],T=null;function Y(){let D=g.value.indexOf("::");return D===-1?-1:Number(g.value.slice(0,D))}function W(){let D=g.value.indexOf("::");return D===-1?g.value:g.value.slice(D+2)}function V(){var ie;N.innerHTML="";let D=document.createElement("option");D.value="",D.textContent="(auto)",N.appendChild(D);let Z=E[Y()];for(let F of(ie=Z==null?void 0:Z.datasets)!=null?ie:[]){let ee=document.createElement("option");ee.value=F,ee.textContent=F,N.appendChild(ee)}}function oe(){if(g.innerHTML="",E.length===0){g.disabled=!0,V();return}g.disabled=!1;let D=E.length>1;E.forEach((Z,ie)=>{let F=D?document.createElement("optgroup"):null;F&&(F.label=Z.name,g.appendChild(F));for(let ee of Z.metrics){let ce=document.createElement("option");ce.value=`${ie}::${ee}`,ce.textContent=ee,(F!=null?F:g).appendChild(ce)}}),V()}g.onchange=()=>{V()};let me=it(()=>{let D=b.value;if(D.trim()===""){E=[],oe(),k.textContent="",J.textContent="";return}k.textContent="Inspecting\u2026",t.osiInspect(D).then(Z=>{E=Z.models,oe();let ie=E.reduce((F,ee)=>F+ee.metrics.length,0);k.textContent=ie>0?`Found ${ie} metric(s) across ${E.length} model(s).`:"No metrics found.",J.textContent=""}).catch(Z=>{E=[],oe(),k.textContent="",J.textContent=Z.message})},400);return b.addEventListener("input",()=>{me()}),ne.onclick=()=>{J.textContent="",Q.innerHTML="";let D=b.value;if(D.trim()===""){J.textContent="paste an OSI model first";return}if(g.value===""){J.textContent="pick a metric to import";return}let Z=n();if(!Z){J.textContent="set an interval in Schedule & loading first";return}let ie=S.value,F={text:D,metric:W(),interval:Pn(Z),target:ie},ee=r();ee.length>0&&(F.seasonality=ee),ie==="clickhouse"?(N.value&&(F.dataset=N.value),_.value.trim()&&(F.time_field=_.value.trim()),A.value.trim()&&(F.where=A.value.trim())):(z.value.trim()&&(F.cube=z.value.trim()),q.value.trim()&&(F.cube_measure=q.value.trim()),U.value.trim()&&(F.time_dimension=U.value.trim()),A.value.trim()&&(F.where=A.value.trim()));let ce=W();ne.disabled=!0,ne.textContent="Compiling\u2026",t.osiImport(F).then(te=>{let fe=typeof te.body.query=="string"?te.body.query:te.sql;if(x.setValue(fe),x.setDisabled(!1),p&&(p.style.display="none"),v="inline",w="",f("sql"),T={fingerprint:te.fingerprint,target:te.target,metric:ce},i(te.body,te.name||ce),te.warnings.length>0)for(let we of te.warnings){let he=document.createElement("div");he.textContent=`\u26A0 ${we}`,Q.appendChild(he)}t.onDirty()}).catch(te=>{J.textContent=te.message}).finally(()=>{ne.disabled=!1,ne.textContent="Compile"})},{el:o,getMode:()=>v,getQuery:()=>x.getValue(),getFilePath:()=>w,getOsiProvenance:()=>T,issues:()=>v==="inline"&&x.getValue().trim()===""?["query is empty"]:[]}}function Kt(e,t,n,r){let i=document.createElement("div");i.className="dtk-ui-form";let o,a,s,m,l,u,h,f={};function c(p){i.innerHTML="";let x=$("div","dtk-ui-form-rail"),b=$("div","dtk-ui-form-main");i.append(x,b),f=wn(p),o=Cn(p,t,n),a=Tn(p,n),s=Nn(p,n),m=Dn(p,n,r.mode),l=On(p,t,n),u=In(p,n),x.append(o.el,a.el,s.el,m.el,l.el,u.el),Object.keys(f).length>0&&x.appendChild(En(f)),h=Hn(p,n,()=>a.getInterval(),()=>s.getColumns(),(k,g)=>{r.mode==="create"&&(o.getName()===""||o.getName()==="my_metric")&&o.setName(g),typeof k.description=="string"&&o.setDescription(k.description),k.ai_context&&typeof k.ai_context=="object"&&u.setData(k.ai_context),Array.isArray(k.seasonality_columns)&&s.setColumns(k.seasonality_columns.map(String))}),b.appendChild(h.el)}c(e);function v(){let p={},x=o.getName();x&&(p.name=x);let b=o.getDescription().trim();b&&(p.description=b);let k=o.getTags();k.length>0&&(p.tags=k);let g=o.getProfile();g&&(p.profile=g);let S=u.getData();S&&(p.ai_context=S),h.getMode()==="file"?p.query_file=h.getFilePath():p.query=h.getQuery();let N=a.getQueryColumns();N&&(p.query_columns=N);let L=a.getInterval();L&&(p.interval=je(L));let _=a.getLoadingStartTime();_&&(p.loading_start_time=_);let I=a.getLoadingDelay();I&&(p.loading_delay=je(I));let A=a.getLoadingBatchSize();A!==null&&(p.loading_batch_size=A);let z=s.getColumns();z.length>0&&(p.seasonality_columns=z);let K=m.getData();K.length>0&&(p.detectors=K);let q=l.getData();q!==void 0&&(p.alerting=q);for(let[X,U]of Object.entries(f))p[X]=U;return o.getEnabled()||(p.enabled=!1),p}function w(){let p=v(),x=h.getOsiProvenance(),b=x?[`Query compiled from OSI metric '${x.metric}' (target: ${x.target}, sql-fingerprint: ${x.fingerprint}).`,"Review the SQL before saving \u2014 re-compiling after the OSI model changes is a visible diff."]:void 0;return jt(p,b)}function M(){return[...o.issues(),...a.issues(),...h.issues(),...m.issues(),...l.issues()]}return{el:i,setFromData:p=>c(p),toData:v,toYaml:w,clientIssues:M,focusFirst:()=>o.focusName()}}var Wt=`# New metric \u2014 edit the query and name, then Create.
480
480
  # Template variables available in query:
481
481
  # {{ dtk_start_time }} / {{ dtk_end_time }} \u2014 load window bounds
482
482
  # {{ interval_seconds }} \u2014 metric interval in seconds
@@ -506,10 +506,13 @@ detectors:
506
506
  # enabled: true
507
507
  # channels: [my_channel]
508
508
  # consecutive_anomalies: 3
509
- `,jn={channels:[],profiles:[],default_profile:null};function et(e,t,n){var we,he;let r=t.mode==="create",i=(we=t.meta)!=null?we:jn,o=r||t.data!==null&&t.data!==void 0,a=!1,s=!1,f=!1,l=!1,p=o?"builder":"yaml",h=He(e,{modalClass:"dtk-ui-editor-modal",onRequestClose:()=>{fe()}}),{modal:m}=h,c=document.createElement("div");c.className="dtk-ui-editor-head";let v=document.createElement("div");v.className="dtk-ui-editor-titlewrap";let w=document.createElement("span");if(w.className="dtk-ui-editor-title",w.textContent=r?"New metric":`Edit ${(he=t.name)!=null?he:""}`,v.appendChild(w),!r&&t.file){let C=document.createElement("span");C.className="dtk-ui-editor-sub",C.textContent=t.file,v.appendChild(C)}c.appendChild(v);let M=document.createElement("div");M.className="dtk-ui-edtabs";let u=document.createElement("button");u.type="button",u.className="dtk-ui-edtab",u.textContent="Builder",o||(u.disabled=!0,u.title=t.parseError?`This file doesn't parse as a metric config \u2014 fix it in YAML first.
510
- ${t.parseError}`:"Builder unavailable for this file"),u.onclick=()=>{oe("builder")};let x=document.createElement("button");x.type="button",x.className="dtk-ui-edtab",x.textContent="YAML",x.onclick=()=>{oe("yaml")},M.append(u,x),c.appendChild(M);let b=document.createElement("button");b.type="button",b.className="dtk-ui-overlay-close",b.textContent="\u2715",b.title="Close (Esc)",b.onclick=()=>{fe()},c.appendChild(b),m.appendChild(c);let k=document.createElement("div");k.className="dtk-ui-editor-body",m.appendChild(k);let g=null;if(r){let C=document.createElement("div");C.className="dtk-ui-editor-field",C.innerHTML='<span class="dtk-ui-field-label">Folder</span>',g=document.createElement("input"),g.type="text",g.className="dtk-ui-input",g.placeholder="optional subfolder under metrics/",C.appendChild(g);let P=document.createElement("div");P.className="dtk-ui-editor-hint",P.textContent="The file is written as metrics/[folder/]<name>.yml \u2014 <name> comes from the metric name below.",C.appendChild(P),k.appendChild(C)}let S=!r&&/(^|\n)\s*#/.test(t.text),N=document.createElement("div");N.className="dtk-ui-editor-note",N.textContent="Saving from Builder re-writes the YAML \u2014 comments are dropped (the previous file is archived to metrics/.history/).",N.style.display="none",k.appendChild(N);let L=document.createElement("div");L.className="dtk-ui-editor-panes",k.appendChild(L);let _=document.createElement("textarea");_.className="dtk-ui-editor-textarea",_.spellcheck=!1,_.autocapitalize="off",_.value=t.text,_.addEventListener("input",()=>{a=!0,l=!0,T()}),_.addEventListener("keydown",C=>{if(C.key==="Tab"){C.preventDefault();let P=_.selectionStart,Z=_.selectionEnd;_.value=`${_.value.slice(0,P)} ${_.value.slice(Z)}`,_.selectionStart=_.selectionEnd=P+2,a=!0,l=!0,T()}});let A=null;o&&(A=Kt(r?null:t.data,i,{onDirty:()=>{a=!0,f=!0,T()},osiInspect:C=>gt(C),osiImport:C=>ht(C)},{mode:t.mode}),L.appendChild(A.el)),L.appendChild(_),m.addEventListener("keydown",C=>{(C.ctrlKey||C.metaKey)&&C.key.toLowerCase()==="s"&&(C.preventDefault(),ee())});let I=document.createElement("div");I.className="dtk-ui-editor-error",I.style.display="none",m.appendChild(I);function z(C){I.textContent=C,I.style.display=""}function K(){I.style.display="none",I.textContent=""}let q=document.createElement("div");q.className="dtk-ui-editor-foot";let G=document.createElement("div");G.className="dtk-ui-editor-foot-left";let U=document.createElement("div");U.className="dtk-ui-editor-foot-right",q.append(G,U),m.appendChild(q);let B=document.createElement("span");B.className="dtk-ui-validchip",B.style.display="none",U.appendChild(B);let le=document.createElement("button");le.type="button",le.className="dtk-ui-btn primary";let ne=r?"Create metric":"Save changes";le.textContent=ne,le.onclick=()=>{ee()},U.appendChild(le);let J,V=0;function E(C,P,Z){B.className=`dtk-ui-validchip ${C}`,B.innerHTML='<span class="dtk-ui-validchip-dot"></span>',B.appendChild(document.createTextNode(P)),B.title=Z!=null?Z:P,B.style.display=""}function T(){J!==void 0&&window.clearTimeout(J),J=window.setTimeout(()=>{J=void 0,Y()},600)}async function Y(){let C=++V,P;if(p==="builder"&&A){let Z=A.clientIssues();if(Z.length>0){E("warn",Z[0],Z.join(`
511
- `));return}P=A.toYaml()}else P=_.value;E("checking","checking\u2026");try{if(await Ye(P),C!==V)return;E("ok","\u2713 valid config")}catch(Z){if(C!==V)return;let d=Z.message;E("err",d.split(`
512
- `)[0],d)}}function W(){u.classList.toggle("on",p==="builder"),x.classList.toggle("on",p==="yaml"),A&&(A.el.style.display=p==="builder"?"":"none"),_.style.display=p==="yaml"?"":"none",N.style.display=p==="builder"&&S?"":"none"}let Q=!1;async function oe(C){if(!(C===p||s||Q)&&!(C==="builder"&&!A)){Q=!0;try{await me(C)}finally{Q=!1}}}async function me(C){if(C==="yaml")f&&A&&(_.value=A.toYaml(),f=!1,l=!1);else if(l&&A){K();try{let P=await Ye(_.value);A.setFromData(P.data),l=!1,f=!1}catch(P){z(`Fix the YAML before switching to Builder:
513
- ${P.message}`);return}}K(),p=C,W(),T()}function D(){let C=document.createElement("button");return C.type="button",C.className="dtk-ui-btn danger",C.textContent="Delete metric\u2026",C.onclick=()=>X(),C}r||G.appendChild(D());function X(){var ae,re;let C=(ae=t.name)!=null?ae:"",P=(re=t.file)!=null?re:"";G.innerHTML="";let Z=document.createElement("div");Z.className="dtk-ui-editor-confirm";let d=document.createElement("span");d.className="dtk-ui-editor-confirm-text",d.innerHTML=`Delete <b>${O(C)}</b>? The file <code>${O(P)}</code> is archived to <code>metrics/.history/</code> and removed. Data rows in the <code>_dtk_*</code> tables remain until <code>dtk clean</code>.`,Z.appendChild(d);let y=document.createElement("button");y.type="button",y.className="dtk-ui-btn danger",y.textContent="Delete metric",y.onclick=()=>{ce(C,y,R)};let R=document.createElement("button");R.type="button",R.className="dtk-ui-btn",R.textContent="Cancel",R.onclick=()=>{G.innerHTML="",G.appendChild(D())},Z.append(y,R),G.appendChild(Z)}function ie(C){s=C,le.disabled=C,le.textContent=C?"Saving\u2026":ne}function F(){return p==="builder"&&A&&f?A.toYaml():_.value}async function ee(){var C;if(!s){if(K(),p==="builder"&&A){let P=A.clientIssues();if(P.length>0){z(`Fix before saving:
509
+ `,jn={channels:[],profiles:[],default_profile:null};function qn(e){var l;let t=e.split(`
510
+ `),n=(l=t[0])!=null?l:e,r=n.match(/^(.*?)(\d+) validation errors? for \S+$/);if(!r)return n;let i=Number(r[2])-1,o=i>0?` (+${i} more)`:"",a=u=>u.trim().replace(/\s*\[type=.*$/,"").replace(/^(Value|Assertion) error, /,""),s=t[1];if(!(s!=null&&s.trim()))return n;if(/^\s/.test(s)||s.includes("[type="))return`${r[1]}${a(s)}${o}`;let m=t[2]?a(t[2]):"";return m?`${r[1]}${s.trim()} \u2014 ${m}${o}`:n}function et(e,t,n){var we,he;let r=t.mode==="create",i=(we=t.meta)!=null?we:jn,o=r||t.data!==null&&t.data!==void 0,a=!1,s=!1,m=!1,l=!1,u=o?"builder":"yaml",h=He(e,{modalClass:"dtk-ui-editor-modal",onRequestClose:()=>{fe()}}),{modal:f}=h,c=document.createElement("div");c.className="dtk-ui-editor-head";let v=document.createElement("div");v.className="dtk-ui-editor-titlewrap";let w=document.createElement("span");if(w.className="dtk-ui-editor-title",w.textContent=r?"New metric":`Edit ${(he=t.name)!=null?he:""}`,v.appendChild(w),!r&&t.file){let C=document.createElement("span");C.className="dtk-ui-editor-sub",C.textContent=t.file,v.appendChild(C)}c.appendChild(v);let M=document.createElement("div");M.className="dtk-ui-edtabs";let p=document.createElement("button");p.type="button",p.className="dtk-ui-edtab",p.textContent="Builder",o||(p.disabled=!0,p.title=t.parseError?`This file doesn't parse as a metric config \u2014 fix it in YAML first.
511
+ ${t.parseError}`:"Builder unavailable for this file"),p.onclick=()=>{oe("builder")};let x=document.createElement("button");x.type="button",x.className="dtk-ui-edtab",x.textContent="YAML",x.onclick=()=>{oe("yaml")},M.append(p,x),c.appendChild(M);let b=document.createElement("button");b.type="button",b.className="dtk-ui-overlay-close",b.textContent="\u2715",b.title="Close (Esc)",b.onclick=()=>{fe()},c.appendChild(b),f.appendChild(c);let k=document.createElement("div");k.className="dtk-ui-editor-body",f.appendChild(k);let g=null;if(r){let C=document.createElement("div");C.className="dtk-ui-editor-field",C.innerHTML='<span class="dtk-ui-field-label">Folder</span>',g=document.createElement("input"),g.type="text",g.className="dtk-ui-input",g.placeholder="optional subfolder under metrics/",C.appendChild(g);let P=document.createElement("div");P.className="dtk-ui-editor-hint",P.textContent="The file is written as metrics/[folder/]<name>.yml \u2014 <name> comes from the metric name below.",C.appendChild(P),k.appendChild(C)}let S=!r&&/(^|\n)\s*#/.test(t.text),N=document.createElement("div");N.className="dtk-ui-editor-note",N.textContent="Saving from Builder re-writes the YAML \u2014 comments are dropped (the previous file is archived to metrics/.history/).",N.style.display="none",k.appendChild(N);let L=document.createElement("div");L.className="dtk-ui-editor-panes",k.appendChild(L);let _=document.createElement("textarea");_.className="dtk-ui-editor-textarea",_.spellcheck=!1,_.autocapitalize="off",_.value=t.text,_.addEventListener("input",()=>{a=!0,l=!0,T()}),_.addEventListener("keydown",C=>{if(C.key==="Tab"){C.preventDefault();let P=_.selectionStart,G=_.selectionEnd;_.value=`${_.value.slice(0,P)} ${_.value.slice(G)}`,_.selectionStart=_.selectionEnd=P+2,a=!0,l=!0,T()}});let I=null;o&&(I=Kt(r?null:t.data,i,{onDirty:()=>{a=!0,m=!0,T()},osiInspect:C=>gt(C),osiImport:C=>ht(C)},{mode:t.mode}),L.appendChild(I.el)),L.appendChild(_),f.addEventListener("keydown",C=>{(C.ctrlKey||C.metaKey)&&C.key.toLowerCase()==="s"&&(C.preventDefault(),ee())});let A=document.createElement("div");A.className="dtk-ui-editor-error",A.style.display="none",f.appendChild(A);function z(C){A.textContent=C,A.style.display=""}function K(){A.style.display="none",A.textContent=""}let q=document.createElement("div");q.className="dtk-ui-editor-foot";let X=document.createElement("div");X.className="dtk-ui-editor-foot-left";let U=document.createElement("div");U.className="dtk-ui-editor-foot-right",q.append(X,U),f.appendChild(q);let B=document.createElement("span");B.className="dtk-ui-validchip",B.style.display="none",U.appendChild(B);let le=document.createElement("button");le.type="button",le.className="dtk-ui-btn primary";let ne=r?"Create metric":"Save changes";le.textContent=ne,le.onclick=()=>{ee()},U.appendChild(le);let J,Q=0;function E(C,P,G){B.className=`dtk-ui-validchip ${C}`,B.innerHTML='<span class="dtk-ui-validchip-dot"></span>',B.appendChild(document.createTextNode(P)),B.title=G!=null?G:P,B.style.display=""}function T(){J!==void 0&&window.clearTimeout(J),J=window.setTimeout(()=>{J=void 0,Y()},600)}async function Y(){let C=++Q;if(I&&(u==="builder"||!l)){let G=I.clientIssues();if(G.length>0){E("warn",G[0],G.join(`
512
+ `));return}}let P=u==="builder"&&I?I.toYaml():_.value;E("checking","checking\u2026");try{if(await Ye(P),C!==Q)return;E("ok","\u2713 valid config")}catch(G){if(C!==Q)return;let d=G.message;E("err",qn(d),d)}}function W(){p.classList.toggle("on",u==="builder"),x.classList.toggle("on",u==="yaml"),I&&(I.el.style.display=u==="builder"?"":"none"),_.style.display=u==="yaml"?"":"none",N.style.display=u==="builder"&&S?"":"none"}let V=!1;async function oe(C){if(!(C===u||s||V)&&!(C==="builder"&&!I)){V=!0;try{await me(C)}finally{V=!1}}}async function me(C){if(C==="yaml")m&&I&&(_.value=I.toYaml(),m=!1,l=!1);else if(l&&I){K();try{let P=await Ye(_.value);I.setFromData(P.data),l=!1,m=!1}catch(P){if(!window.confirm(`The YAML doesn't validate:
513
+ ${P.message}
514
+
515
+ Return to the Builder anyway? Your YAML edits will be discarded (the Builder keeps its own last state).`)){z(`Fix the YAML (or discard it via the Builder tab):
516
+ ${P.message}`);return}l=!1,m=!0}}K(),u=C,W(),T()}function D(){let C=document.createElement("button");return C.type="button",C.className="dtk-ui-btn danger",C.textContent="Delete metric\u2026",C.onclick=()=>Z(),C}r||X.appendChild(D());function Z(){var ae,re;let C=(ae=t.name)!=null?ae:"",P=(re=t.file)!=null?re:"";X.innerHTML="";let G=document.createElement("div");G.className="dtk-ui-editor-confirm";let d=document.createElement("span");d.className="dtk-ui-editor-confirm-text",d.innerHTML=`Delete <b>${O(C)}</b>? The file <code>${O(P)}</code> is archived to <code>metrics/.history/</code> and removed. Data rows in the <code>_dtk_*</code> tables remain until <code>dtk clean</code>.`,G.appendChild(d);let y=document.createElement("button");y.type="button",y.className="dtk-ui-btn danger",y.textContent="Delete metric",y.onclick=()=>{ce(C,y,R)};let R=document.createElement("button");R.type="button",R.className="dtk-ui-btn",R.textContent="Cancel",R.onclick=()=>{X.innerHTML="",X.appendChild(D())},G.append(y,R),X.appendChild(G)}function ie(C){s=C,le.disabled=C,le.textContent=C?"Saving\u2026":ne}function F(){return u==="builder"&&I&&m?I.toYaml():_.value}async function ee(){var C;if(!s){if(K(),I&&(u==="builder"||!l)){let P=I.clientIssues();if(P.length>0){z(`Fix before saving:
514
517
  - ${P.join(`
515
- - `)}`);return}}ie(!0);try{let P=F(),Z=r?await mt({text:P,folder:(g==null?void 0:g.value.trim())||void 0}):await ft((C=t.name)!=null?C:"",{text:P,digest:t.digest});a=!1,n.onSaved(Z,t.mode),te()}catch(P){z(P.message)}finally{ie(!1)}}}async function ce(C,P,Z){if(!s){K(),s=!0,P.disabled=!0,Z.disabled=!0,P.textContent="Deleting\u2026";try{let d=await bt(C);a=!1,n.onDeleted(d),te()}catch(d){z(d.message),P.disabled=!1,Z.disabled=!1,P.textContent="Delete metric"}finally{s=!1}}}function te(){h.close(),n.onClose()}function fe(){return a&&!window.confirm("Discard unsaved changes?")?!1:(te(),!0)}return W(),p==="builder"&&A?A.focusFirst():_.focus(),T(),{close:te,requestClose:fe}}function Qt(e,t,n){if(e.innerHTML="",!t)return;let r=document.createElement("div");r.className="dtk-ui-nextsteps"+(t.phase==="failed"?" failed":"");let i=document.createElement("span");i.className="dtk-ui-nextsteps-text";let o=document.createElement("b");if(o.textContent=t.metric,t.phase==="done")i.append("Data loaded for ",o," \u2014 tune the detector on the real series.");else if(t.phase==="running"){i.append("Loading data for ",o,"\u2026 ");let p=document.createElement("a");p.href="#",p.className="dtk-ui-nextsteps-link",p.textContent="view log",p.onclick=h=>{h.preventDefault(),t.jobId&&n.onFollow(t.jobId)},i.appendChild(p)}else t.phase==="failed"?i.append("Loading data for ",o," failed \u2014 check the log, then retry."):i.append("Metric ",o," created. Next: load data, then tune the detector on it.");r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-nextsteps-actions";let s=document.createElement("button");if(s.type="button",s.className="dtk-ui-btn"+(t.phase==="idle"||t.phase==="failed"?" primary":""),s.textContent=t.phase==="failed"?"Retry load":"Load & detect",s.disabled=t.phase==="running",s.title="Runs `dtk run --steps load,detect` for this metric (no alerts sent)",s.onclick=()=>n.onLoad(t.metric),a.appendChild(s),t.phase==="running"){let p=document.createElement("span");p.className="dtk-ui-nextsteps-spin",a.appendChild(p)}let f=document.createElement("button");f.type="button",f.className="dtk-ui-btn"+(t.phase==="done"?" primary":""),f.textContent="Open tune",f.disabled=t.phase!=="done",f.title=t.phase==="done"?"Open the tune cockpit on the loaded series":"Load data first \u2014 the tune cockpit works on persisted datapoints",f.onclick=()=>n.onTune(t.metric),a.appendChild(f);let l=document.createElement("button");l.type="button",l.className="dtk-ui-nextsteps-close",l.textContent="\u2715",l.title="Dismiss",l.onclick=()=>n.onDismiss(),a.appendChild(l),r.appendChild(a),e.appendChild(r)}var qn=3,Fn=[{value:"24h",label:"24h"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"},{value:"all",label:"All"}];function zn(e,t){var Z;yt(),t.classList.add(ve),t.innerHTML="";let n=document.createElement("div");n.className=`${ve}-root`,t.appendChild(n);let r=e.metrics,i=(Z=e.form_meta)!=null?Z:{channels:[],profiles:[],default_profile:null},o={windowPreset:e.initial_window||"30d",metrics:r.map(Se),jobs:[],followedJobId:null,followOffset:0,tagFilter:null,sort:{key:"alerts",dir:Ke.alerts},nextSteps:null},a=null,s=null,f,l;function p(){let d=new Set,y=new Set;for(let R of r){d.add(R.name);for(let ae of R.tags)y.add(ae)}return[...d,...[...y].map(R=>`tag:${R}`)]}function h(){let d=o.jobs.find(y=>y.status==="running"&&y.kind!=="tune");return d?{busy:!0,reason:`a pipeline job is already running (${d.label})`}:{busy:!1,reason:""}}let m=document.createElement("div");m.className="dtk-ui-header",n.appendChild(m);let c=document.createElement("div");c.className="dtk-ui-brand",c.innerHTML=`<span class="dtk-ui-brand-dot"></span><span class="dtk-ui-brand-name">detectkit \xB7 <b>${O(e.project)}</b></span>`,m.appendChild(c);let v=document.createElement("div");v.className="dtk-ui-header-right",m.appendChild(v);let w=document.createElement("div");w.className="dtk-ui-seg";for(let d of Fn){let y=document.createElement("button");y.type="button",y.className="dtk-ui-seg-btn"+(o.windowPreset===d.value?" on":""),y.textContent=d.label,y.onclick=()=>{o.windowPreset!==d.value&&(o.windowPreset=d.value,w.querySelectorAll(".dtk-ui-seg-btn").forEach(R=>R.classList.remove("on")),y.classList.add("on"),a&&a.setWindow(d.value),P())},w.appendChild(y)}v.appendChild(w);let M=document.createElement("button");M.type="button",M.className="dtk-ui-iconbtn",M.title="Refresh overview",M.textContent="\u27F3",M.onclick=()=>{P()},v.appendChild(M);let u=document.createElement("button");u.type="button",u.className="dtk-ui-runbtn",u.textContent="Run pipeline",u.onclick=()=>T(),v.appendChild(u);let x=document.createElement("button");x.type="button",x.className="dtk-ui-newbtn",x.textContent="New metric",x.onclick=()=>G(),v.appendChild(x);let b=document.createElement("span");b.className="dtk-ui-progresschip",b.style.display="none",v.appendChild(b);function k(d,y){if(y===0||d>=y){b.style.display="none";return}b.textContent=`${d}/${y}`,b.style.display=""}let g=document.createElement("button");g.type="button",g.className="dtk-ui-jobschip",g.innerHTML='<span class="dtk-ui-jobschip-dot"></span><span>idle</span>',g.onclick=()=>{E.isOpen()?E.close():Y()},v.appendChild(g);function S(){let d=o.jobs.find(ae=>ae.status==="running");g.classList.toggle("running",!!d);let y=d?`${d.kind} ${d.label}`:"idle",R=g.querySelector("span:last-child");R&&(R.textContent=y),g.title=d?`Started ${new Date(d.started_at).toLocaleString()}`:"No jobs running"}let N=document.createElement("div");N.className="dtk-ui-nextsteps-box",n.appendChild(N);function L(){Qt(N,o.nextSteps,{onLoad:d=>{_(d)},onTune:d=>{ie(d)},onFollow:d=>ee(d),onDismiss:()=>{o.nextSteps=null,L()}})}async function _(d){if(!Q){Q=!0;try{let y=await Ue({select:d,steps:["load","detect"],from:null,to:null,full_refresh:!1,force:!1});W("run",`run --select ${d}`,y.job_id,null),o.nextSteps&&o.nextSteps.metric===d&&(o.nextSteps={metric:d,jobId:y.job_id,phase:"running"},L())}catch(y){de(n,"error",y.message)}finally{Q=!1}}}function A(){let d=o.nextSteps;if(!d||!d.jobId||d.phase!=="running")return;let y=o.jobs.find(R=>R.id===d.jobId);!y||y.status==="running"||(o.nextSteps={...d,phase:y.status==="done"?"done":"failed"},L())}let I=document.createElement("div");I.className="dtk-ui-content",n.appendChild(I);function z(){var se,pe;I.innerHTML="";let d=r.length;if(d===0){let H=document.createElement("div");H.className="dtk-ui-empty",H.textContent="No metrics found for this project/selector.",I.appendChild(H);return}let y=o.metrics.filter(H=>!H.pending),R=y.filter(H=>H.error!==null);if(y.length===d&&R.length===d){let H=document.createElement("div");H.className="dtk-ui-banner";let Ee=(pe=(se=R[0])==null?void 0:se.error)!=null?pe:"unknown error";H.innerHTML=`<span>Failed to load overview: every metric failed (${O(Ee)}).</span>`;let be=document.createElement("button");be.type="button",be.className="dtk-ui-banner-retry",be.textContent="Retry",be.onclick=()=>{P()},H.appendChild(be),I.appendChild(H)}I.appendChild(kt(o.metrics)),I.appendChild(xt(y,o.tagFilter,H=>{o.tagFilter=H,z()}));let ae=o.tagFilter===null?o.metrics:o.metrics.filter(H=>o.tagFilter===Re?H.tags.length===0:H.tags.includes(o.tagFilter)),re=Nt(ae,o.sort,Date.now(),{onOpen:K,onTune:H=>{ie(H)},onRun:H=>T(H),onEdit:H=>{U(H)},onSortChange:H=>{o.sort=o.sort.key===H?{key:H,dir:o.sort.dir==="asc"?"desc":"asc"}:{key:H,dir:Ke[H]},z()}});I.appendChild(re.el),re.paint()}function K(d){q()&&(a&&a.close(),a=Rt(n,d,o.windowPreset,{onTune:y=>{ie(y)},onClose:()=>{a=null}}))}function q(){return s?s.requestClose():!0}function G(){q()&&(a&&(a.close(),a=null),s=et(n,{mode:"create",text:Wt,meta:i},{onSaved:(d,y)=>B(d,y),onDeleted:()=>{},onClose:()=>{s=null}}))}async function U(d){var R,ae;if(!q())return;let y;try{y=await pt(d)}catch(re){de(n,"error",re.message);return}q()&&(a&&(a.close(),a=null),s=et(n,{mode:"edit",name:y.name,file:y.file,text:y.text,digest:y.digest,data:(R=y.data)!=null?R:null,parseError:(ae=y.parse_error)!=null?ae:null,meta:i},{onSaved:(re,se)=>B(re,se),onDeleted:re=>le(re),onClose:()=>{s=null}}))}function B(d,y){de(n,"info",`Metric '${d.name}' ${y==="create"?"created":"saved"}.`),d.note&&de(n,"info",d.note),y==="create"&&(o.nextSteps={metric:d.name,jobId:null,phase:"idle"},L()),y==="edit"&&!d.renamed_from?J(d.name,d.metrics):ne(d.metrics)}function le(d){de(n,"info",`Metric '${d.name}' deleted (archived).`),d.note&&de(n,"info",d.note),ne(d.metrics)}function ne(d){r=d,V.refreshOptions(),P()}function J(d,y){r=y,V.refreshOptions();let R=y.find(se=>se.name===d),ae=o.metrics.findIndex(se=>se.name===d);if(!R||ae===-1){P();return}let re=C;o.metrics[ae]=Se(R),z(),Je(d,o.windowPreset).then(se=>{if(re!==C)return;se.pending=!1;let pe=o.metrics.findIndex(H=>H.name===d);pe!==-1&&(o.metrics[pe]=se),z()}).catch(se=>{if(re!==C)return;let pe=o.metrics.findIndex(H=>H.name===d);pe!==-1&&(o.metrics[pe]={...Se(R),pending:!1,error:se.message}),z()})}let V=Dt(n,{submitRun:d=>{me(d)},submitAutotune:d=>{D(d)},submitUnlock:d=>{X(d)},getSelectOptions:p,isPipelineBusy:h}),E=$t(n,{onFollow:d=>ee(d),onStop:d=>{F(d)}});function T(d){E.close(),V.refreshOptions(),V.refreshBusyState(),V.open(d)}function Y(){V.close(),E.render(o.jobs,Date.now(),o.followedJobId),E.open(),fe()}function W(d,y,R,ae){let re={id:R,kind:d,label:y,status:"running",returncode:null,url:ae,started_at:Date.now(),finished_at:null};o.jobs=[re,...o.jobs.filter(se=>se.id!==R)],ce(),fe(),te()}let Q=!1,oe=new Set;async function me(d){if(!Q){Q=!0;try{let y=await Ue(d);W("run",`run --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{Q=!1}}}async function D(d){if(!Q){Q=!0;try{let y=await lt(d);W("autotune",`autotune --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{Q=!1}}}async function X(d){if(!Q){Q=!0;try{let y=await dt(d);W("unlock",`unlock --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{Q=!1}}}async function ie(d){if(!oe.has(d)){oe.add(d),de(n,"info",`Opening tuner for ${d}\u2026`);try{let y=await ct({metric:d});W("tune",`tune --select ${d}`,y.job_id,y.url),window.open(y.url,"_blank")}catch(y){de(n,"error",y.message)}finally{oe.delete(d)}}}async function F(d){try{await ut(d),de(n,"info","Stop requested."),te()}catch(y){de(n,"error",y.message)}}function ee(d){o.followedJobId=d,o.followOffset=0,T(),V.resetLog(),he(d)}function ce(){S(),E.render(o.jobs,Date.now(),o.followedJobId),V.refreshBusyState(),A()}async function te(){try{let d=await at();o.jobs=d.jobs}catch{}ce()}function fe(){if(f!==void 0)return;let d=()=>{te().then(()=>{f=E.isOpen()||o.jobs.some(R=>R.status==="running")?window.setTimeout(d,2e3):void 0})};f=window.setTimeout(d,2e3)}function we(){l!==void 0&&(window.clearTimeout(l),l=void 0)}function he(d){we();let y=()=>{st(d,o.followOffset).then(R=>{if(o.followedJobId===d){if(V.appendLog(R.lines),o.followOffset=R.next_offset,R.status!=="running"){V.setLogStatus(R.status,R.returncode),l=void 0,te();return}l=window.setTimeout(y,1e3)}}).catch(R=>{de(n,"error",`job ${d}: ${R.message}`),l=void 0})};l=window.setTimeout(y,0)}let C=0;async function P(){let d=++C,y=o.windowPreset,R=r;if(o.metrics=R.map(Se),M.classList.add("spinning"),k(0,R.length),z(),R.length===0){M.classList.remove("spinning"),k(0,0);return}let ae=[...R],re=0;async function se(){for(;;){if(d!==C)return;let H=ae.shift();if(!H)return;let Ee;try{Ee=await Je(H.name,y),Ee.pending=!1}catch(qe){Ee={...Se(H),pending:!1,error:qe.message}}if(d!==C)return;let be=o.metrics.findIndex(qe=>qe.name===H.name);be!==-1&&(o.metrics[be]=Ee),re++,k(re,R.length),z()}}let pe=Math.min(qn,R.length);await Promise.all(Array.from({length:pe},()=>se())),d===C&&(M.classList.remove("spinning"),k(re,R.length),V.refreshOptions())}z(),V.refreshOptions(),P(),te()}window.__DTK_UI__={render:zn};})();
518
+ - `)}`);return}}ie(!0);try{let P=F(),G=r?await mt({text:P,folder:(g==null?void 0:g.value.trim())||void 0}):await ft((C=t.name)!=null?C:"",{text:P,digest:t.digest});a=!1,n.onSaved(G,t.mode),te()}catch(P){z(P.message)}finally{ie(!1)}}}async function ce(C,P,G){if(!s){K(),s=!0,P.disabled=!0,G.disabled=!0,P.textContent="Deleting\u2026";try{let d=await bt(C);a=!1,n.onDeleted(d),te()}catch(d){z(d.message),P.disabled=!1,G.disabled=!1,P.textContent="Delete metric"}finally{s=!1}}}function te(){h.close(),n.onClose()}function fe(){return a&&!window.confirm("Discard unsaved changes?")?!1:(te(),!0)}return W(),u==="builder"&&I?I.focusFirst():_.focus(),T(),{close:te,requestClose:fe}}function Vt(e,t,n){if(e.innerHTML="",!t)return;let r=document.createElement("div");r.className="dtk-ui-nextsteps"+(t.phase==="failed"?" failed":"");let i=document.createElement("span");i.className="dtk-ui-nextsteps-text";let o=document.createElement("b");if(o.textContent=t.metric,t.phase==="done")i.append("Data loaded for ",o," \u2014 tune the detector on the real series.");else if(t.phase==="running"){i.append("Loading data for ",o,"\u2026 ");let u=document.createElement("a");u.href="#",u.className="dtk-ui-nextsteps-link",u.textContent="view log",u.onclick=h=>{h.preventDefault(),t.jobId&&n.onFollow(t.jobId)},i.appendChild(u)}else t.phase==="failed"?i.append("Loading data for ",o," failed \u2014 check the log, then retry."):i.append("Metric ",o," created. Next: load data, then tune the detector on it.");r.appendChild(i);let a=document.createElement("div");a.className="dtk-ui-nextsteps-actions";let s=document.createElement("button");if(s.type="button",s.className="dtk-ui-btn"+(t.phase==="idle"||t.phase==="failed"?" primary":""),s.textContent=t.phase==="failed"?"Retry load":"Load & detect",s.disabled=t.phase==="running",s.title="Runs `dtk run --steps load,detect` for this metric (no alerts sent)",s.onclick=()=>n.onLoad(t.metric),a.appendChild(s),t.phase==="running"){let u=document.createElement("span");u.className="dtk-ui-nextsteps-spin",a.appendChild(u)}let m=document.createElement("button");m.type="button",m.className="dtk-ui-btn"+(t.phase==="done"?" primary":""),m.textContent="Open tune",m.disabled=t.phase!=="done",m.title=t.phase==="done"?"Open the tune cockpit on the loaded series":"Load data first \u2014 the tune cockpit works on persisted datapoints",m.onclick=()=>n.onTune(t.metric),a.appendChild(m);let l=document.createElement("button");l.type="button",l.className="dtk-ui-nextsteps-close",l.textContent="\u2715",l.title="Dismiss",l.onclick=()=>n.onDismiss(),a.appendChild(l),r.appendChild(a),e.appendChild(r)}var Fn=3,zn=[{value:"24h",label:"24h"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"},{value:"all",label:"All"}];function Bn(e,t){var G;yt(),t.classList.add(ve),t.innerHTML="";let n=document.createElement("div");n.className=`${ve}-root`,t.appendChild(n);let r=e.metrics,i=(G=e.form_meta)!=null?G:{channels:[],profiles:[],default_profile:null},o={windowPreset:e.initial_window||"30d",metrics:r.map(Se),jobs:[],followedJobId:null,followOffset:0,tagFilter:null,sort:{key:"alerts",dir:Ke.alerts},nextSteps:null},a=null,s=null,m,l;function u(){let d=new Set,y=new Set;for(let R of r){d.add(R.name);for(let ae of R.tags)y.add(ae)}return[...d,...[...y].map(R=>`tag:${R}`)]}function h(){let d=o.jobs.find(y=>y.status==="running"&&y.kind!=="tune");return d?{busy:!0,reason:`a pipeline job is already running (${d.label})`}:{busy:!1,reason:""}}let f=document.createElement("div");f.className="dtk-ui-header",n.appendChild(f);let c=document.createElement("div");c.className="dtk-ui-brand",c.innerHTML=`<span class="dtk-ui-brand-dot"></span><span class="dtk-ui-brand-name">detectkit \xB7 <b>${O(e.project)}</b></span>`,f.appendChild(c);let v=document.createElement("div");v.className="dtk-ui-header-right",f.appendChild(v);let w=document.createElement("div");w.className="dtk-ui-seg";for(let d of zn){let y=document.createElement("button");y.type="button",y.className="dtk-ui-seg-btn"+(o.windowPreset===d.value?" on":""),y.textContent=d.label,y.onclick=()=>{o.windowPreset!==d.value&&(o.windowPreset=d.value,w.querySelectorAll(".dtk-ui-seg-btn").forEach(R=>R.classList.remove("on")),y.classList.add("on"),a&&a.setWindow(d.value),P())},w.appendChild(y)}v.appendChild(w);let M=document.createElement("button");M.type="button",M.className="dtk-ui-iconbtn",M.title="Refresh overview",M.textContent="\u27F3",M.onclick=()=>{P()},v.appendChild(M);let p=document.createElement("button");p.type="button",p.className="dtk-ui-runbtn",p.textContent="Run pipeline",p.onclick=()=>T(),v.appendChild(p);let x=document.createElement("button");x.type="button",x.className="dtk-ui-newbtn",x.textContent="New metric",x.onclick=()=>X(),v.appendChild(x);let b=document.createElement("span");b.className="dtk-ui-progresschip",b.style.display="none",v.appendChild(b);function k(d,y){if(y===0||d>=y){b.style.display="none";return}b.textContent=`${d}/${y}`,b.style.display=""}let g=document.createElement("button");g.type="button",g.className="dtk-ui-jobschip",g.innerHTML='<span class="dtk-ui-jobschip-dot"></span><span>idle</span>',g.onclick=()=>{E.isOpen()?E.close():Y()},v.appendChild(g);function S(){let d=o.jobs.find(ae=>ae.status==="running");g.classList.toggle("running",!!d);let y=d?`${d.kind} ${d.label}`:"idle",R=g.querySelector("span:last-child");R&&(R.textContent=y),g.title=d?`Started ${new Date(d.started_at).toLocaleString()}`:"No jobs running"}let N=document.createElement("div");N.className="dtk-ui-nextsteps-box",n.appendChild(N);function L(){Vt(N,o.nextSteps,{onLoad:d=>{_(d)},onTune:d=>{ie(d)},onFollow:d=>ee(d),onDismiss:()=>{o.nextSteps=null,L()}})}async function _(d){if(!V){V=!0;try{let y=await Ue({select:d,steps:["load","detect"],from:null,to:null,full_refresh:!1,force:!1});W("run",`run --select ${d}`,y.job_id,null),o.nextSteps&&o.nextSteps.metric===d&&(o.nextSteps={metric:d,jobId:y.job_id,phase:"running"},L())}catch(y){de(n,"error",y.message)}finally{V=!1}}}function I(){let d=o.nextSteps;if(!d||!d.jobId||d.phase!=="running")return;let y=o.jobs.find(R=>R.id===d.jobId);!y||y.status==="running"||(o.nextSteps={...d,phase:y.status==="done"?"done":"failed"},L())}let A=document.createElement("div");A.className="dtk-ui-content",n.appendChild(A);function z(){var se,pe;A.innerHTML="";let d=r.length;if(d===0){let H=document.createElement("div");H.className="dtk-ui-empty",H.textContent="No metrics found for this project/selector.",A.appendChild(H);return}let y=o.metrics.filter(H=>!H.pending),R=y.filter(H=>H.error!==null);if(y.length===d&&R.length===d){let H=document.createElement("div");H.className="dtk-ui-banner";let Ee=(pe=(se=R[0])==null?void 0:se.error)!=null?pe:"unknown error";H.innerHTML=`<span>Failed to load overview: every metric failed (${O(Ee)}).</span>`;let be=document.createElement("button");be.type="button",be.className="dtk-ui-banner-retry",be.textContent="Retry",be.onclick=()=>{P()},H.appendChild(be),A.appendChild(H)}A.appendChild(kt(o.metrics)),A.appendChild(xt(y,o.tagFilter,H=>{o.tagFilter=H,z()}));let ae=o.tagFilter===null?o.metrics:o.metrics.filter(H=>o.tagFilter===Re?H.tags.length===0:H.tags.includes(o.tagFilter)),re=Nt(ae,o.sort,Date.now(),{onOpen:K,onTune:H=>{ie(H)},onRun:H=>T(H),onEdit:H=>{U(H)},onSortChange:H=>{o.sort=o.sort.key===H?{key:H,dir:o.sort.dir==="asc"?"desc":"asc"}:{key:H,dir:Ke[H]},z()}});A.appendChild(re.el),re.paint()}function K(d){q()&&(a&&a.close(),a=Rt(n,d,o.windowPreset,{onTune:y=>{ie(y)},onClose:()=>{a=null}}))}function q(){return s?s.requestClose():!0}function X(){q()&&(a&&(a.close(),a=null),s=et(n,{mode:"create",text:Wt,meta:i},{onSaved:(d,y)=>B(d,y),onDeleted:()=>{},onClose:()=>{s=null}}))}async function U(d){var R,ae;if(!q())return;let y;try{y=await pt(d)}catch(re){de(n,"error",re.message);return}q()&&(a&&(a.close(),a=null),s=et(n,{mode:"edit",name:y.name,file:y.file,text:y.text,digest:y.digest,data:(R=y.data)!=null?R:null,parseError:(ae=y.parse_error)!=null?ae:null,meta:i},{onSaved:(re,se)=>B(re,se),onDeleted:re=>le(re),onClose:()=>{s=null}}))}function B(d,y){de(n,"info",`Metric '${d.name}' ${y==="create"?"created":"saved"}.`),d.note&&de(n,"info",d.note),y==="create"&&(o.nextSteps={metric:d.name,jobId:null,phase:"idle"},L()),y==="edit"&&!d.renamed_from?J(d.name,d.metrics):ne(d.metrics)}function le(d){de(n,"info",`Metric '${d.name}' deleted (archived).`),d.note&&de(n,"info",d.note),ne(d.metrics)}function ne(d){r=d,Q.refreshOptions(),P()}function J(d,y){r=y,Q.refreshOptions();let R=y.find(se=>se.name===d),ae=o.metrics.findIndex(se=>se.name===d);if(!R||ae===-1){P();return}let re=C;o.metrics[ae]=Se(R),z(),Je(d,o.windowPreset).then(se=>{if(re!==C)return;se.pending=!1;let pe=o.metrics.findIndex(H=>H.name===d);pe!==-1&&(o.metrics[pe]=se),z()}).catch(se=>{if(re!==C)return;let pe=o.metrics.findIndex(H=>H.name===d);pe!==-1&&(o.metrics[pe]={...Se(R),pending:!1,error:se.message}),z()})}let Q=Dt(n,{submitRun:d=>{me(d)},submitAutotune:d=>{D(d)},submitUnlock:d=>{Z(d)},getSelectOptions:u,isPipelineBusy:h}),E=$t(n,{onFollow:d=>ee(d),onStop:d=>{F(d)}});function T(d){E.close(),Q.refreshOptions(),Q.refreshBusyState(),Q.open(d)}function Y(){Q.close(),E.render(o.jobs,Date.now(),o.followedJobId),E.open(),fe()}function W(d,y,R,ae){let re={id:R,kind:d,label:y,status:"running",returncode:null,url:ae,started_at:Date.now(),finished_at:null};o.jobs=[re,...o.jobs.filter(se=>se.id!==R)],ce(),fe(),te()}let V=!1,oe=new Set;async function me(d){if(!V){V=!0;try{let y=await Ue(d);W("run",`run --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{V=!1}}}async function D(d){if(!V){V=!0;try{let y=await lt(d);W("autotune",`autotune --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{V=!1}}}async function Z(d){if(!V){V=!0;try{let y=await dt(d);W("unlock",`unlock --select ${d.select}`,y.job_id,null),ee(y.job_id)}catch(y){de(n,"error",y.message)}finally{V=!1}}}async function ie(d){if(!oe.has(d)){oe.add(d),de(n,"info",`Opening tuner for ${d}\u2026`);try{let y=await ct({metric:d});W("tune",`tune --select ${d}`,y.job_id,y.url),window.open(y.url,"_blank")}catch(y){de(n,"error",y.message)}finally{oe.delete(d)}}}async function F(d){try{await ut(d),de(n,"info","Stop requested."),te()}catch(y){de(n,"error",y.message)}}function ee(d){o.followedJobId=d,o.followOffset=0,T(),Q.resetLog(),he(d)}function ce(){S(),E.render(o.jobs,Date.now(),o.followedJobId),Q.refreshBusyState(),I()}async function te(){try{let d=await at();o.jobs=d.jobs}catch{}ce()}function fe(){if(m!==void 0)return;let d=()=>{te().then(()=>{m=E.isOpen()||o.jobs.some(R=>R.status==="running")?window.setTimeout(d,2e3):void 0})};m=window.setTimeout(d,2e3)}function we(){l!==void 0&&(window.clearTimeout(l),l=void 0)}function he(d){we();let y=()=>{st(d,o.followOffset).then(R=>{if(o.followedJobId===d){if(Q.appendLog(R.lines),o.followOffset=R.next_offset,R.status!=="running"){Q.setLogStatus(R.status,R.returncode),l=void 0,te();return}l=window.setTimeout(y,1e3)}}).catch(R=>{de(n,"error",`job ${d}: ${R.message}`),l=void 0})};l=window.setTimeout(y,0)}let C=0;async function P(){let d=++C,y=o.windowPreset,R=r;if(o.metrics=R.map(Se),M.classList.add("spinning"),k(0,R.length),z(),R.length===0){M.classList.remove("spinning"),k(0,0);return}let ae=[...R],re=0;async function se(){for(;;){if(d!==C)return;let H=ae.shift();if(!H)return;let Ee;try{Ee=await Je(H.name,y),Ee.pending=!1}catch(qe){Ee={...Se(H),pending:!1,error:qe.message}}if(d!==C)return;let be=o.metrics.findIndex(qe=>qe.name===H.name);be!==-1&&(o.metrics[be]=Ee),re++,k(re,R.length),z()}}let pe=Math.min(Fn,R.length);await Promise.all(Array.from({length:pe},()=>se())),d===C&&(M.classList.remove("spinning"),k(re,R.length),Q.refreshOptions())}z(),Q.refreshOptions(),P(),te()}window.__DTK_UI__={render:Bn};})();
@@ -841,10 +841,16 @@ class _Handler(BaseHTTPRequestHandler):
841
841
  error), so the detail rides in the body instead. Errors other than the
842
842
  routine bad-token 403 are also echoed to the terminal — a page stuck on
843
843
  a failing request should be diagnosable without opening devtools.
844
+ ``/api/metric-parse`` 400s are exempt too: that route powers the
845
+ editor's *live draft validation*, so "invalid config" is its routine,
846
+ per-keystroke outcome (surfaced in the page's validation chip), not an
847
+ operational error worth a terminal line.
844
848
  """
845
- if code >= 400 and code != 403:
849
+ path = urlparse(self.path).path
850
+ routine = code == 403 or (code == 400 and path == "/api/metric-parse")
851
+ if code >= 400 and not routine:
846
852
  first_line = detail.splitlines()[0] if detail else ""
847
- self._srv().echo(f" [ui] {code} {urlparse(self.path).path}: {first_line}")
853
+ self._srv().echo(f" [ui] {code} {path}: {first_line}")
848
854
  body = detail.encode("utf-8")
849
855
  self.send_response(code)
850
856
  self.send_header("Content-Type", "text/plain; charset=utf-8")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.55.0
3
+ Version: 0.55.2
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
File without changes
File without changes
File without changes