detectkit 0.56.0__tar.gz → 0.56.1__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.
- {detectkit-0.56.0/detectkit.egg-info → detectkit-0.56.1}/PKG-INFO +1 -1
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/__init__.py +1 -1
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/assets/ui.js +27 -20
- {detectkit-0.56.0 → detectkit-0.56.1/detectkit.egg-info}/PKG-INFO +1 -1
- {detectkit-0.56.0 → detectkit-0.56.1}/LICENSE +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/MANIFEST.in +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/README.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/branding.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/email.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/factory.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/mattermost.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/slack.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/telegram.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/channels/webhook.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_decision.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_recovery.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_replay.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/_types.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/_base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/_types.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/autotuner.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/axis_spec.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/config_emitter.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/crossval.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/detector_select.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/distribution.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/grid_search.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/labels.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/result.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/runner.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/scoring.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/seasonality_search.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/settings.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/autotune/window_select.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/_output.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/alerting.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/cli.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/overview.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/rules/project.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/assets/claude/skills/dtk-tune/SKILL.md +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/autotune.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/clean.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/init.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/init_claude.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/osi.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/run.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/test_alert.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/tune.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/ui.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/commands/unlock.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/cli/main.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/metric_config.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/metric_io.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/profile.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/project_config.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/config/validator.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/core/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/core/interval.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/core/models.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/_sql_manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/clickhouse_manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_alert_states.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_datapoints.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_detections.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_maintenance.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_metrics.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_schema.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/_tasks.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/internal_tables/manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/mysql_manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/postgres_manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/database/tables.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/factory.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/seasonality.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/_windowed.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/autoreg.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/iqr.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/mad.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/manual_bounds.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/detectors/statistical/zscore.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/loaders/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/loaders/metric_loader.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/loaders/query_template.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/error_dispatch.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/_base.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/_load_step.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/_types.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/orchestration/task_manager/manager.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/reporting/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/reporting/assets/report.js +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/reporting/builder.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/reporting/html_report.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/errors.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/exporter.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/importer.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/osi_model.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/semantic/query_gen.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/assets/tune.js +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/config_writer.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/html.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/payload.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/tuning/server.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/html.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/jobs.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/metric_files.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/overview.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/ui/server.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/utils/__init__.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/utils/datetime_utils.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/utils/env_interpolation.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/utils/json_utils.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit/utils/stats.py +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit.egg-info/SOURCES.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit.egg-info/dependency_links.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit.egg-info/entry_points.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit.egg-info/requires.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/detectkit.egg-info/top_level.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/pyproject.toml +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/requirements.txt +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/setup.cfg +0 -0
- {detectkit-0.56.0 → detectkit-0.56.1}/setup.py +0 -0
|
@@ -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.56.
|
|
7
|
+
__version__ = "0.56.1"
|
|
8
8
|
|
|
9
9
|
from detectkit.core.interval import Interval
|
|
10
10
|
from detectkit.core.models import ColumnDefinition, TableModel
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(()=>{var O=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function at(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
|
|
1
|
+
"use strict";(()=>{var O=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function at(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 xe(e){return e==null||!Number.isFinite(e)?"\u2014":(e*100).toFixed(1)+"%"}function Le(e){return e==null||!Number.isFinite(e)?"\u2014":Math.round(e).toLocaleString("en-US")}function Te(e){return e==null||!Number.isFinite(e)?"\u2014":`\u2248${e>=9.5?e.toFixed(0):e.toFixed(1)}/day`}function He(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 st(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 Ye(e){return new Date(e).toISOString().slice(0,19).replace("T"," ")}function je(e,t){return e===null?null:Math.max(0,e-(t!=null?t:0))}function De(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 lt(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 dt(e,t){let n;return()=>{n!==void 0&&window.clearTimeout(n),n=window.setTimeout(e,t)}}var on=new URLSearchParams(location.search).get("token")||"";function Ke(e,t){let n=new URL(e,location.origin);if(n.searchParams.set("token",on),t)for(let[r,i]of Object.entries(t))n.searchParams.set(r,i);return n.toString()}function qe(e,t){return Ke(`/metric/${encodeURIComponent(e)}`,{window:t})}async function ct(e){let t=await e.text().catch(()=>"");return new Error(t||`HTTP ${e.status}`)}async function $e(e,t){let n=await fetch(Ke(e,t));if(!n.ok)throw await ct(n);return n.json()}async function me(e,t){let n=await fetch(Ke(e),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw await ct(n);return n.json()}function We(e,t){return $e(`/api/stats/${encodeURIComponent(e)}`,{window:t})}function ut(){return $e("/api/jobs")}function Ve(e,t){return $e(`/api/job/${encodeURIComponent(e)}`,{offset:String(t)})}function Qe(e){return me("/api/run",e)}function pt(e){return me("/api/autotune",e)}function mt(e){return me("/api/unlock",e)}function ft(e){return me("/api/tune",e)}function bt(e){return $e(`/api/clean-preview/${encodeURIComponent(e)}`)}function gt(e){return me("/api/clean",e)}function ht(e){return me(`/api/job/${encodeURIComponent(e)}/stop`,{})}function vt(e){return $e(`/api/metric-source/${encodeURIComponent(e)}`)}function yt(e){return me("/api/metric-create",e)}function xt(e,t){return me(`/api/metric/${encodeURIComponent(e)}/update`,t)}function kt(e){return me(`/api/metric/${encodeURIComponent(e)}/delete`,{confirm:e})}function Ge(e){return me("/api/metric-parse",{text:e})}function wt(e){return me("/api/osi-inspect",{text:e})}function Et(e){return me("/api/osi-import",e)}var we="dtk-ui",Ct=!1;function St(){if(Ct)return;Ct=!0;let e=`
|
|
2
2
|
.${we}{
|
|
3
3
|
--clay:#d15b36;--clay-700:#b4471f;--ink:#1b1916;--paper:#f5f1e8;
|
|
4
4
|
--muted:#6e675b;--faint:#9a9384;
|
|
@@ -96,13 +96,18 @@
|
|
|
96
96
|
|
|
97
97
|
/* --- metrics table --------------------------------------------------------- */
|
|
98
98
|
.dtk-ui-table-wrap{background:var(--surface);border:1px solid var(--border);border-radius:12px;
|
|
99
|
-
overflow:hidden;}
|
|
99
|
+
overflow:hidden;overflow-x:auto;}
|
|
100
100
|
.dtk-ui-group + .dtk-ui-group{border-top:1px solid var(--border);}
|
|
101
101
|
.dtk-ui-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
|
|
102
102
|
padding:9px 14px;background:var(--surface-2);}
|
|
103
103
|
.dtk-ui-group-name{font-family:var(--mono);font-size:11.5px;color:var(--text);font-weight:600;}
|
|
104
104
|
.dtk-ui-group-sub{font-family:var(--mono);font-size:11px;color:var(--faint);}
|
|
105
|
-
|
|
105
|
+
/* table-layout:fixed + the <colgroup> in table.ts pin every column to the same
|
|
106
|
+
width in every group, so the blocks line up regardless of each block's
|
|
107
|
+
longest metric name; min-width keeps the columns usable on a narrow viewport
|
|
108
|
+
(the wrap scrolls horizontally instead of squeezing the Name column to zero). */
|
|
109
|
+
.dtk-ui-table{width:100%;min-width:1040px;table-layout:fixed;border-collapse:collapse;
|
|
110
|
+
font-size:12.5px;}
|
|
106
111
|
.dtk-ui-table thead th{text-align:left;padding:8px 12px;font-family:var(--mono);font-size:10.5px;
|
|
107
112
|
color:var(--faint);text-transform:uppercase;letter-spacing:0.05em;font-weight:600;
|
|
108
113
|
border-bottom:1px solid var(--border);white-space:nowrap;}
|
|
@@ -119,7 +124,10 @@
|
|
|
119
124
|
.dtk-ui-pending{font-family:var(--mono);color:var(--faint);}
|
|
120
125
|
.dtk-ui-dotcell{width:14px;}
|
|
121
126
|
.dtk-ui-dot{width:9px;height:9px;border-radius:50%;display:inline-block;cursor:help;}
|
|
122
|
-
|
|
127
|
+
/* Name is the one flexible column (no <col> width) \u2014 bound its content so a
|
|
128
|
+
long snake_case identifier wraps inside the cell instead of widening the
|
|
129
|
+
column and shoving the action buttons off the right edge. */
|
|
130
|
+
.dtk-ui-namecell{overflow-wrap:anywhere;}
|
|
123
131
|
.dtk-ui-name{font-weight:600;color:var(--text-strong);}
|
|
124
132
|
.dtk-ui-err-badge{color:var(--st-anomaly);margin-left:6px;cursor:help;font-weight:700;}
|
|
125
133
|
.dtk-ui-stalechip{font-family:var(--mono);font-size:9.5px;color:var(--st-nodata);
|
|
@@ -467,21 +475,20 @@
|
|
|
467
475
|
@media (max-width:860px){
|
|
468
476
|
.dtk-ui-drawer{width:100vw;}
|
|
469
477
|
.dtk-ui-row2{grid-template-columns:1fr;}
|
|
470
|
-
.dtk-ui-table-wrap{overflow-x:auto;}
|
|
471
478
|
}
|
|
472
|
-
`,t=document.createElement("style");t.setAttribute("data-dtk-ui",""),t.textContent=e,document.head.appendChild(t)}var Ee=null;function
|
|
479
|
+
`,t=document.createElement("style");t.setAttribute("data-dtk-ui",""),t.textContent=e,document.head.appendChild(t)}var Ee=null;function rn(e){return Ee&&Ee.isConnected||(Ee=document.createElement("div"),Ee.className="dtk-toasts",e.appendChild(Ee)),Ee}function Z(e,t,n){let r=rn(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 Ce(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 Mt(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 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=je(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 x=p.length===0?void 0:`worst: ${p[0].m.name}${Number.isFinite(p[0].lag)?` (${De(p[0].lag)})`:" (no data)"}`;t.innerHTML=Ce(`${r}/${n}`,"Metrics","enabled / total")+Ce(Le(o),"Alerts in window",l?Te(m):void 0)+Ce(Le(a),"No-data events")+Ce(Le(s),"Metrics alerting")+Ce(Le(p.length),"Stale metrics",x,{warn:p.length>0,err:p.length>0});let f=i.filter(c=>c.quality!==null);if(f.length>0){let c=0,v=0,w=0,S=0,u=0;for(let g of f){let C=g.quality;C&&(c+=C.caught,v+=C.incidents_in_window,w+=C.false_alerts,S+=g.alerts.anomaly,g.budget>u&&(u=g.budget))}let k=v>0?c/v:null,b=S>0?w/S:null,h=b!==null&&u>0&&b>u;t.innerHTML+=Ce(xe(k),"Labeled recall",`${f.length} metric(s) labeled`)+Ce(xe(b),"False-alert rate",h?`\u25B2 over ${xe(u)} budget`:void 0,{warn:h})}return t}var Pe="untagged";function an(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(Pe,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 Tt(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 an(e)){let a=document.createElement("button");a.type="button",a.className="dtk-ui-tag"+(t===o.tag?" on":"");let s=o.havePerDay?` \xB7 ${Te(o.perDaySum)}`:"";a.innerHTML=`<span class="dtk-ui-tag-name">${O(o.tag===Pe?Pe:`#${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 sn={"--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 ze(e){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()||sn[e]||"#888"}function ln(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 Nt(e,t){let[n,r,i]=ln(e);return`rgba(${n},${r},${i},${t})`}var ro=Number.isFinite;var Rt=140,_t=30;function Lt(e,t,n){let r=Math.max(1,window.devicePixelRatio||1);e.style.width=`${Rt}px`,e.style.height=`${_t}px`,e.width=Math.round(Rt*r),e.height=Math.round(_t*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,p=l-m||1,x=b=>o+(b-m)/p*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=Nt(ze("--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=ze("--term-text"),i.lineWidth=1*r,i.lineJoin="round",i.beginPath();let S=!1;for(let b of t){if(b.v===null||!Number.isFinite(b.v)){S=!1;continue}let h=x(b.t),g=w(b.v);S?i.lineTo(h,g):(i.moveTo(h,g),S=!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 k=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 h=1;h<u.length;h++){let[g,C]=u[h];if(b<=g){let[L,_]=u[h-1],T=g===L?0:(b-L)/(g-L);return _+(C-_)*T}}return u[u.length-1][1]};i.fillStyle=ze("--st-anomaly");for(let b of n){if(b<m||b>l)continue;let h=k(b);h!==null&&(i.beginPath(),i.arc(x(b),w(h),2*r,0,Math.PI*2),i.fill())}}var Fe='<span class="dtk-ui-pending">\xB7\xB7\xB7</span>';function Ne(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,stale_detectors: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 Xe={alerts:"desc",name:"asc",rate:"desc",freshness:"desc"};function $t(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=je(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 ${De(t)} excluded`:"",o=`lag ${De(n)} (${r.toFixed(1)}\xD7 interval)${i} \xB7 last point ${Ye(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 dn(e){return e.length===0?"":`<div class="dtk-ui-tagchips">${e.map(t=>`<span class="dtk-ui-tagchip">${O(t)}</span>`).join("")}</div>`}function cn(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(xe(t.recall))}</b></span> \xB7 <span class="dtk-ui-quality-chip">FDR <b>${O(xe(t.fdr))}</b></span> \xB7 <span class="dtk-ui-quality-chip">\u2713${t.reviewed_valid}</span></span>`}function un(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"}
|
|
473
480
|
alert rule: ${t}
|
|
474
|
-
file: ${e.file}`}function un(e,t,n,r){var L;let i=document.createElement("tr");i.className="dtk-ui-row"+(e.enabled?"":" disabled")+(e.error?" errored":"")+(e.pending?" pending":"");let o=$t(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>`:"",l=(L=e.stale_detectors)!=null?L:0,p=l>0?`<span class="dtk-ui-stalechip" title="${l} superseded detector generation(s) still stored for this metric \u2014 Open it and use 'Clean stale' to prune them">${l} stale</span>`:"";s.title=cn(e),s.innerHTML=`<span class="dtk-ui-name">${O(e.name)}</span>${m}${p}${ln(e.tags)}`,i.appendChild(s);let k=document.createElement("td");k.innerHTML=`<span class="dtk-ui-interval">${O(at(e.interval_seconds))}</span>`,i.appendChild(k);let f=document.createElement("td");if(f.className="dtk-ui-sparkcell",e.pending)f.innerHTML='<span class="dtk-ui-spark-loading">loading\u2026</span>';else if(e.spark.length===0)f.innerHTML='<span class="dtk-ui-spark-empty">no data yet</span>';else{let _=document.createElement("canvas");_.className="dtk-spark",f.appendChild(_),r.push({canvas:_,points:e.spark.map(([T,D])=>({t:T,v:D})),anoms:e.spark_anoms})}i.appendChild(f);let c=document.createElement("td");if(c.className="dtk-ui-alertscell",e.pending)c.innerHTML=Fe;else{let _=e.quality!==null&&e.quality.fdr!==null&&e.quality.fdr>e.budget,T="dtk-ui-alerts-n"+(e.alerts.anomaly>0?" hasany":"")+(_?" overbudget":""),D=e.alerts.per_day!==null?`<span class="dtk-ui-alerts-sub">\xB7 ${O(Te(e.alerts.per_day))}</span>`:"";c.innerHTML=`<span class="${T}">${e.alerts.anomaly}</span>${D}`}i.appendChild(c);let y=document.createElement("td");e.pending?y.innerHTML=Fe:e.alerts.last_ts!==null?y.innerHTML=`<span class="dtk-ui-lastalert" title="${O(Ye(e.alerts.last_ts))} UTC">${O(He(t,e.alerts.last_ts))}</span>`:y.innerHTML='<span class="dtk-ui-lastalert">\u2014</span>',i.appendChild(y);let w=document.createElement("td");w.innerHTML=e.pending?Fe:`<span class="dtk-ui-rate">${O(ke(e.anomaly_rate))}</span>`,i.appendChild(w);let S=document.createElement("td");S.innerHTML=e.pending?Fe:dn(e),i.appendChild(S);let u=document.createElement("td");u.innerHTML=e.locked?'<span class="dtk-ui-lock" title="pipeline lock currently held for this metric">LOCK</span>':"",i.appendChild(u);let x=document.createElement("td");x.className="dtk-ui-actionscell";let b=document.createElement("button");b.type="button",b.className="dtk-ui-actionbtn",b.textContent="Open",b.onclick=()=>n.onOpen(e.name);let h=document.createElement("button");h.type="button",h.className="dtk-ui-actionbtn",h.textContent="Tune",h.onclick=()=>n.onTune(e.name);let g=document.createElement("button");g.type="button",g.className="dtk-ui-actionbtn",g.textContent="Run",g.onclick=()=>n.onRun(e.name);let C=document.createElement("button");return C.type="button",C.className="dtk-ui-actionbtn",C.textContent="Edit",C.onclick=()=>n.onEdit(e.name),x.append(b,h,g,C),i.appendChild(x),i}function Dt(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 $t(e).rank}}function pn(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=Dt(o,t.key),m=Dt(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 mn=[{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 fn(e,t){let n=document.createElement("tr");for(let r of mn){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 bn(e){return e===""?"metrics/":`metrics/${e}/`}function Pt(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=lt(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=(m=a.get(l))!=null?m:[],k=document.createElement("div");k.className="dtk-ui-group";let f=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(bn(l))}</span><span class="dtk-ui-group-sub">${p.length} metric${p.length===1?"":"s"} \xB7 ${f} alert${f===1?"":"s"}</span>`,k.appendChild(c);let y=document.createElement("table");y.className="dtk-ui-table";let w=document.createElement("thead");w.appendChild(fn(t,r)),y.appendChild(w);let S=document.createElement("tbody");for(let u of pn(p,t))S.appendChild(un(u,n,r,i));y.appendChild(S),k.appendChild(y),o.appendChild(k)}return{el:o,paint:()=>{for(let l of i)Lt(l.canvas,l.points,l.anoms)}}}var gn='a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function Be(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(gn)).filter(w=>w.offsetParent!==null);if(p.length===0)return;let k=p[0],f=p[p.length-1],c=document.activeElement,y=c instanceof HTMLElement&&r.contains(c);l.shiftKey&&(!y||c===k)?(l.preventDefault(),f.focus()):!l.shiftKey&&(!y||c===f)&&(l.preventDefault(),k.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 Ot(e,t,n,r){let i=Be(e,{onRequestClose:()=>b()}),{modal:o}=i,a=n,s=document.createElement("div");s.className="dtk-ui-overlay-head",s.innerHTML=`<span><span class="dtk-ui-overlay-title">${O(t)}</span><span class="dtk-ui-overlay-sub">window: ${O(n)}</span></span>`;let m=document.createElement("div");m.className="dtk-ui-overlay-actions";let l=document.createElement("button");l.type="button",l.className="dtk-ui-btn",l.textContent="Clean stale",l.title="Remove stored detections/alert state from superseded detector configs (dtk clean)";let p=document.createElement("button");p.type="button",p.className="dtk-ui-btn",p.textContent="Tune",p.onclick=()=>r.onTune(t);let k=document.createElement("button");k.type="button",k.className="dtk-ui-overlay-close",k.textContent="\u2715",k.title="Close (Esc)",m.append(l,p,k),s.appendChild(m),o.appendChild(s);let f=document.createElement("div");f.className="dtk-ui-overlay-body";let c=document.createElement("div");c.className="dtk-ui-overlay-loading",c.innerHTML=`<span class="dtk-ui-overlay-spinner"></span><span>Building the report for <b>${O(t)}</b>\u2026</span>`,f.appendChild(c);let y=document.createElement("iframe");y.title=`detectkit report \u2014 ${t}`,y.style.visibility="hidden",y.addEventListener("load",()=>{c.style.display="none",y.style.visibility="visible"}),y.src=qe(t,n),f.appendChild(y),o.appendChild(f);function w(){c.style.display="",y.style.visibility="hidden",y.src=qe(t,a)}let S=null;function u(){S==null||S.remove(),S=null}function x(h){u(),S=document.createElement("div"),S.className="dtk-ui-cleanstrip";let g=[];if(h.stale_detectors.length>0){let H=h.stale_detectors.reduce((F,I)=>F+I.rows,0);g.push(`<b>${h.stale_detectors.length}</b> superseded detector generation(s) \u2014 <b>${H.toLocaleString()}</b> detection row(s)`)}h.stale_alert_states.length>0&&g.push(`<b>${h.stale_alert_states.length}</b> stale alert state(s)`);let C=h.warnings.length?`<div class="dtk-ui-cleanstrip-warn">${h.warnings.map(O).join(" \xB7 ")}</div>`:"",L=document.createElement("div");L.className="dtk-ui-cleanstrip-text",L.innerHTML=`Permanently delete ${g.join(" and ")}? The report will then show only the current config's detectors.${C}`;let _=document.createElement("div");_.className="dtk-ui-cleanstrip-actions";let T=document.createElement("button");T.type="button",T.className="dtk-ui-btn",T.textContent="Cancel",T.onclick=()=>u();let D=document.createElement("button");D.type="button",D.className="dtk-ui-btn danger",D.textContent="Delete stale data",D.onclick=async()=>{D.disabled=!0,T.disabled=!0,D.textContent="Cleaning\u2026",await r.onCleanExecute(t),o.isConnected&&u()},_.append(T,D),S.append(L,_),o.insertBefore(S,f)}l.onclick=async()=>{if(S){u();return}l.disabled=!0,l.textContent="Checking\u2026";let h=await r.onCleanPreview(t);l.disabled=!1,l.textContent="Clean stale",h&&x(h)};function b(){i.close(),r.onClose()}return k.onclick=b,{setWindow(h){a=h;let g=s.querySelector(".dtk-ui-overlay-sub");g&&(g.textContent=`window: ${h}`),c.style.display="",y.style.visibility="hidden",y.src=qe(t,h)},reload:w,close:b}}var It=/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/,At="dtk-ui-run-select-options";function Ht(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=At;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",At),s.innerHTML='<span class="dtk-ui-field-label">Select</span>',s.append(l,m),a.appendChild(s);let p=document.createElement("div");p.className="dtk-ui-field",p.innerHTML='<span class="dtk-ui-field-label">Steps</span>';let k=document.createElement("div");k.className="dtk-ui-checks";let f={};for(let N of["load","detect","alert"]){let U=document.createElement("label");U.className="dtk-ui-check";let Q=document.createElement("input");Q.type="checkbox",Q.checked=!0,Q.onchange=J,U.append(Q,document.createTextNode(N)),k.appendChild(U),f[N]=Q}p.appendChild(k),a.appendChild(p);let c=document.createElement("div");c.className="dtk-ui-row2";let y=document.createElement("div");y.className="dtk-ui-field",y.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,y.appendChild(w);let S=document.createElement("div");S.className="dtk-ui-field",S.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,S.appendChild(u),c.append(y,S),a.appendChild(c);let x=document.createElement("div");x.className="dtk-ui-checks";let b=document.createElement("label");b.className="dtk-ui-check";let h=document.createElement("input");h.type="checkbox",b.append(h,document.createTextNode("force (skip lock check)"));let g=document.createElement("label");g.className="dtk-ui-check";let C=document.createElement("input");C.type="checkbox",g.append(C,document.createTextNode("full refresh")),x.append(b,g),a.appendChild(x);let L=document.createElement("div");L.className="dtk-ui-btnrow";let _=document.createElement("button");_.type="button",_.className="dtk-ui-btn primary",_.textContent="Run";let T=document.createElement("button");T.type="button",T.className="dtk-ui-btn",T.textContent="Autotune";let D=document.createElement("button");D.type="button",D.className="dtk-ui-btn danger",D.textContent="Unlock",L.append(_,T,D),a.appendChild(L);let H=document.createElement("div");H.className="dtk-ui-reason",a.appendChild(H);let F=document.createElement("div");F.className="dtk-ui-field",F.innerHTML='<span class="dtk-ui-field-label">Log</span>';let I=document.createElement("div");I.className="dtk-ui-log";let Y=document.createElement("div");Y.className="dtk-ui-log-body";let V=document.createElement("div");V.className="dtk-ui-log-line",I.append(Y,V),F.appendChild(I),a.appendChild(F);let K=[];function W(){Y.innerHTML=K.length===0?'<span class="dtk-ui-log-empty">no output yet</span>':K.map(O).join("<br>")}W();function se(){return I.scrollTop+I.clientHeight>=I.scrollHeight-24}function te(){return Object.keys(f).filter(N=>f[N].checked)}function J(){let N=t.isPipelineBusy(),U=l.value.trim(),Q=w.value.trim()===""||It.test(w.value.trim()),ne=u.value.trim()===""||It.test(u.value.trim()),B="";N.busy?B=N.reason:U===""?B="select is required":!Q||!ne?B="from/to must be YYYY-MM-DD or YYYY-MM-DD HH:MM:SS":te().length===0&&(B="pick at least one step to run"),H.textContent=B,_.disabled=B!=="",T.disabled=N.busy||U===""||!Q||!ne,D.disabled=N.busy||U===""}function de(){return{select:l.value.trim(),steps:te(),from:w.value.trim()||null,to:u.value.trim()||null,full_refresh:C.checked,force:h.checked}}_.onclick=()=>t.submitRun(de()),T.onclick=()=>t.submitAutotune({select:l.value.trim(),from:w.value.trim()||null,to:u.value.trim()||null}),D.onclick=()=>{let N=l.value.trim();window.confirm(`Unlock the pipeline lock for "${N}"? Only do this if you're sure no dtk process is actually running against it.`)&&t.submitUnlock({select:N})};function E(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=E,n.onclick=E,e.append(n,r),{el:r,open(N){N&&(l.value=N),n.classList.add("open"),r.classList.add("open"),J()},close:E,isOpen(){return r.classList.contains("open")},refreshOptions(){m.innerHTML=["*",...t.getSelectOptions()].map(N=>`<option value="${O(N)}"></option>`).join("")},refreshBusyState:J,resetLog(){K=[],W(),V.textContent="",V.className="dtk-ui-log-line"},appendLog(N){if(N.length===0)return;let U=se();K.push(...N),W(),U&&(I.scrollTop=I.scrollHeight)},setLogStatus(N,U){if(N==="running")return;let Q=N==="done"&&U===0?"exit-ok":N==="stopped"?"exit-stop":"exit-fail";V.className=`dtk-ui-log-line ${Q}`,V.textContent=`\u2500\u2500 ${N} (exit ${U!=null?U:"?"}) \u2500\u2500`}}}function hn(e){return e==="done"?"var(--st-recovery)":e==="failed"?"var(--st-anomaly)":e==="running"?"var(--clay)":"var(--faint)"}function jt(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,p,k){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 y=document.createElement("div");y.className="dtk-ui-jobrow"+(c.id===k?" active":"");let w=c.status==="running"?" pulse":"",S=st(c.started_at,(f=c.finished_at)!=null?f: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:${hn(c.status)}"></span>${O(c.kind)} \xB7 ${O(c.status)}</span><span class="dtk-ui-jobrow-meta">${O(He(p,c.started_at))} \xB7 ${O(S)}</span>`,y.appendChild(u);let x=document.createElement("div");x.className="dtk-ui-jobrow-label",x.textContent=c.label,y.appendChild(x);let b=document.createElement("div");if(b.className="dtk-ui-jobrow-actions",c.status==="running"){let h=document.createElement("button");h.type="button",h.className="dtk-ui-actionbtn",h.textContent="Stop",h.onclick=g=>{g.stopPropagation(),t.onStop(c.id)},b.appendChild(h)}if(c.kind==="tune"&&c.url){let h=document.createElement("a");h.className="dtk-ui-joblink",h.href=c.url,h.target="_blank",h.rel="noopener",h.textContent="Open tuner",h.onclick=g=>g.stopPropagation(),b.appendChild(h)}b.childElementCount>0&&y.appendChild(b),y.onclick=()=>t.onFollow(c.id),s.appendChild(y)}}}}var vn=/^(true|false|null|yes|no|on|off|~)$/i,yn=/^[A-Za-z0-9_][A-Za-z0-9_.\-]*$/,kn=/^[-+.]?\d/;function qt(e){return!(!yn.test(e)||vn.test(e)||!Number.isNaN(Number(e))||kn.test(e))}function Oe(e){return JSON.stringify(e)}function xn(e){var o;let r=(e.endsWith(`
|
|
481
|
+
file: ${e.file}`}function pn(e,t,n,r){var L;let i=document.createElement("tr");i.className="dtk-ui-row"+(e.enabled?"":" disabled")+(e.error?" errored":"")+(e.pending?" pending":"");let o=$t(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>`:"",l=(L=e.stale_detectors)!=null?L:0,p=l>0?`<span class="dtk-ui-stalechip" title="${l} superseded detector generation(s) still stored for this metric \u2014 Open it and use 'Clean stale' to prune them">${l} stale</span>`:"";s.title=un(e),s.innerHTML=`<span class="dtk-ui-name">${O(e.name)}</span>${m}${p}${dn(e.tags)}`,i.appendChild(s);let x=document.createElement("td");x.innerHTML=`<span class="dtk-ui-interval">${O(at(e.interval_seconds))}</span>`,i.appendChild(x);let f=document.createElement("td");if(f.className="dtk-ui-sparkcell",e.pending)f.innerHTML='<span class="dtk-ui-spark-loading">loading\u2026</span>';else if(e.spark.length===0)f.innerHTML='<span class="dtk-ui-spark-empty">no data yet</span>';else{let _=document.createElement("canvas");_.className="dtk-spark",f.appendChild(_),r.push({canvas:_,points:e.spark.map(([T,D])=>({t:T,v:D})),anoms:e.spark_anoms})}i.appendChild(f);let c=document.createElement("td");if(c.className="dtk-ui-alertscell",e.pending)c.innerHTML=Fe;else{let _=e.quality!==null&&e.quality.fdr!==null&&e.quality.fdr>e.budget,T="dtk-ui-alerts-n"+(e.alerts.anomaly>0?" hasany":"")+(_?" overbudget":""),D=e.alerts.per_day!==null?`<span class="dtk-ui-alerts-sub">\xB7 ${O(Te(e.alerts.per_day))}</span>`:"";c.innerHTML=`<span class="${T}">${e.alerts.anomaly}</span>${D}`}i.appendChild(c);let v=document.createElement("td");e.pending?v.innerHTML=Fe:e.alerts.last_ts!==null?v.innerHTML=`<span class="dtk-ui-lastalert" title="${O(Ye(e.alerts.last_ts))} UTC">${O(He(t,e.alerts.last_ts))}</span>`:v.innerHTML='<span class="dtk-ui-lastalert">\u2014</span>',i.appendChild(v);let w=document.createElement("td");w.innerHTML=e.pending?Fe:`<span class="dtk-ui-rate">${O(xe(e.anomaly_rate))}</span>`,i.appendChild(w);let S=document.createElement("td");S.innerHTML=e.pending?Fe:cn(e),i.appendChild(S);let u=document.createElement("td");u.innerHTML=e.locked?'<span class="dtk-ui-lock" title="pipeline lock currently held for this metric">LOCK</span>':"",i.appendChild(u);let k=document.createElement("td");k.className="dtk-ui-actionscell";let b=document.createElement("button");b.type="button",b.className="dtk-ui-actionbtn",b.textContent="Open",b.onclick=()=>n.onOpen(e.name);let h=document.createElement("button");h.type="button",h.className="dtk-ui-actionbtn",h.textContent="Tune",h.onclick=()=>n.onTune(e.name);let g=document.createElement("button");g.type="button",g.className="dtk-ui-actionbtn",g.textContent="Run",g.onclick=()=>n.onRun(e.name);let C=document.createElement("button");return C.type="button",C.className="dtk-ui-actionbtn",C.textContent="Edit",C.onclick=()=>n.onEdit(e.name),k.append(b,h,g,C),i.appendChild(k),i}function Dt(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 $t(e).rank}}function mn(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=Dt(o,t.key),m=Dt(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 Pt=[{label:"\u25CF",key:"freshness",width:"22px"},{label:"Name",key:"name"},{label:"Interval",key:null,width:"84px"},{label:"Trend",key:null,width:"160px"},{label:"Alerts",key:"alerts",width:"96px"},{label:"Last alert",key:null,width:"104px"},{label:"Rate",key:"rate",width:"72px"},{label:"Quality",key:null,width:"150px"},{label:"",key:null,width:"44px"},{label:"",key:null,width:"244px"}];function fn(){let e=document.createElement("colgroup");for(let t of Pt){let n=document.createElement("col");t.width&&(n.style.width=t.width),e.appendChild(n)}return e}function bn(e,t){let n=document.createElement("tr");for(let r of Pt){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 gn(e){return e===""?"metrics/":`metrics/${e}/`}function Ot(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=lt(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=(m=a.get(l))!=null?m:[],x=document.createElement("div");x.className="dtk-ui-group";let f=p.reduce((u,k)=>u+k.alerts.anomaly,0),c=document.createElement("div");c.className="dtk-ui-group-head",c.innerHTML=`<span class="dtk-ui-group-name">${O(gn(l))}</span><span class="dtk-ui-group-sub">${p.length} metric${p.length===1?"":"s"} \xB7 ${f} alert${f===1?"":"s"}</span>`,x.appendChild(c);let v=document.createElement("table");v.className="dtk-ui-table",v.appendChild(fn());let w=document.createElement("thead");w.appendChild(bn(t,r)),v.appendChild(w);let S=document.createElement("tbody");for(let u of mn(p,t))S.appendChild(pn(u,n,r,i));v.appendChild(S),x.appendChild(v),o.appendChild(x)}return{el:o,paint:()=>{for(let l of i)Lt(l.canvas,l.points,l.anoms)}}}var hn='a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function Be(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(hn)).filter(w=>w.offsetParent!==null);if(p.length===0)return;let x=p[0],f=p[p.length-1],c=document.activeElement,v=c instanceof HTMLElement&&r.contains(c);l.shiftKey&&(!v||c===x)?(l.preventDefault(),f.focus()):!l.shiftKey&&(!v||c===f)&&(l.preventDefault(),x.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 It(e,t,n,r){let i=Be(e,{onRequestClose:()=>b()}),{modal:o}=i,a=n,s=document.createElement("div");s.className="dtk-ui-overlay-head",s.innerHTML=`<span><span class="dtk-ui-overlay-title">${O(t)}</span><span class="dtk-ui-overlay-sub">window: ${O(n)}</span></span>`;let m=document.createElement("div");m.className="dtk-ui-overlay-actions";let l=document.createElement("button");l.type="button",l.className="dtk-ui-btn",l.textContent="Clean stale",l.title="Remove stored detections/alert state from superseded detector configs (dtk clean)";let p=document.createElement("button");p.type="button",p.className="dtk-ui-btn",p.textContent="Tune",p.onclick=()=>r.onTune(t);let x=document.createElement("button");x.type="button",x.className="dtk-ui-overlay-close",x.textContent="\u2715",x.title="Close (Esc)",m.append(l,p,x),s.appendChild(m),o.appendChild(s);let f=document.createElement("div");f.className="dtk-ui-overlay-body";let c=document.createElement("div");c.className="dtk-ui-overlay-loading",c.innerHTML=`<span class="dtk-ui-overlay-spinner"></span><span>Building the report for <b>${O(t)}</b>\u2026</span>`,f.appendChild(c);let v=document.createElement("iframe");v.title=`detectkit report \u2014 ${t}`,v.style.visibility="hidden",v.addEventListener("load",()=>{c.style.display="none",v.style.visibility="visible"}),v.src=qe(t,n),f.appendChild(v),o.appendChild(f);function w(){c.style.display="",v.style.visibility="hidden",v.src=qe(t,a)}let S=null;function u(){S==null||S.remove(),S=null}function k(h){u(),S=document.createElement("div"),S.className="dtk-ui-cleanstrip";let g=[];if(h.stale_detectors.length>0){let H=h.stale_detectors.reduce((F,I)=>F+I.rows,0);g.push(`<b>${h.stale_detectors.length}</b> superseded detector generation(s) \u2014 <b>${H.toLocaleString()}</b> detection row(s)`)}h.stale_alert_states.length>0&&g.push(`<b>${h.stale_alert_states.length}</b> stale alert state(s)`);let C=h.warnings.length?`<div class="dtk-ui-cleanstrip-warn">${h.warnings.map(O).join(" \xB7 ")}</div>`:"",L=document.createElement("div");L.className="dtk-ui-cleanstrip-text",L.innerHTML=`Permanently delete ${g.join(" and ")}? The report will then show only the current config's detectors.${C}`;let _=document.createElement("div");_.className="dtk-ui-cleanstrip-actions";let T=document.createElement("button");T.type="button",T.className="dtk-ui-btn",T.textContent="Cancel",T.onclick=()=>u();let D=document.createElement("button");D.type="button",D.className="dtk-ui-btn danger",D.textContent="Delete stale data",D.onclick=async()=>{D.disabled=!0,T.disabled=!0,D.textContent="Cleaning\u2026",await r.onCleanExecute(t),o.isConnected&&u()},_.append(T,D),S.append(L,_),o.insertBefore(S,f)}l.onclick=async()=>{if(S){u();return}l.disabled=!0,l.textContent="Checking\u2026";let h=await r.onCleanPreview(t);l.disabled=!1,l.textContent="Clean stale",h&&k(h)};function b(){i.close(),r.onClose()}return x.onclick=b,{setWindow(h){a=h;let g=s.querySelector(".dtk-ui-overlay-sub");g&&(g.textContent=`window: ${h}`),c.style.display="",v.style.visibility="hidden",v.src=qe(t,h)},reload:w,close:b}}var At=/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/,Ht="dtk-ui-run-select-options";function jt(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=Ht;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",Ht),s.innerHTML='<span class="dtk-ui-field-label">Select</span>',s.append(l,m),a.appendChild(s);let p=document.createElement("div");p.className="dtk-ui-field",p.innerHTML='<span class="dtk-ui-field-label">Steps</span>';let x=document.createElement("div");x.className="dtk-ui-checks";let f={};for(let R of["load","detect","alert"]){let U=document.createElement("label");U.className="dtk-ui-check";let Q=document.createElement("input");Q.type="checkbox",Q.checked=!0,Q.onchange=J,U.append(Q,document.createTextNode(R)),x.appendChild(U),f[R]=Q}p.appendChild(x),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 S=document.createElement("div");S.className="dtk-ui-field",S.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,S.appendChild(u),c.append(v,S),a.appendChild(c);let k=document.createElement("div");k.className="dtk-ui-checks";let b=document.createElement("label");b.className="dtk-ui-check";let h=document.createElement("input");h.type="checkbox",b.append(h,document.createTextNode("force (skip lock check)"));let g=document.createElement("label");g.className="dtk-ui-check";let C=document.createElement("input");C.type="checkbox",g.append(C,document.createTextNode("full refresh")),k.append(b,g),a.appendChild(k);let L=document.createElement("div");L.className="dtk-ui-btnrow";let _=document.createElement("button");_.type="button",_.className="dtk-ui-btn primary",_.textContent="Run";let T=document.createElement("button");T.type="button",T.className="dtk-ui-btn",T.textContent="Autotune";let D=document.createElement("button");D.type="button",D.className="dtk-ui-btn danger",D.textContent="Unlock",L.append(_,T,D),a.appendChild(L);let H=document.createElement("div");H.className="dtk-ui-reason",a.appendChild(H);let F=document.createElement("div");F.className="dtk-ui-field",F.innerHTML='<span class="dtk-ui-field-label">Log</span>';let I=document.createElement("div");I.className="dtk-ui-log";let Y=document.createElement("div");Y.className="dtk-ui-log-body";let V=document.createElement("div");V.className="dtk-ui-log-line",I.append(Y,V),F.appendChild(I),a.appendChild(F);let K=[];function W(){Y.innerHTML=K.length===0?'<span class="dtk-ui-log-empty">no output yet</span>':K.map(O).join("<br>")}W();function se(){return I.scrollTop+I.clientHeight>=I.scrollHeight-24}function te(){return Object.keys(f).filter(R=>f[R].checked)}function J(){let R=t.isPipelineBusy(),U=l.value.trim(),Q=w.value.trim()===""||At.test(w.value.trim()),ne=u.value.trim()===""||At.test(u.value.trim()),B="";R.busy?B=R.reason:U===""?B="select is required":!Q||!ne?B="from/to must be YYYY-MM-DD or YYYY-MM-DD HH:MM:SS":te().length===0&&(B="pick at least one step to run"),H.textContent=B,_.disabled=B!=="",T.disabled=R.busy||U===""||!Q||!ne,D.disabled=R.busy||U===""}function de(){return{select:l.value.trim(),steps:te(),from:w.value.trim()||null,to:u.value.trim()||null,full_refresh:C.checked,force:h.checked}}_.onclick=()=>t.submitRun(de()),T.onclick=()=>t.submitAutotune({select:l.value.trim(),from:w.value.trim()||null,to:u.value.trim()||null}),D.onclick=()=>{let R=l.value.trim();window.confirm(`Unlock the pipeline lock for "${R}"? Only do this if you're sure no dtk process is actually running against it.`)&&t.submitUnlock({select:R})};function E(){n.classList.remove("open"),r.classList.remove("open")}return o.onclick=E,n.onclick=E,e.append(n,r),{el:r,open(R){R&&(l.value=R),n.classList.add("open"),r.classList.add("open"),J()},close:E,isOpen(){return r.classList.contains("open")},refreshOptions(){m.innerHTML=["*",...t.getSelectOptions()].map(R=>`<option value="${O(R)}"></option>`).join("")},refreshBusyState:J,resetLog(){K=[],W(),V.textContent="",V.className="dtk-ui-log-line"},appendLog(R){if(R.length===0)return;let U=se();K.push(...R),W(),U&&(I.scrollTop=I.scrollHeight)},setLogStatus(R,U){if(R==="running")return;let Q=R==="done"&&U===0?"exit-ok":R==="stopped"?"exit-stop":"exit-fail";V.className=`dtk-ui-log-line ${Q}`,V.textContent=`\u2500\u2500 ${R} (exit ${U!=null?U:"?"}) \u2500\u2500`}}}function vn(e){return e==="done"?"var(--st-recovery)":e==="failed"?"var(--st-anomaly)":e==="running"?"var(--clay)":"var(--faint)"}function qt(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,p,x){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===x?" active":"");let w=c.status==="running"?" pulse":"",S=st(c.started_at,(f=c.finished_at)!=null?f: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:${vn(c.status)}"></span>${O(c.kind)} \xB7 ${O(c.status)}</span><span class="dtk-ui-jobrow-meta">${O(He(p,c.started_at))} \xB7 ${O(S)}</span>`,v.appendChild(u);let k=document.createElement("div");k.className="dtk-ui-jobrow-label",k.textContent=c.label,v.appendChild(k);let b=document.createElement("div");if(b.className="dtk-ui-jobrow-actions",c.status==="running"){let h=document.createElement("button");h.type="button",h.className="dtk-ui-actionbtn",h.textContent="Stop",h.onclick=g=>{g.stopPropagation(),t.onStop(c.id)},b.appendChild(h)}if(c.kind==="tune"&&c.url){let h=document.createElement("a");h.className="dtk-ui-joblink",h.href=c.url,h.target="_blank",h.rel="noopener",h.textContent="Open tuner",h.onclick=g=>g.stopPropagation(),b.appendChild(h)}b.childElementCount>0&&v.appendChild(b),v.onclick=()=>t.onFollow(c.id),s.appendChild(v)}}}}var yn=/^(true|false|null|yes|no|on|off|~)$/i,xn=/^[A-Za-z0-9_][A-Za-z0-9_.\-]*$/,kn=/^[-+.]?\d/;function zt(e){return!(!xn.test(e)||yn.test(e)||!Number.isNaN(Number(e))||kn.test(e))}function Oe(e){return JSON.stringify(e)}function wn(e){var o;let r=(e.endsWith(`
|
|
475
482
|
`)?e.slice(0,-1):e).split(`
|
|
476
|
-
`),i=(o=r[0])!=null?o:"";return!(i.length===0||/^\s/.test(i)||r.some(a=>a.trim().length===0))}function
|
|
483
|
+
`),i=(o=r[0])!=null?o:"";return!(i.length===0||/^\s/.test(i)||r.some(a=>a.trim().length===0))}function En(e,t){let n=e.endsWith(`
|
|
477
484
|
`),i=(n?e.slice(0,-1):e).split(`
|
|
478
|
-
`).map(o=>t+o);return{indicator:n?"|":"|-",lines:i}}function
|
|
479
|
-
`)?n.push(...
|
|
480
|
-
`)?n.push(...
|
|
485
|
+
`).map(o=>t+o);return{indicator:n?"|":"|-",lines:i}}function Ft(e){if(typeof e=="string")return zt(e)?e:Oe(e);if(typeof e=="number"){if(!Number.isFinite(e))return Oe(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":Oe(String(e))}function Cn(e){return zt(e)?e:Oe(e)}function Bt(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Ze(e){let t={};for(let[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}function Jt(e,t,n){if(wn(t)){let{indicator:r,lines:i}=En(t,n);return[`${e}${r}`,...i]}return[`${e}${Oe(t)}`]}function et(e,t){let n=[],r=t+" ";for(let[i,o]of Object.entries(e)){if(o===void 0)continue;let a=Cn(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(...Ut(o,r)));else if(Bt(o)){let s=Ze(o);Object.keys(s).length===0?n.push(`${t}${a}: {}`):(n.push(`${t}${a}:`),n.push(...et(s,r)))}else typeof o=="string"&&o.includes(`
|
|
486
|
+
`)?n.push(...Jt(`${t}${a}: `,o,r)):n.push(`${t}${a}: ${Ft(o)}`)}return n}function Ut(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(...Ut(i,r)));else if(Bt(i)){let o=Ze(i);if(Object.keys(o).length===0)n.push(`${t}- {}`);else{let a=et(o,r);n.push(`${t}- ${a[0].slice(r.length)}`),n.push(...a.slice(1))}}else typeof i=="string"&&i.includes(`
|
|
487
|
+
`)?n.push(...Jt(`${t}- `,i,r)):n.push(`${t}- ${Ft(i)}`);return n}function Yt(e,t){let n=[];if(t)for(let i of t)for(let o of i.split(`
|
|
481
488
|
`))n.push(`# ${o}`);let r=Ze(e);return Object.keys(r).length===0?n.push("{}"):n.push(...et(r,"")),n.join(`
|
|
482
489
|
`)+`
|
|
483
|
-
`}var
|
|
484
|
-
`}function Kt(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=Mn(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,p=i.selectionEnd,k=i.value;i.value=`${k.slice(0,l)} ${k.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: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 P(e,t){let n=document.createElement(e);return t&&(n.className=t),n}function z(e,t,n){let r=P("div","dtk-ui-field"),i=P("span","dtk-ui-field-label");if(i.textContent=e,r.append(i,t),n){let o=P("div","dtk-ui-editor-hint");o.textContent=n,r.appendChild(o)}return r}function Se(e){let t=P("div","dtk-ui-form-sec"),n=P("div","dtk-ui-form-sec-head"),r=P("span","dtk-ui-form-sec-title");r.textContent=e,n.appendChild(r),t.appendChild(n);let i=P("div","dtk-ui-form-sec-body");return t.appendChild(i),{root:t,body:i}}function Gt(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=P("div","dtk-ui-form-adv-body");return t.appendChild(r),{details:t,body:r}}function Ne(e,t,n){let r=P("div","dtk-ui-chipinput"),i=P("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=P("span","dtk-ui-chip"),k=document.createElement("span");k.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()},p.append(k,f),i.appendChild(p)}}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 Tn=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 Rn(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e))Tn.has(n)||(t[n]=r);return t}function Nn(e){let{root:t,body:n}=Se("Preserved fields"),r=P("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=P("div","dtk-ui-preschips");for(let o of Object.keys(e)){let a=P("span","dtk-ui-preschip");a.textContent=o,i.appendChild(a)}return n.appendChild(i),t}var Wt=/^[\p{L}\p{N}_-]+$/u;function _n(e,t,n){let{root:r,body:i}=Se("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=P("div","dtk-ui-form-err-inline");function s(){let x=o.value.trim();a.textContent=x===""||Wt.test(x)?"":"letters, digits, _ and - only"}o.oninput=()=>{s(),n.onDirty()},s();let m=z("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(z("Description",l));let p=Array.isArray(e==null?void 0:e.tags)?e.tags.map(String):[],k=Ne(p,"add tag, Enter",()=>n.onDirty());i.appendChild(z("Tags",k.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 y=typeof(e==null?void 0:e.profile)=="string"?e.profile:"",w=y&&!t.profiles.includes(y)?[y,...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=y,f.onchange=()=>n.onDirty(),i.appendChild(z("Profile",f));let S=document.createElement("label");S.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(),S.append(u,document.createTextNode("Enabled")),i.appendChild(S),{el:r,getName:()=>o.value.trim(),getDescription:()=>l.value,getTags:()=>k.get(),getEnabled:()=>u.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"]:Wt.test(x)?[]:["name has invalid characters (use letters, digits, _ or -)"]}}}var Ln=["10min","1h","1d"],Dn=/^\d+(s|sec|secs|second|seconds|min|mins|minute|minutes|h|hr|hour|hours|d|day|days)?$/i;function $n(e,t){let{root:n,body:r}=Se("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=P("div","dtk-ui-form-err-inline");function a(){let g=i.value.trim();o.textContent=g===""||Dn.test(g)?"":"looks unusual \u2014 the server validates on save"}i.oninput=()=>{a(),t.onDirty()},a();let s=z("Interval",i),m=P("div","dtk-ui-chip-presets");for(let g of Ln){let C=document.createElement("button");C.type="button",C.className="dtk-ui-chip-preset",C.textContent=g,C.onclick=()=>{i.value=g,a(),t.onDirty()},m.appendChild(C)}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(z("Loading start time",l));let p=e!=null&&e.query_columns&&typeof e.query_columns=="object"?e.query_columns:{},k=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||k!==null&&k!==1e4||Object.keys(p).length>0,c=Gt("Advanced");c.details.open=f,r.appendChild(c.details);let y=document.createElement("input");y.type="text",y.className="dtk-ui-input",y.placeholder="e.g. 10min (optional)",y.value=(e==null?void 0:e.loading_delay)!==void 0&&(e==null?void 0:e.loading_delay)!==null?String(e.loading_delay):"",y.oninput=()=>t.onDirty(),c.body.appendChild(z("Loading delay",y,"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=k!==null&&k!==1e4?String(k):"",w.oninput=()=>t.onDirty(),c.body.appendChild(z("Loading batch size",w));let S=document.createElement("input");S.type="text",S.className="dtk-ui-input",S.placeholder="timestamp",S.value=typeof p.timestamp=="string"?p.timestamp:"",S.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=P("div","dtk-ui-row2");x.append(z("Timestamp column",S),z("Value column",u)),c.body.appendChild(x);let b=Array.isArray(p.seasonality)?p.seasonality.map(String):[],h=Ne(b,"add query column name, Enter",()=>t.onDirty());return c.body.appendChild(z("Seasonality columns (in query results)",h.el)),{el:n,getInterval:()=>i.value.trim(),getLoadingStartTime:()=>l.value.trim(),getLoadingDelay:()=>y.value.trim(),getLoadingBatchSize:()=>{let g=w.value.trim();if(!g)return null;let C=Math.round(Number(g));return Number.isFinite(C)&&C!==1e4?C:null},getQueryColumns:()=>{let g=S.value.trim(),C=u.value.trim(),L=h.get();if(!g&&!C&&L.length===0)return null;let _={};return g&&(_.timestamp=g),C&&(_.metric=C),L.length>0&&(_.seasonality=L),_},issues:()=>i.value.trim()===""?["interval is required"]:[]}}var ot=[{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 Pn(e,t){let{root:n,body:r}=Se("Seasonality"),i=new Set(Array.isArray(e==null?void 0:e.seasonality_columns)?e.seasonality_columns.map(String):[]),o={},a=P("div","dtk-ui-checks");for(let{key:s,label:m}of ot){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(m)),a.appendChild(l),o[s]=p}return r.appendChild(a),{el:n,getColumns:()=>ot.filter(s=>o[s.key].checked).map(s=>s.key),setColumns:s=>{let m=new Set(s);for(let{key:l}of ot)o[l].checked=m.has(l)}}}var Xt=["mad","zscore","iqr","autoreg","manual_bounds"];function Ie(e){return Xt.includes(e)}var Ae={mad:["threshold","window_size"],zscore:["threshold","window_size"],iqr:["threshold","window_size"],autoreg:["threshold","window_size","lags"],manual_bounds:["lower_bound","upper_bound"]},On={threshold:"Threshold",window_size:"Window size",lags:"Lags",lower_bound:"Lower bound",upper_bound:"Upper bound"},In={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 it(e){let t=e&&typeof e=="object"?{...e}:{},n=typeof t.type=="string"?t.type:"";if(!Ie(n))return{type:n,raw:t,extraParams:{},extrasOwner:n,fields:{}};let r=t.params&&typeof t.params=="object"?t.params:{},i=new Set(Ae[n]),o={};for(let[s,m]of Object.entries(r))i.has(s)||(o[s]=m);let a={};for(let s of Ae[n]){let m=r[s];m!=null&&(a[s]=String(m))}return{type:n,raw:t,extraParams:o,extrasOwner:n,fields:a}}function An(e){if(!Ie(e.type))return e.raw;let t=Ae[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 Hn(e,t,n){let{root:r,body:i}=Se("Detectors"),o=P("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=P("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(it):n==="create"?[it({type:"mad",params:{threshold:3,window_size:100}})]:[];function p(f){var S,u,x;let c=P("div","dtk-ui-detrow"),y=P("div","dtk-ui-detrow-head");if(Ie(f.type)){let b=document.createElement("select");b.className="dtk-ui-select";for(let h of Xt){let g=document.createElement("option");g.value=h,g.textContent=h,b.appendChild(g)}b.value=f.type,b.onchange=()=>{let h=b.value;if(!Ie(h))return;let g={};for(let C of Ae[h])f.fields[C]!==void 0&&(g[C]=f.fields[C]);f.type=h,f.fields=g,t.onDirty(),k()},y.appendChild(b)}else{let b=P("span","dtk-ui-detrow-readonly");b.textContent=`${f.type||"unknown type"} \u2014 preserved as-is, edit in the YAML tab`,y.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(),k()},y.appendChild(w),c.appendChild(y),Ie(f.type)){let b=P("div","dtk-ui-detrow-fields"),h=Ae[f.type];for(let L of h){let _=document.createElement("input");_.type="number",_.step="any",_.className="dtk-ui-input",_.placeholder=(S=In[f.type][L])!=null?S:"",_.value=(u=f.fields[L])!=null?u:"",_.oninput=()=>{f.fields[L]=_.value,t.onDirty()},b.appendChild(z((x=On[L])!=null?x:L,_))}c.appendChild(b);let g=new Set(h),C=Object.keys(f.extraParams).filter(L=>!g.has(L)).length;if(C>0){let L=P("span","dtk-ui-preschip");L.textContent=f.type===f.extrasOwner?`+${C} params preserved`:`${C} ${f.extrasOwner} param(s) withheld \u2014 switch the type back to restore`,c.appendChild(L)}}return c}function k(){a.innerHTML="";for(let f of l)a.appendChild(p(f))}return k(),s.onclick=()=>{l.push(it({type:"mad",params:{threshold:3,window_size:100}})),t.onDirty(),k()},{el:r,getData:()=>l.map(An),issues:()=>{let f=[];for(let c of l)if(c.type==="manual_bounds"){let y=c.fields.lower_bound,w=c.fields.upper_bound;(!y||y.trim()==="")&&(!w||w.trim()==="")&&f.push("a manual_bounds detector needs at least a lower or upper bound")}return f}}}var Vt=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 jn(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 qn(e,t,n){let{root:r,body:i}=Se("Alerting"),o=jn(e);if(o.mode==="verbatim"){let E=P("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,N]of Object.entries(a))Vt.has(E)||(s[E]=N);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 p=P("div","dtk-ui-alerting-fields");i.appendChild(p);let k=document.createElement("label");k.className="dtk-ui-check";let f=document.createElement("input");f.type="checkbox",f.checked=a.enabled!==!1,f.onchange=()=>n.onDirty(),k.append(f,document.createTextNode("Enabled (uncheck to keep the config but pause sending)")),p.appendChild(k);let c=new Set(t.channels.map(E=>E.name)),y=Array.isArray(a.channels)?a.channels.map(String):[],w=new Set(y.filter(E=>c.has(E))),S=y.filter(E=>!c.has(E)),u=P("div","dtk-ui-field"),x=P("span","dtk-ui-field-label");x.textContent="Channels",u.appendChild(x);let b=P("div","dtk-ui-checks");for(let E of t.channels){let N=document.createElement("label");N.className="dtk-ui-check";let U=document.createElement("input");U.type="checkbox",U.checked=w.has(E.name),U.onchange=()=>{U.checked?w.add(E.name):w.delete(E.name),n.onDirty()};let Q=P("span","dtk-ui-check-type");Q.textContent=`(${E.type})`,N.append(U,document.createTextNode(E.name+" "),Q),b.appendChild(N)}u.appendChild(b);let h=Ne(S,"add channel name, Enter",()=>n.onDirty());u.appendChild(h.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(z("Consecutive anomalies",g));let C=document.createElement("select");C.className="dtk-ui-select";for(let E of["same","any","up","down"]){let N=document.createElement("option");N.value=E,N.textContent=E,C.appendChild(N)}C.value=typeof a.direction=="string"?a.direction:"same",C.onchange=()=>n.onDirty(),p.appendChild(z("Direction",C));let L=document.createElement("label");L.className="dtk-ui-check";let _=document.createElement("input");_.type="checkbox",_.checked=a.no_data_alert===!0,_.onchange=()=>n.onDirty(),L.append(_,document.createTextNode("Alert on missing data")),p.appendChild(L);let T=document.createElement("label");T.className="dtk-ui-check";let D=document.createElement("input");D.type="checkbox",D.checked=a.notify_on_recovery===!0,D.onchange=()=>n.onDirty(),T.append(D,document.createTextNode("Notify on recovery")),p.appendChild(T);let H=document.createElement("input");H.type="text",H.className="dtk-ui-input",H.placeholder="e.g. 30min (optional)",H.value=a.alert_cooldown!==void 0&&a.alert_cooldown!==null?String(a.alert_cooldown):"",H.oninput=()=>n.onDirty(),p.appendChild(z("Alert cooldown",H));let F=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,I=Gt("Advanced");I.details.open=F,p.appendChild(I.details);let Y=document.createElement("input");Y.type="number",Y.min="1",Y.step="1",Y.className="dtk-ui-input",Y.value=String(typeof a.min_detectors=="number"?a.min_detectors:1),Y.oninput=()=>n.onDirty(),I.body.appendChild(z("Min detectors",Y));let V=P("div","dtk-ui-row2"),K=document.createElement("input");K.type="text",K.className="dtk-ui-input",K.placeholder="e.g. 30min",K.value=a.anomaly_window!==void 0&&a.anomaly_window!==null?String(a.anomaly_window):"",K.oninput=()=>n.onDirty();let W=document.createElement("input");W.type="number",W.min="0",W.max="1",W.step="0.05",W.className="dtk-ui-input",W.placeholder="e.g. 0.3",W.value=typeof a.min_anomaly_share=="number"?String(a.min_anomaly_share):"",W.oninput=()=>n.onDirty(),V.append(z("Anomaly window",K),z("Min anomaly share",W)),I.body.appendChild(V);let se=Array.isArray(a.mentions)?a.mentions.map(String):[],te=Ne(se,"add mention, Enter",()=>n.onDirty());I.body.appendChild(z("Mentions",te.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(),I.body.appendChild(z("Dashboard URL",J)),Object.keys(s).length>0){let E=P("span","dtk-ui-preschip");E.textContent=`+${Object.keys(s).length} fields preserved`,p.appendChild(E)}function de(){p.style.display=l.checked?"":"none"}return l.onchange=()=>{de(),n.onDirty()},de(),{el:r,getData:()=>{if(!l.checked)return;let E={enabled:f.checked},N=[...t.channels.filter(j=>w.has(j.name)).map(j=>j.name),...h.get()];N.length>0&&(E.channels=N);let U=Number(g.value);E.consecutive_anomalies=g.value.trim()!==""&&Number.isFinite(U)?Math.max(1,Math.round(U)):3,E.direction=C.value,E.no_data_alert=_.checked,E.notify_on_recovery=D.checked;let Q=H.value.trim();Q&&(E.alert_cooldown=Je(Q));let ne=Number(Y.value),B=Y.value.trim()!==""&&Number.isFinite(ne)?Math.max(1,Math.round(ne)):1;B!==1&&(E.min_detectors=B);let fe=K.value.trim(),$=W.value.trim();fe&&$&&(E.anomaly_window=Je(fe),E.min_anomaly_share=Number($));let G=te.get();G.length>0&&(E.mentions=G);let ie=J.value.trim();ie&&(E.dashboard_url=ie);for(let[j,re]of Object.entries(s))Vt.has(j)||(E[j]=re);return E},issues:()=>{if(!l.checked)return[];let E=K.value.trim(),N=W.value.trim();return E===""!=(N==="")?["anomaly window and min anomaly share must be set together"]:[]}}}function Qt(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 zn(e,t){let n=Qt(e==null?void 0:e.ai_context),{root:r,body:i}=Se("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=P("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(z("Instructions",m));let l=Ne(n.synonyms,"add synonym, Enter",()=>t.onDirty());s.appendChild(z("Synonyms",l.el));let p=Ne(n.examples,"add example, Enter",()=>t.onDirty());return s.appendChild(z("Examples",p.el)),{el:r,getData:()=>{let k=m.value.trim(),f=l.get(),c=p.get();if(!k&&f.length===0&&c.length===0)return;let y={};return k&&(y.instructions=k),f.length>0&&(y.synonyms=f),c.length>0&&(y.examples=c),y},setData:k=>{let f=Qt(k!=null?k:null);m.value=f.instructions,l.set(f.synonyms),p.set(f.examples),(f.instructions||f.synonyms.length>0||f.examples.length>0)&&(o.open=!0)}}}var Fn=`SELECT
|
|
490
|
+
`}var Sn=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+/)),tt=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/g,nt=/(--[^\n]*|\/\*[\s\S]*?\*\/)|('(?:''|[^'])*')|(\b\d+(?:\.\d+)?\b)|([A-Za-z_][A-Za-z0-9_]*)/g;function Kt(e){let t=[],n=0;nt.lastIndex=0;let r;for(;r=nt.exec(e);){r.index>n&&t.push({start:n,end:r.index,cls:null});let i=r.index,o=nt.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;Sn.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 Mn(e){let t=[];tt.lastIndex=0;let n;for(;n=tt.exec(e);)t.push({start:n.index,end:tt.lastIndex,text:n[0]});if(t.length===0)return Kt(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=Kt(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 Tn(e){return Mn(e).map(n=>n.cls?`<span class="${n.cls}">${O(n.text)}</span>`:O(n.text)).join("")+`
|
|
491
|
+
`}function Wt(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=Tn(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,p=i.selectionEnd,x=i.value;i.value=`${x.slice(0,l)} ${x.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: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 P(e,t){let n=document.createElement(e);return t&&(n.className=t),n}function z(e,t,n){let r=P("div","dtk-ui-field"),i=P("span","dtk-ui-field-label");if(i.textContent=e,r.append(i,t),n){let o=P("div","dtk-ui-editor-hint");o.textContent=n,r.appendChild(o)}return r}function Se(e){let t=P("div","dtk-ui-form-sec"),n=P("div","dtk-ui-form-sec-head"),r=P("span","dtk-ui-form-sec-title");r.textContent=e,n.appendChild(r),t.appendChild(n);let i=P("div","dtk-ui-form-sec-body");return t.appendChild(i),{root:t,body:i}}function Xt(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=P("div","dtk-ui-form-adv-body");return t.appendChild(r),{details:t,body:r}}function Re(e,t,n){let r=P("div","dtk-ui-chipinput"),i=P("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=P("span","dtk-ui-chip"),x=document.createElement("span");x.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()},p.append(x,f),i.appendChild(p)}}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 Nn=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 Rn(e){let t={};if(!e)return t;for(let[n,r]of Object.entries(e))Nn.has(n)||(t[n]=r);return t}function _n(e){let{root:t,body:n}=Se("Preserved fields"),r=P("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=P("div","dtk-ui-preschips");for(let o of Object.keys(e)){let a=P("span","dtk-ui-preschip");a.textContent=o,i.appendChild(a)}return n.appendChild(i),t}var Vt=/^[\p{L}\p{N}_-]+$/u;function Ln(e,t,n){let{root:r,body:i}=Se("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=P("div","dtk-ui-form-err-inline");function s(){let k=o.value.trim();a.textContent=k===""||Vt.test(k)?"":"letters, digits, _ and - only"}o.oninput=()=>{s(),n.onDirty()},s();let m=z("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(z("Description",l));let p=Array.isArray(e==null?void 0:e.tags)?e.tags.map(String):[],x=Re(p,"add tag, Enter",()=>n.onDirty());i.appendChild(z("Tags",x.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 k of w){let b=document.createElement("option");b.value=k,b.textContent=k,f.appendChild(b)}f.value=v,f.onchange=()=>n.onDirty(),i.appendChild(z("Profile",f));let S=document.createElement("label");S.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(),S.append(u,document.createTextNode("Enabled")),i.appendChild(S),{el:r,getName:()=>o.value.trim(),getDescription:()=>l.value,getTags:()=>x.get(),getEnabled:()=>u.checked,getProfile:()=>f.value.trim(),setName:k=>{o.value=k,s()},setDescription:k=>{l.value=k},focusName:()=>o.focus(),issues:()=>{let k=o.value.trim();return k===""?["name is required"]:Vt.test(k)?[]:["name has invalid characters (use letters, digits, _ or -)"]}}}var Dn=["10min","1h","1d"],$n=/^\d+(s|sec|secs|second|seconds|min|mins|minute|minutes|h|hr|hour|hours|d|day|days)?$/i;function Pn(e,t){let{root:n,body:r}=Se("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=P("div","dtk-ui-form-err-inline");function a(){let g=i.value.trim();o.textContent=g===""||$n.test(g)?"":"looks unusual \u2014 the server validates on save"}i.oninput=()=>{a(),t.onDirty()},a();let s=z("Interval",i),m=P("div","dtk-ui-chip-presets");for(let g of Dn){let C=document.createElement("button");C.type="button",C.className="dtk-ui-chip-preset",C.textContent=g,C.onclick=()=>{i.value=g,a(),t.onDirty()},m.appendChild(C)}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(z("Loading start time",l));let p=e!=null&&e.query_columns&&typeof e.query_columns=="object"?e.query_columns:{},x=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||x!==null&&x!==1e4||Object.keys(p).length>0,c=Xt("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(z("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=x!==null&&x!==1e4?String(x):"",w.oninput=()=>t.onDirty(),c.body.appendChild(z("Loading batch size",w));let S=document.createElement("input");S.type="text",S.className="dtk-ui-input",S.placeholder="timestamp",S.value=typeof p.timestamp=="string"?p.timestamp:"",S.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 k=P("div","dtk-ui-row2");k.append(z("Timestamp column",S),z("Value column",u)),c.body.appendChild(k);let b=Array.isArray(p.seasonality)?p.seasonality.map(String):[],h=Re(b,"add query column name, Enter",()=>t.onDirty());return c.body.appendChild(z("Seasonality columns (in query results)",h.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 C=Math.round(Number(g));return Number.isFinite(C)&&C!==1e4?C:null},getQueryColumns:()=>{let g=S.value.trim(),C=u.value.trim(),L=h.get();if(!g&&!C&&L.length===0)return null;let _={};return g&&(_.timestamp=g),C&&(_.metric=C),L.length>0&&(_.seasonality=L),_},issues:()=>i.value.trim()===""?["interval is required"]:[]}}var ot=[{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 On(e,t){let{root:n,body:r}=Se("Seasonality"),i=new Set(Array.isArray(e==null?void 0:e.seasonality_columns)?e.seasonality_columns.map(String):[]),o={},a=P("div","dtk-ui-checks");for(let{key:s,label:m}of ot){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(m)),a.appendChild(l),o[s]=p}return r.appendChild(a),{el:n,getColumns:()=>ot.filter(s=>o[s.key].checked).map(s=>s.key),setColumns:s=>{let m=new Set(s);for(let{key:l}of ot)o[l].checked=m.has(l)}}}var Zt=["mad","zscore","iqr","autoreg","manual_bounds"];function Ie(e){return Zt.includes(e)}var Ae={mad:["threshold","window_size"],zscore:["threshold","window_size"],iqr:["threshold","window_size"],autoreg:["threshold","window_size","lags"],manual_bounds:["lower_bound","upper_bound"]},In={threshold:"Threshold",window_size:"Window size",lags:"Lags",lower_bound:"Lower bound",upper_bound:"Upper bound"},An={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 it(e){let t=e&&typeof e=="object"?{...e}:{},n=typeof t.type=="string"?t.type:"";if(!Ie(n))return{type:n,raw:t,extraParams:{},extrasOwner:n,fields:{}};let r=t.params&&typeof t.params=="object"?t.params:{},i=new Set(Ae[n]),o={};for(let[s,m]of Object.entries(r))i.has(s)||(o[s]=m);let a={};for(let s of Ae[n]){let m=r[s];m!=null&&(a[s]=String(m))}return{type:n,raw:t,extraParams:o,extrasOwner:n,fields:a}}function Hn(e){if(!Ie(e.type))return e.raw;let t=Ae[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 jn(e,t,n){let{root:r,body:i}=Se("Detectors"),o=P("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=P("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(it):n==="create"?[it({type:"mad",params:{threshold:3,window_size:100}})]:[];function p(f){var S,u,k;let c=P("div","dtk-ui-detrow"),v=P("div","dtk-ui-detrow-head");if(Ie(f.type)){let b=document.createElement("select");b.className="dtk-ui-select";for(let h of Zt){let g=document.createElement("option");g.value=h,g.textContent=h,b.appendChild(g)}b.value=f.type,b.onchange=()=>{let h=b.value;if(!Ie(h))return;let g={};for(let C of Ae[h])f.fields[C]!==void 0&&(g[C]=f.fields[C]);f.type=h,f.fields=g,t.onDirty(),x()},v.appendChild(b)}else{let b=P("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(),x()},v.appendChild(w),c.appendChild(v),Ie(f.type)){let b=P("div","dtk-ui-detrow-fields"),h=Ae[f.type];for(let L of h){let _=document.createElement("input");_.type="number",_.step="any",_.className="dtk-ui-input",_.placeholder=(S=An[f.type][L])!=null?S:"",_.value=(u=f.fields[L])!=null?u:"",_.oninput=()=>{f.fields[L]=_.value,t.onDirty()},b.appendChild(z((k=In[L])!=null?k:L,_))}c.appendChild(b);let g=new Set(h),C=Object.keys(f.extraParams).filter(L=>!g.has(L)).length;if(C>0){let L=P("span","dtk-ui-preschip");L.textContent=f.type===f.extrasOwner?`+${C} params preserved`:`${C} ${f.extrasOwner} param(s) withheld \u2014 switch the type back to restore`,c.appendChild(L)}}return c}function x(){a.innerHTML="";for(let f of l)a.appendChild(p(f))}return x(),s.onclick=()=>{l.push(it({type:"mad",params:{threshold:3,window_size:100}})),t.onDirty(),x()},{el:r,getData:()=>l.map(Hn),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 Qt=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 qn(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 zn(e,t,n){let{root:r,body:i}=Se("Alerting"),o=qn(e);if(o.mode==="verbatim"){let E=P("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,R]of Object.entries(a))Qt.has(E)||(s[E]=R);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 p=P("div","dtk-ui-alerting-fields");i.appendChild(p);let x=document.createElement("label");x.className="dtk-ui-check";let f=document.createElement("input");f.type="checkbox",f.checked=a.enabled!==!1,f.onchange=()=>n.onDirty(),x.append(f,document.createTextNode("Enabled (uncheck to keep the config but pause sending)")),p.appendChild(x);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))),S=v.filter(E=>!c.has(E)),u=P("div","dtk-ui-field"),k=P("span","dtk-ui-field-label");k.textContent="Channels",u.appendChild(k);let b=P("div","dtk-ui-checks");for(let E of t.channels){let R=document.createElement("label");R.className="dtk-ui-check";let U=document.createElement("input");U.type="checkbox",U.checked=w.has(E.name),U.onchange=()=>{U.checked?w.add(E.name):w.delete(E.name),n.onDirty()};let Q=P("span","dtk-ui-check-type");Q.textContent=`(${E.type})`,R.append(U,document.createTextNode(E.name+" "),Q),b.appendChild(R)}u.appendChild(b);let h=Re(S,"add channel name, Enter",()=>n.onDirty());u.appendChild(h.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(z("Consecutive anomalies",g));let C=document.createElement("select");C.className="dtk-ui-select";for(let E of["same","any","up","down"]){let R=document.createElement("option");R.value=E,R.textContent=E,C.appendChild(R)}C.value=typeof a.direction=="string"?a.direction:"same",C.onchange=()=>n.onDirty(),p.appendChild(z("Direction",C));let L=document.createElement("label");L.className="dtk-ui-check";let _=document.createElement("input");_.type="checkbox",_.checked=a.no_data_alert===!0,_.onchange=()=>n.onDirty(),L.append(_,document.createTextNode("Alert on missing data")),p.appendChild(L);let T=document.createElement("label");T.className="dtk-ui-check";let D=document.createElement("input");D.type="checkbox",D.checked=a.notify_on_recovery===!0,D.onchange=()=>n.onDirty(),T.append(D,document.createTextNode("Notify on recovery")),p.appendChild(T);let H=document.createElement("input");H.type="text",H.className="dtk-ui-input",H.placeholder="e.g. 30min (optional)",H.value=a.alert_cooldown!==void 0&&a.alert_cooldown!==null?String(a.alert_cooldown):"",H.oninput=()=>n.onDirty(),p.appendChild(z("Alert cooldown",H));let F=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,I=Xt("Advanced");I.details.open=F,p.appendChild(I.details);let Y=document.createElement("input");Y.type="number",Y.min="1",Y.step="1",Y.className="dtk-ui-input",Y.value=String(typeof a.min_detectors=="number"?a.min_detectors:1),Y.oninput=()=>n.onDirty(),I.body.appendChild(z("Min detectors",Y));let V=P("div","dtk-ui-row2"),K=document.createElement("input");K.type="text",K.className="dtk-ui-input",K.placeholder="e.g. 30min",K.value=a.anomaly_window!==void 0&&a.anomaly_window!==null?String(a.anomaly_window):"",K.oninput=()=>n.onDirty();let W=document.createElement("input");W.type="number",W.min="0",W.max="1",W.step="0.05",W.className="dtk-ui-input",W.placeholder="e.g. 0.3",W.value=typeof a.min_anomaly_share=="number"?String(a.min_anomaly_share):"",W.oninput=()=>n.onDirty(),V.append(z("Anomaly window",K),z("Min anomaly share",W)),I.body.appendChild(V);let se=Array.isArray(a.mentions)?a.mentions.map(String):[],te=Re(se,"add mention, Enter",()=>n.onDirty());I.body.appendChild(z("Mentions",te.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(),I.body.appendChild(z("Dashboard URL",J)),Object.keys(s).length>0){let E=P("span","dtk-ui-preschip");E.textContent=`+${Object.keys(s).length} fields preserved`,p.appendChild(E)}function de(){p.style.display=l.checked?"":"none"}return l.onchange=()=>{de(),n.onDirty()},de(),{el:r,getData:()=>{if(!l.checked)return;let E={enabled:f.checked},R=[...t.channels.filter(j=>w.has(j.name)).map(j=>j.name),...h.get()];R.length>0&&(E.channels=R);let U=Number(g.value);E.consecutive_anomalies=g.value.trim()!==""&&Number.isFinite(U)?Math.max(1,Math.round(U)):3,E.direction=C.value,E.no_data_alert=_.checked,E.notify_on_recovery=D.checked;let Q=H.value.trim();Q&&(E.alert_cooldown=Je(Q));let ne=Number(Y.value),B=Y.value.trim()!==""&&Number.isFinite(ne)?Math.max(1,Math.round(ne)):1;B!==1&&(E.min_detectors=B);let fe=K.value.trim(),$=W.value.trim();fe&&$&&(E.anomaly_window=Je(fe),E.min_anomaly_share=Number($));let G=te.get();G.length>0&&(E.mentions=G);let ie=J.value.trim();ie&&(E.dashboard_url=ie);for(let[j,re]of Object.entries(s))Qt.has(j)||(E[j]=re);return E},issues:()=>{if(!l.checked)return[];let E=K.value.trim(),R=W.value.trim();return E===""!=(R==="")?["anomaly window and min anomaly share must be set together"]:[]}}}function Gt(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 Fn(e,t){let n=Gt(e==null?void 0:e.ai_context),{root:r,body:i}=Se("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=P("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(z("Instructions",m));let l=Re(n.synonyms,"add synonym, Enter",()=>t.onDirty());s.appendChild(z("Synonyms",l.el));let p=Re(n.examples,"add example, Enter",()=>t.onDirty());return s.appendChild(z("Examples",p.el)),{el:r,getData:()=>{let x=m.value.trim(),f=l.get(),c=p.get();if(!x&&f.length===0&&c.length===0)return;let v={};return x&&(v.instructions=x),f.length>0&&(v.synonyms=f),c.length>0&&(v.examples=c),v},setData:x=>{let f=Gt(x!=null?x:null);m.value=f.instructions,l.set(f.synonyms),p.set(f.examples),(f.instructions||f.synonyms.length>0||f.examples.length>0)&&(o.open=!0)}}}var Bn=`SELECT
|
|
485
492
|
toStartOfInterval(event_time, INTERVAL {{ interval_seconds }} SECOND) AS timestamp,
|
|
486
493
|
count() AS value
|
|
487
494
|
FROM my_table
|
|
@@ -489,7 +496,7 @@ WHERE event_time >= '{{ dtk_start_time }}'
|
|
|
489
496
|
AND event_time < '{{ dtk_end_time }}'
|
|
490
497
|
GROUP BY timestamp
|
|
491
498
|
ORDER BY timestamp
|
|
492
|
-
`;function
|
|
499
|
+
`;function Jn(e){let t=e.trim();return/^\d+$/.test(t)?`${t}s`:t}function Un(e,t,n,r,i){let o=P("div","dtk-ui-form-query"),a=P("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=P("div","dtk-ui-subtab-panes");o.appendChild(l);let p=P("div","dtk-ui-subtab-pane"),x=P("div","dtk-ui-subtab-pane");x.style.display="none",l.append(p,x);function f($){s.classList.toggle("on",$==="sql"),m.classList.toggle("on",$==="osi"),p.style.display=$==="sql"?"":"none",x.style.display=$==="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:"",S=typeof(e==null?void 0:e.query)=="string"?e.query:e===null&&!c?Bn:"",u=null;if(c){u=document.createElement("div");let $=document.createElement("input");$.type="text",$.className="dtk-ui-input",$.readOnly=!0,$.value=c,u.appendChild(z("Query file (read-only)",$)),p.appendChild(u)}let k=Wt({value:S,onInput:()=>t.onDirty(),ariaLabel:"Metric SQL query"});p.appendChild(k.el),c&&k.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)",x.appendChild(z("OSI model",b));let h=P("div","dtk-ui-form-hint-status");x.appendChild(h);let g=document.createElement("select");g.className="dtk-ui-select",g.disabled=!0,x.appendChild(z("Metric",g));let C=document.createElement("select");C.className="dtk-ui-select";for(let $ of["clickhouse","cube"]){let G=document.createElement("option");G.value=$,G.textContent=$,C.appendChild(G)}x.appendChild(z("Target",C));let L=document.createElement("select");L.className="dtk-ui-select";let _=z("Dataset (optional)",L);x.appendChild(_);let T=document.createElement("input");T.type="text",T.className="dtk-ui-input",T.placeholder="time column (auto-detected if omitted)";let D=z("Time field (optional)",T);x.appendChild(D);let H=document.createElement("input");H.type="text",H.className="dtk-ui-input",H.placeholder="extra WHERE condition (optional)",x.appendChild(z("Where (optional)",H));let F=document.createElement("input");F.type="text",F.className="dtk-ui-input",F.placeholder="cube name";let I=z("Cube (optional)",F);x.appendChild(I);let Y=document.createElement("input");Y.type="text",Y.className="dtk-ui-input",Y.placeholder="measure name (defaults to the metric name)";let V=z("Cube measure (optional)",Y);x.appendChild(V);let K=document.createElement("input");K.type="text",K.className="dtk-ui-input",K.placeholder="time dimension";let W=z("Time dimension (cube)",K);x.appendChild(W);function se(){let $=C.value==="cube";_.style.display=$?"none":"",D.style.display=$?"none":"",I.style.display=$?"":"none",V.style.display=$?"":"none",W.style.display=$?"":"none"}C.onchange=()=>{se()},se();let te=document.createElement("button");te.type="button",te.className="dtk-ui-btn primary",te.textContent="Compile",x.appendChild(te);let J=P("div","dtk-ui-form-err");x.appendChild(J);let de=P("div","dtk-ui-form-warn");x.appendChild(de);let E=[],R=null;function U(){let $=g.value.indexOf("::");return $===-1?-1:Number(g.value.slice(0,$))}function Q(){let $=g.value.indexOf("::");return $===-1?g.value:g.value.slice($+2)}function ne(){var ie;L.innerHTML="";let $=document.createElement("option");$.value="",$.textContent="(auto)",L.appendChild($);let G=E[U()];for(let j of(ie=G==null?void 0:G.datasets)!=null?ie:[]){let re=document.createElement("option");re.value=j,re.textContent=j,L.appendChild(re)}}function B(){if(g.innerHTML="",E.length===0){g.disabled=!0,ne();return}g.disabled=!1;let $=E.length>1;E.forEach((G,ie)=>{let j=$?document.createElement("optgroup"):null;j&&(j.label=G.name,g.appendChild(j));for(let re of G.metrics){let be=document.createElement("option");be.value=`${ie}::${re}`,be.textContent=re,(j!=null?j:g).appendChild(be)}}),ne()}g.onchange=()=>{ne()};let fe=dt(()=>{let $=b.value;if($.trim()===""){E=[],B(),h.textContent="",J.textContent="";return}h.textContent="Inspecting\u2026",t.osiInspect($).then(G=>{E=G.models,B();let ie=E.reduce((j,re)=>j+re.metrics.length,0);h.textContent=ie>0?`Found ${ie} metric(s) across ${E.length} model(s).`:"No metrics found.",J.textContent=""}).catch(G=>{E=[],B(),h.textContent="",J.textContent=G.message})},400);return b.addEventListener("input",()=>{fe()}),te.onclick=()=>{J.textContent="",de.innerHTML="";let $=b.value;if($.trim()===""){J.textContent="paste an OSI model first";return}if(g.value===""){J.textContent="pick a metric to import";return}let G=n();if(!G){J.textContent="set an interval in Schedule & loading first";return}let ie=C.value,j={text:$,metric:Q(),interval:Jn(G),target:ie},re=r();re.length>0&&(j.seasonality=re),ie==="clickhouse"?(L.value&&(j.dataset=L.value),T.value.trim()&&(j.time_field=T.value.trim()),H.value.trim()&&(j.where=H.value.trim())):(F.value.trim()&&(j.cube=F.value.trim()),Y.value.trim()&&(j.cube_measure=Y.value.trim()),K.value.trim()&&(j.time_dimension=K.value.trim()),H.value.trim()&&(j.where=H.value.trim()));let be=Q();te.disabled=!0,te.textContent="Compiling\u2026",t.osiImport(j).then(ae=>{let ke=typeof ae.body.query=="string"?ae.body.query:ae.sql;if(k.setValue(ke),k.setDisabled(!1),u&&(u.style.display="none"),v="inline",w="",f("sql"),R={fingerprint:ae.fingerprint,target:ae.target,metric:be},i(ae.body,ae.name||be),ae.warnings.length>0)for(let ge of ae.warnings){let ve=document.createElement("div");ve.textContent=`\u26A0 ${ge}`,de.appendChild(ve)}t.onDirty()}).catch(ae=>{J.textContent=ae.message}).finally(()=>{te.disabled=!1,te.textContent="Compile"})},{el:o,getMode:()=>v,getQuery:()=>k.getValue(),getFilePath:()=>w,getOsiProvenance:()=>R,issues:()=>v==="inline"&&k.getValue().trim()===""?["query is empty"]:[]}}function en(e,t,n,r){let i=document.createElement("div");i.className="dtk-ui-form";let o,a,s,m,l,p,x,f={};function c(u){i.innerHTML="";let k=P("div","dtk-ui-form-rail"),b=P("div","dtk-ui-form-main");i.append(k,b),f=Rn(u),o=Ln(u,t,n),a=Pn(u,n),s=On(u,n),m=jn(u,n,r.mode),l=zn(u,t,n),p=Fn(u,n),k.append(o.el,a.el,s.el,m.el,l.el,p.el),Object.keys(f).length>0&&k.appendChild(_n(f)),x=Un(u,n,()=>a.getInterval(),()=>s.getColumns(),(h,g)=>{r.mode==="create"&&(o.getName()===""||o.getName()==="my_metric")&&o.setName(g),typeof h.description=="string"&&o.setDescription(h.description),h.ai_context&&typeof h.ai_context=="object"&&p.setData(h.ai_context),Array.isArray(h.seasonality_columns)&&s.setColumns(h.seasonality_columns.map(String))}),b.appendChild(x.el)}c(e);function v(){let u={},k=o.getName();k&&(u.name=k);let b=o.getDescription().trim();b&&(u.description=b);let h=o.getTags();h.length>0&&(u.tags=h);let g=o.getProfile();g&&(u.profile=g);let C=p.getData();C&&(u.ai_context=C),x.getMode()==="file"?u.query_file=x.getFilePath():u.query=x.getQuery();let L=a.getQueryColumns();L&&(u.query_columns=L);let _=a.getInterval();_&&(u.interval=Je(_));let T=a.getLoadingStartTime();T&&(u.loading_start_time=T);let D=a.getLoadingDelay();D&&(u.loading_delay=Je(D));let H=a.getLoadingBatchSize();H!==null&&(u.loading_batch_size=H);let F=s.getColumns();F.length>0&&(u.seasonality_columns=F);let I=m.getData();I.length>0&&(u.detectors=I);let Y=l.getData();Y!==void 0&&(u.alerting=Y);for(let[V,K]of Object.entries(f))u[V]=K;return o.getEnabled()||(u.enabled=!1),u}function w(){let u=v(),k=x.getOsiProvenance(),b=k?[`Query compiled from OSI metric '${k.metric}' (target: ${k.target}, sql-fingerprint: ${k.fingerprint}).`,"Review the SQL before saving \u2014 re-compiling after the OSI model changes is a visible diff."]:void 0;return Yt(u,b)}function S(){return[...o.issues(),...a.issues(),...x.issues(),...m.issues(),...l.issues()]}return{el:i,setFromData:u=>c(u),toData:v,toYaml:w,clientIssues:S,focusFirst:()=>o.focusName()}}var tn=`# New metric \u2014 edit the query and name, then Create.
|
|
493
500
|
# Template variables available in query:
|
|
494
501
|
# {{ dtk_start_time }} / {{ dtk_end_time }} \u2014 load window bounds
|
|
495
502
|
# {{ interval_seconds }} \u2014 metric interval in seconds
|
|
@@ -519,13 +526,13 @@ detectors:
|
|
|
519
526
|
# enabled: true
|
|
520
527
|
# channels: [my_channel]
|
|
521
528
|
# consecutive_anomalies: 3
|
|
522
|
-
`,
|
|
523
|
-
`),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=p=>p.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 rt(e,t,n){var ge,ve;let r=t.mode==="create",i=(ge=t.meta)!=null?ge:
|
|
524
|
-
${t.parseError}`:"Builder unavailable for this file"),u.onclick=()=>{B("builder")};let
|
|
525
|
-
`));return}}let q=p==="builder"&&D?D.toYaml():T.value;E("checking","checking\u2026");try{if(await Ge(q),M!==de)return;E("ok","\u2713 valid config")}catch(X){if(M!==de)return;let pe=X.message;E("err",
|
|
529
|
+
`,Yn={channels:[],profiles:[],default_profile:null};function Kn(e){var l;let t=e.split(`
|
|
530
|
+
`),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=p=>p.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 rt(e,t,n){var ge,ve;let r=t.mode==="create",i=(ge=t.meta)!=null?ge:Yn,o=r||t.data!==null&&t.data!==void 0,a=!1,s=!1,m=!1,l=!1,p=o?"builder":"yaml",x=Be(e,{modalClass:"dtk-ui-editor-modal",onRequestClose:()=>{ke()}}),{modal:f}=x,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 ${(ve=t.name)!=null?ve:""}`,v.appendChild(w),!r&&t.file){let M=document.createElement("span");M.className="dtk-ui-editor-sub",M.textContent=t.file,v.appendChild(M)}c.appendChild(v);let S=document.createElement("div");S.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.
|
|
531
|
+
${t.parseError}`:"Builder unavailable for this file"),u.onclick=()=>{B("builder")};let k=document.createElement("button");k.type="button",k.className="dtk-ui-edtab",k.textContent="YAML",k.onclick=()=>{B("yaml")},S.append(u,k),c.appendChild(S);let b=document.createElement("button");b.type="button",b.className="dtk-ui-overlay-close",b.textContent="\u2715",b.title="Close (Esc)",b.onclick=()=>{ke()},c.appendChild(b),f.appendChild(c);let h=document.createElement("div");h.className="dtk-ui-editor-body",f.appendChild(h);let g=null;if(r){let M=document.createElement("div");M.className="dtk-ui-editor-field",M.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/",M.appendChild(g);let q=document.createElement("div");q.className="dtk-ui-editor-hint",q.textContent="The file is written as metrics/[folder/]<name>.yml \u2014 <name> comes from the metric name below.",M.appendChild(q),h.appendChild(M)}let C=!r&&/(^|\n)\s*#/.test(t.text),L=document.createElement("div");L.className="dtk-ui-editor-note",L.textContent="Saving from Builder re-writes the YAML \u2014 comments are dropped (the previous file is archived to metrics/.history/).",L.style.display="none",h.appendChild(L);let _=document.createElement("div");_.className="dtk-ui-editor-panes",h.appendChild(_);let T=document.createElement("textarea");T.className="dtk-ui-editor-textarea",T.spellcheck=!1,T.autocapitalize="off",T.value=t.text,T.addEventListener("input",()=>{a=!0,l=!0,R()}),T.addEventListener("keydown",M=>{if(M.key==="Tab"){M.preventDefault();let q=T.selectionStart,X=T.selectionEnd;T.value=`${T.value.slice(0,q)} ${T.value.slice(X)}`,T.selectionStart=T.selectionEnd=q+2,a=!0,l=!0,R()}});let D=null;o&&(D=en(r?null:t.data,i,{onDirty:()=>{a=!0,m=!0,R()},osiInspect:M=>wt(M),osiImport:M=>Et(M)},{mode:t.mode}),_.appendChild(D.el)),_.appendChild(T),f.addEventListener("keydown",M=>{(M.ctrlKey||M.metaKey)&&M.key.toLowerCase()==="s"&&(M.preventDefault(),re())});let H=document.createElement("div");H.className="dtk-ui-editor-error",H.style.display="none",f.appendChild(H);function F(M){H.textContent=M,H.style.display=""}function I(){H.style.display="none",H.textContent=""}let Y=document.createElement("div");Y.className="dtk-ui-editor-foot";let V=document.createElement("div");V.className="dtk-ui-editor-foot-left";let K=document.createElement("div");K.className="dtk-ui-editor-foot-right",Y.append(V,K),f.appendChild(Y);let W=document.createElement("span");W.className="dtk-ui-validchip",W.style.display="none",K.appendChild(W);let se=document.createElement("button");se.type="button",se.className="dtk-ui-btn primary";let te=r?"Create metric":"Save changes";se.textContent=te,se.onclick=()=>{re()},K.appendChild(se);let J,de=0;function E(M,q,X){W.className=`dtk-ui-validchip ${M}`,W.innerHTML='<span class="dtk-ui-validchip-dot"></span>',W.appendChild(document.createTextNode(q)),W.title=X!=null?X:q,W.style.display=""}function R(){J!==void 0&&window.clearTimeout(J),J=window.setTimeout(()=>{J=void 0,U()},600)}async function U(){let M=++de;if(D&&(p==="builder"||!l)){let X=D.clientIssues();if(X.length>0){E("warn",X[0],X.join(`
|
|
532
|
+
`));return}}let q=p==="builder"&&D?D.toYaml():T.value;E("checking","checking\u2026");try{if(await Ge(q),M!==de)return;E("ok","\u2713 valid config")}catch(X){if(M!==de)return;let pe=X.message;E("err",Kn(pe),pe)}}function Q(){u.classList.toggle("on",p==="builder"),k.classList.toggle("on",p==="yaml"),D&&(D.el.style.display=p==="builder"?"":"none"),T.style.display=p==="yaml"?"":"none",L.style.display=p==="builder"&&C?"":"none"}let ne=!1;async function B(M){if(!(M===p||s||ne)&&!(M==="builder"&&!D)){ne=!0;try{await fe(M)}finally{ne=!1}}}async function fe(M){if(M==="yaml")m&&D&&(T.value=D.toYaml(),m=!1,l=!1);else if(l&&D){I();try{let q=await Ge(T.value);D.setFromData(q.data),l=!1,m=!1}catch(q){if(!window.confirm(`The YAML doesn't validate:
|
|
526
533
|
${q.message}
|
|
527
534
|
|
|
528
535
|
Return to the Builder anyway? Your YAML edits will be discarded (the Builder keeps its own last state).`)){F(`Fix the YAML (or discard it via the Builder tab):
|
|
529
|
-
${q.message}`);return}l=!1,m=!0}}I(),p=M,Q(),
|
|
536
|
+
${q.message}`);return}l=!1,m=!0}}I(),p=M,Q(),R()}function $(){let M=document.createElement("button");return M.type="button",M.className="dtk-ui-btn danger",M.textContent="Delete metric\u2026",M.onclick=()=>G(),M}r||V.appendChild($());function G(){var _e,d;let M=(_e=t.name)!=null?_e:"",q=(d=t.file)!=null?d:"";V.innerHTML="";let X=document.createElement("div");X.className="dtk-ui-editor-confirm";let pe=document.createElement("span");pe.className="dtk-ui-editor-confirm-text",pe.innerHTML=`Delete <b>${O(M)}</b>? The file <code>${O(q)}</code> is archived to <code>metrics/.history/</code> and removed. Data rows in the <code>_dtk_*</code> tables remain until <code>dtk clean</code>.`,X.appendChild(pe);let ce=document.createElement("button");ce.type="button",ce.className="dtk-ui-btn danger",ce.textContent="Delete metric",ce.onclick=()=>{be(M,ce,ue)};let ue=document.createElement("button");ue.type="button",ue.className="dtk-ui-btn",ue.textContent="Cancel",ue.onclick=()=>{V.innerHTML="",V.appendChild($())},X.append(ce,ue),V.appendChild(X)}function ie(M){s=M,se.disabled=M,se.textContent=M?"Saving\u2026":te}function j(){return p==="builder"&&D&&m?D.toYaml():T.value}async function re(){var M;if(!s){if(I(),D&&(p==="builder"||!l)){let q=D.clientIssues();if(q.length>0){F(`Fix before saving:
|
|
530
537
|
- ${q.join(`
|
|
531
|
-
- `)}`);return}}ie(!0);try{let q=j(),X=r?await yt({text:q,folder:(g==null?void 0:g.value.trim())||void 0}):await kt((M=t.name)!=null?M:"",{text:q,digest:t.digest});a=!1,n.onSaved(X,t.mode),ae()}catch(q){F(q.message)}finally{ie(!1)}}}async function be(M,q,X){if(!s){I(),s=!0,q.disabled=!0,X.disabled=!0,q.textContent="Deleting\u2026";try{let pe=await xt(M);a=!1,n.onDeleted(pe),ae()}catch(pe){F(pe.message),q.disabled=!1,X.disabled=!1,q.textContent="Delete metric"}finally{s=!1}}}function ae(){k.close(),n.onClose()}function xe(){return a&&!window.confirm("Discard unsaved changes?")?!1:(ae(),!0)}return Q(),p==="builder"&&D?D.focusFirst():T.focus(),N(),{close:ae,requestClose:xe}}function tn(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=k=>{k.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 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 Kn=3,Wn=[{value:"24h",label:"24h"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"},{value:"all",label:"All"}];function Vn(e,t){var _e;St(),t.classList.add(we),t.innerHTML="";let n=document.createElement("div");n.className=`${we}-root`,t.appendChild(n);let r=e.metrics,i=(_e=e.form_meta)!=null?_e:{channels:[],profiles:[],default_profile:null},o={windowPreset:e.initial_window||"30d",metrics:r.map(Re),jobs:[],followedJobId:null,followOffset:0,tagFilter:null,sort:{key:"alerts",dir:Xe.alerts},nextSteps:null},a=null,s=null,m=null,l,p;function k(){let d=new Set,v=new Set;for(let R of r){d.add(R.name);for(let oe of R.tags)v.add(oe)}return[...d,...[...v].map(R=>`tag:${R}`)]}function f(){let d=o.jobs.find(v=>v.status==="running"&&v.kind!=="tune");return d?{busy:!0,reason:`a pipeline job is already running (${d.label})`}:{busy:!1,reason:""}}let c=document.createElement("div");c.className="dtk-ui-header",n.appendChild(c);let y=document.createElement("div");y.className="dtk-ui-brand",y.innerHTML=`<span class="dtk-ui-brand-dot"></span><span class="dtk-ui-brand-name">detectkit \xB7 <b>${O(e.project)}</b></span>`,c.appendChild(y);let w=document.createElement("div");w.className="dtk-ui-header-right",c.appendChild(w);let S=document.createElement("div");S.className="dtk-ui-seg";for(let d of Wn){let v=document.createElement("button");v.type="button",v.className="dtk-ui-seg-btn"+(o.windowPreset===d.value?" on":""),v.textContent=d.label,v.onclick=()=>{o.windowPreset!==d.value&&(o.windowPreset=d.value,S.querySelectorAll(".dtk-ui-seg-btn").forEach(R=>R.classList.remove("on")),v.classList.add("on"),a&&a.setWindow(d.value),ue())},S.appendChild(v)}w.appendChild(S);let u=document.createElement("button");u.type="button",u.className="dtk-ui-iconbtn",u.title="Refresh overview",u.textContent="\u27F3",u.onclick=()=>{ue()},w.appendChild(u);let x=document.createElement("button");x.type="button",x.className="dtk-ui-runbtn",x.textContent="Run pipeline",x.onclick=()=>U(),w.appendChild(x);let b=document.createElement("button");b.type="button",b.className="dtk-ui-newbtn",b.textContent="New metric",b.onclick=()=>K(),w.appendChild(b);let h=document.createElement("span");h.className="dtk-ui-progresschip",h.style.display="none",w.appendChild(h);function g(d,v){if(v===0||d>=v){h.style.display="none";return}h.textContent=`${d}/${v}`,h.style.display=""}let C=document.createElement("button");C.type="button",C.className="dtk-ui-jobschip",C.innerHTML='<span class="dtk-ui-jobschip-dot"></span><span>idle</span>',C.onclick=()=>{N.isOpen()?N.close():Q()},w.appendChild(C);function L(){let d=o.jobs.find(oe=>oe.status==="running");C.classList.toggle("running",!!d);let v=d?`${d.kind} ${d.label}`:"idle",R=C.querySelector("span:last-child");R&&(R.textContent=v),C.title=d?`Started ${new Date(d.started_at).toLocaleString()}`:"No jobs running"}let _=document.createElement("div");_.className="dtk-ui-nextsteps-box",n.appendChild(_);function T(){tn(_,o.nextSteps,{onLoad:d=>{D(d)},onTune:d=>{j(d)},onFollow:d=>ge(d),onDismiss:()=>{o.nextSteps=null,T()}})}async function D(d){if(!B){B=!0;try{let v=await Qe({select:d,steps:["load","detect"],from:null,to:null,full_refresh:!1,force:!1});ne("run",`run --select ${d}`,v.job_id,null),o.nextSteps&&o.nextSteps.metric===d&&(o.nextSteps={metric:d,jobId:v.job_id,phase:"running"},T())}catch(v){Z(n,"error",v.message)}finally{B=!1}}}function H(){let d=o.nextSteps;if(!d||!d.jobId||d.phase!=="running")return;let v=o.jobs.find(R=>R.id===d.jobId);!v||v.status==="running"||(o.nextSteps={...d,phase:v.status==="done"?"done":"failed"},T())}let F=document.createElement("div");F.className="dtk-ui-content",n.appendChild(F);function I(){var le,he;F.innerHTML="";let d=r.length;if(d===0){let A=document.createElement("div");A.className="dtk-ui-empty",A.textContent="No metrics found for this project/selector.",F.appendChild(A);return}let v=o.metrics.filter(A=>!A.pending),R=v.filter(A=>A.error!==null);if(v.length===d&&R.length===d){let A=document.createElement("div");A.className="dtk-ui-banner";let Me=(he=(le=R[0])==null?void 0:le.error)!=null?he:"unknown error";A.innerHTML=`<span>Failed to load overview: every metric failed (${O(Me)}).</span>`;let ye=document.createElement("button");ye.type="button",ye.className="dtk-ui-banner-retry",ye.textContent="Retry",ye.onclick=()=>{ue()},A.appendChild(ye),F.appendChild(A)}F.appendChild(Mt(o.metrics)),F.appendChild(Tt(v,o.tagFilter,A=>{o.tagFilter=A,I()}));let oe=o.tagFilter===null?o.metrics:o.metrics.filter(A=>o.tagFilter===Pe?A.tags.length===0:A.tags.includes(o.tagFilter)),ee=Pt(oe,o.sort,Date.now(),{onOpen:Y,onTune:A=>{j(A)},onRun:A=>U(A),onEdit:A=>{W(A)},onSortChange:A=>{o.sort=o.sort.key===A?{key:A,dir:o.sort.dir==="asc"?"desc":"asc"}:{key:A,dir:Xe[A]},I()}});F.appendChild(ee.el),ee.paint()}function Y(d){V()&&(a&&a.close(),s=d,a=Ot(n,d,o.windowPreset,{onTune:v=>{j(v)},onClose:()=>{a=null,s=null},onCleanPreview:v=>re(v),onCleanExecute:v=>ae(v)}))}function V(){return m?m.requestClose():!0}function K(){V()&&(a&&(a.close(),a=null),m=rt(n,{mode:"create",text:en,meta:i},{onSaved:(d,v)=>se(d,v),onDeleted:()=>{},onClose:()=>{m=null}}))}async function W(d){var R,oe;if(!V())return;let v;try{v=await vt(d)}catch(ee){Z(n,"error",ee.message);return}V()&&(a&&(a.close(),a=null),m=rt(n,{mode:"edit",name:v.name,file:v.file,text:v.text,digest:v.digest,data:(R=v.data)!=null?R:null,parseError:(oe=v.parse_error)!=null?oe:null,meta:i},{onSaved:(ee,le)=>se(ee,le),onDeleted:ee=>te(ee),onClose:()=>{m=null}}))}function se(d,v){Z(n,"info",`Metric '${d.name}' ${v==="create"?"created":"saved"}.`),d.note&&Z(n,"info",d.note),v==="create"&&(o.nextSteps={metric:d.name,jobId:null,phase:"idle"},T()),v==="edit"&&!d.renamed_from?de(d.name,d.metrics):J(d.metrics)}function te(d){Z(n,"info",`Metric '${d.name}' deleted (archived).`),d.note&&Z(n,"info",d.note),J(d.metrics)}function J(d){r=d,E.refreshOptions(),ue()}function de(d,v){r=v,E.refreshOptions();let R=v.find(le=>le.name===d),oe=o.metrics.findIndex(le=>le.name===d);if(!R||oe===-1){ue();return}let ee=ce;o.metrics[oe]=Re(R),I(),We(d,o.windowPreset).then(le=>{if(ee!==ce)return;le.pending=!1;let he=o.metrics.findIndex(A=>A.name===d);he!==-1&&(o.metrics[he]=le),I()}).catch(le=>{if(ee!==ce)return;let he=o.metrics.findIndex(A=>A.name===d);he!==-1&&(o.metrics[he]={...Re(R),pending:!1,error:le.message}),I()})}let E=Ht(n,{submitRun:d=>{$(d)},submitAutotune:d=>{G(d)},submitUnlock:d=>{ie(d)},getSelectOptions:k,isPipelineBusy:f}),N=jt(n,{onFollow:d=>ge(d),onStop:d=>{xe(d)}});function U(d){N.close(),E.refreshOptions(),E.refreshBusyState(),E.open(d)}function Q(){E.close(),N.render(o.jobs,Date.now(),o.followedJobId),N.open(),q()}function ne(d,v,R,oe){let ee={id:R,kind:d,label:v,status:"running",returncode:null,url:oe,started_at:Date.now(),finished_at:null};o.jobs=[ee,...o.jobs.filter(le=>le.id!==R)],ve(),q(),M()}let B=!1,fe=new Set;async function $(d){if(!B){B=!0;try{let v=await Qe(d);ne("run",`run --select ${d.select}`,v.job_id,null),ge(v.job_id)}catch(v){Z(n,"error",v.message)}finally{B=!1}}}async function G(d){if(!B){B=!0;try{let v=await pt(d);ne("autotune",`autotune --select ${d.select}`,v.job_id,null),ge(v.job_id)}catch(v){Z(n,"error",v.message)}finally{B=!1}}}async function ie(d){if(!B){B=!0;try{let v=await mt(d);ne("unlock",`unlock --select ${d.select}`,v.job_id,null),ge(v.job_id)}catch(v){Z(n,"error",v.message)}finally{B=!1}}}async function j(d){if(!fe.has(d)){fe.add(d),Z(n,"info",`Opening tuner for ${d}\u2026`);try{let v=await ft({metric:d});ne("tune",`tune --select ${d}`,v.job_id,v.url),window.open(v.url,"_blank")}catch(v){Z(n,"error",v.message)}finally{fe.delete(d)}}}async function re(d){let v=f();if(v.busy)return Z(n,"error",v.reason),null;try{let R=await bt(d);return R.stale_detectors.length===0&&R.stale_alert_states.length===0?(Z(n,"info",`Nothing stale for '${d}' \u2014 stored data matches the current config.`),null):R}catch(R){return Z(n,"error",R.message),null}}async function be(d,v=3e5){let R=Date.now()+v;for(;;){let oe;try{oe=await Ve(d,0)}catch{if(Date.now()>=R)throw new Error("lost track of the job \u2014 follow it in the jobs drawer");await new Promise(ee=>window.setTimeout(ee,1e3));continue}if(oe.status!=="running")return oe.status==="done";if(Date.now()>=R)throw new Error("the job is still running \u2014 follow it in the jobs drawer");await new Promise(ee=>window.setTimeout(ee,1e3))}}async function ae(d){if(B)return!1;B=!0;let v;try{v=(await gt({metric:d})).job_id,ne("clean",`clean --select ${d}`,v,null)}catch(R){return Z(n,"error",R.message),!1}finally{B=!1}try{let R=await be(v);return R?(Z(n,"info",`Stale data for '${d}' removed.`),a&&s===d&&a.reload(),de(d,r)):Z(n,"error",`clean --select ${d} failed \u2014 see the jobs drawer for the log.`),M(),R}catch(R){return Z(n,"error",R.message),!1}}async function xe(d){try{await ht(d),Z(n,"info","Stop requested."),M()}catch(v){Z(n,"error",v.message)}}function ge(d){o.followedJobId=d,o.followOffset=0,U(),E.resetLog(),pe(d)}function ve(){L(),N.render(o.jobs,Date.now(),o.followedJobId),E.refreshBusyState(),H()}async function M(){try{let d=await ut();o.jobs=d.jobs}catch{}ve()}function q(){if(l!==void 0)return;let d=()=>{M().then(()=>{l=N.isOpen()||o.jobs.some(R=>R.status==="running")?window.setTimeout(d,2e3):void 0})};l=window.setTimeout(d,2e3)}function X(){p!==void 0&&(window.clearTimeout(p),p=void 0)}function pe(d){X();let v=()=>{Ve(d,o.followOffset).then(R=>{if(o.followedJobId===d){if(E.appendLog(R.lines),o.followOffset=R.next_offset,R.status!=="running"){E.setLogStatus(R.status,R.returncode),p=void 0,M();return}p=window.setTimeout(v,1e3)}}).catch(R=>{Z(n,"error",`job ${d}: ${R.message}`),p=void 0})};p=window.setTimeout(v,0)}let ce=0;async function ue(){let d=++ce,v=o.windowPreset,R=r;if(o.metrics=R.map(Re),u.classList.add("spinning"),g(0,R.length),I(),R.length===0){u.classList.remove("spinning"),g(0,0);return}let oe=[...R],ee=0;async function le(){for(;;){if(d!==ce)return;let A=oe.shift();if(!A)return;let Me;try{Me=await We(A.name,v),Me.pending=!1}catch(Ue){Me={...Re(A),pending:!1,error:Ue.message}}if(d!==ce)return;let ye=o.metrics.findIndex(Ue=>Ue.name===A.name);ye!==-1&&(o.metrics[ye]=Me),ee++,g(ee,R.length),I()}}let he=Math.min(Kn,R.length);await Promise.all(Array.from({length:he},()=>le())),d===ce&&(u.classList.remove("spinning"),g(ee,R.length),E.refreshOptions())}I(),E.refreshOptions(),ue(),M()}window.__DTK_UI__={render:Vn};})();
|
|
538
|
+
- `)}`);return}}ie(!0);try{let q=j(),X=r?await yt({text:q,folder:(g==null?void 0:g.value.trim())||void 0}):await xt((M=t.name)!=null?M:"",{text:q,digest:t.digest});a=!1,n.onSaved(X,t.mode),ae()}catch(q){F(q.message)}finally{ie(!1)}}}async function be(M,q,X){if(!s){I(),s=!0,q.disabled=!0,X.disabled=!0,q.textContent="Deleting\u2026";try{let pe=await kt(M);a=!1,n.onDeleted(pe),ae()}catch(pe){F(pe.message),q.disabled=!1,X.disabled=!1,q.textContent="Delete metric"}finally{s=!1}}}function ae(){x.close(),n.onClose()}function ke(){return a&&!window.confirm("Discard unsaved changes?")?!1:(ae(),!0)}return Q(),p==="builder"&&D?D.focusFirst():T.focus(),R(),{close:ae,requestClose:ke}}function nn(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=x=>{x.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 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 Wn=3,Vn=[{value:"24h",label:"24h"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"},{value:"all",label:"All"}];function Qn(e,t){var _e;St(),t.classList.add(we),t.innerHTML="";let n=document.createElement("div");n.className=`${we}-root`,t.appendChild(n);let r=e.metrics,i=(_e=e.form_meta)!=null?_e:{channels:[],profiles:[],default_profile:null},o={windowPreset:e.initial_window||"30d",metrics:r.map(Ne),jobs:[],followedJobId:null,followOffset:0,tagFilter:null,sort:{key:"alerts",dir:Xe.alerts},nextSteps:null},a=null,s=null,m=null,l,p;function x(){let d=new Set,y=new Set;for(let N of r){d.add(N.name);for(let oe of N.tags)y.add(oe)}return[...d,...[...y].map(N=>`tag:${N}`)]}function f(){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 c=document.createElement("div");c.className="dtk-ui-header",n.appendChild(c);let v=document.createElement("div");v.className="dtk-ui-brand",v.innerHTML=`<span class="dtk-ui-brand-dot"></span><span class="dtk-ui-brand-name">detectkit \xB7 <b>${O(e.project)}</b></span>`,c.appendChild(v);let w=document.createElement("div");w.className="dtk-ui-header-right",c.appendChild(w);let S=document.createElement("div");S.className="dtk-ui-seg";for(let d of Vn){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,S.querySelectorAll(".dtk-ui-seg-btn").forEach(N=>N.classList.remove("on")),y.classList.add("on"),a&&a.setWindow(d.value),ue())},S.appendChild(y)}w.appendChild(S);let u=document.createElement("button");u.type="button",u.className="dtk-ui-iconbtn",u.title="Refresh overview",u.textContent="\u27F3",u.onclick=()=>{ue()},w.appendChild(u);let k=document.createElement("button");k.type="button",k.className="dtk-ui-runbtn",k.textContent="Run pipeline",k.onclick=()=>U(),w.appendChild(k);let b=document.createElement("button");b.type="button",b.className="dtk-ui-newbtn",b.textContent="New metric",b.onclick=()=>K(),w.appendChild(b);let h=document.createElement("span");h.className="dtk-ui-progresschip",h.style.display="none",w.appendChild(h);function g(d,y){if(y===0||d>=y){h.style.display="none";return}h.textContent=`${d}/${y}`,h.style.display=""}let C=document.createElement("button");C.type="button",C.className="dtk-ui-jobschip",C.innerHTML='<span class="dtk-ui-jobschip-dot"></span><span>idle</span>',C.onclick=()=>{R.isOpen()?R.close():Q()},w.appendChild(C);function L(){let d=o.jobs.find(oe=>oe.status==="running");C.classList.toggle("running",!!d);let y=d?`${d.kind} ${d.label}`:"idle",N=C.querySelector("span:last-child");N&&(N.textContent=y),C.title=d?`Started ${new Date(d.started_at).toLocaleString()}`:"No jobs running"}let _=document.createElement("div");_.className="dtk-ui-nextsteps-box",n.appendChild(_);function T(){nn(_,o.nextSteps,{onLoad:d=>{D(d)},onTune:d=>{j(d)},onFollow:d=>ge(d),onDismiss:()=>{o.nextSteps=null,T()}})}async function D(d){if(!B){B=!0;try{let y=await Qe({select:d,steps:["load","detect"],from:null,to:null,full_refresh:!1,force:!1});ne("run",`run --select ${d}`,y.job_id,null),o.nextSteps&&o.nextSteps.metric===d&&(o.nextSteps={metric:d,jobId:y.job_id,phase:"running"},T())}catch(y){Z(n,"error",y.message)}finally{B=!1}}}function H(){let d=o.nextSteps;if(!d||!d.jobId||d.phase!=="running")return;let y=o.jobs.find(N=>N.id===d.jobId);!y||y.status==="running"||(o.nextSteps={...d,phase:y.status==="done"?"done":"failed"},T())}let F=document.createElement("div");F.className="dtk-ui-content",n.appendChild(F);function I(){var le,he;F.innerHTML="";let d=r.length;if(d===0){let A=document.createElement("div");A.className="dtk-ui-empty",A.textContent="No metrics found for this project/selector.",F.appendChild(A);return}let y=o.metrics.filter(A=>!A.pending),N=y.filter(A=>A.error!==null);if(y.length===d&&N.length===d){let A=document.createElement("div");A.className="dtk-ui-banner";let Me=(he=(le=N[0])==null?void 0:le.error)!=null?he:"unknown error";A.innerHTML=`<span>Failed to load overview: every metric failed (${O(Me)}).</span>`;let ye=document.createElement("button");ye.type="button",ye.className="dtk-ui-banner-retry",ye.textContent="Retry",ye.onclick=()=>{ue()},A.appendChild(ye),F.appendChild(A)}F.appendChild(Mt(o.metrics)),F.appendChild(Tt(y,o.tagFilter,A=>{o.tagFilter=A,I()}));let oe=o.tagFilter===null?o.metrics:o.metrics.filter(A=>o.tagFilter===Pe?A.tags.length===0:A.tags.includes(o.tagFilter)),ee=Ot(oe,o.sort,Date.now(),{onOpen:Y,onTune:A=>{j(A)},onRun:A=>U(A),onEdit:A=>{W(A)},onSortChange:A=>{o.sort=o.sort.key===A?{key:A,dir:o.sort.dir==="asc"?"desc":"asc"}:{key:A,dir:Xe[A]},I()}});F.appendChild(ee.el),ee.paint()}function Y(d){V()&&(a&&a.close(),s=d,a=It(n,d,o.windowPreset,{onTune:y=>{j(y)},onClose:()=>{a=null,s=null},onCleanPreview:y=>re(y),onCleanExecute:y=>ae(y)}))}function V(){return m?m.requestClose():!0}function K(){V()&&(a&&(a.close(),a=null),m=rt(n,{mode:"create",text:tn,meta:i},{onSaved:(d,y)=>se(d,y),onDeleted:()=>{},onClose:()=>{m=null}}))}async function W(d){var N,oe;if(!V())return;let y;try{y=await vt(d)}catch(ee){Z(n,"error",ee.message);return}V()&&(a&&(a.close(),a=null),m=rt(n,{mode:"edit",name:y.name,file:y.file,text:y.text,digest:y.digest,data:(N=y.data)!=null?N:null,parseError:(oe=y.parse_error)!=null?oe:null,meta:i},{onSaved:(ee,le)=>se(ee,le),onDeleted:ee=>te(ee),onClose:()=>{m=null}}))}function se(d,y){Z(n,"info",`Metric '${d.name}' ${y==="create"?"created":"saved"}.`),d.note&&Z(n,"info",d.note),y==="create"&&(o.nextSteps={metric:d.name,jobId:null,phase:"idle"},T()),y==="edit"&&!d.renamed_from?de(d.name,d.metrics):J(d.metrics)}function te(d){Z(n,"info",`Metric '${d.name}' deleted (archived).`),d.note&&Z(n,"info",d.note),J(d.metrics)}function J(d){r=d,E.refreshOptions(),ue()}function de(d,y){r=y,E.refreshOptions();let N=y.find(le=>le.name===d),oe=o.metrics.findIndex(le=>le.name===d);if(!N||oe===-1){ue();return}let ee=ce;o.metrics[oe]=Ne(N),I(),We(d,o.windowPreset).then(le=>{if(ee!==ce)return;le.pending=!1;let he=o.metrics.findIndex(A=>A.name===d);he!==-1&&(o.metrics[he]=le),I()}).catch(le=>{if(ee!==ce)return;let he=o.metrics.findIndex(A=>A.name===d);he!==-1&&(o.metrics[he]={...Ne(N),pending:!1,error:le.message}),I()})}let E=jt(n,{submitRun:d=>{$(d)},submitAutotune:d=>{G(d)},submitUnlock:d=>{ie(d)},getSelectOptions:x,isPipelineBusy:f}),R=qt(n,{onFollow:d=>ge(d),onStop:d=>{ke(d)}});function U(d){R.close(),E.refreshOptions(),E.refreshBusyState(),E.open(d)}function Q(){E.close(),R.render(o.jobs,Date.now(),o.followedJobId),R.open(),q()}function ne(d,y,N,oe){let ee={id:N,kind:d,label:y,status:"running",returncode:null,url:oe,started_at:Date.now(),finished_at:null};o.jobs=[ee,...o.jobs.filter(le=>le.id!==N)],ve(),q(),M()}let B=!1,fe=new Set;async function $(d){if(!B){B=!0;try{let y=await Qe(d);ne("run",`run --select ${d.select}`,y.job_id,null),ge(y.job_id)}catch(y){Z(n,"error",y.message)}finally{B=!1}}}async function G(d){if(!B){B=!0;try{let y=await pt(d);ne("autotune",`autotune --select ${d.select}`,y.job_id,null),ge(y.job_id)}catch(y){Z(n,"error",y.message)}finally{B=!1}}}async function ie(d){if(!B){B=!0;try{let y=await mt(d);ne("unlock",`unlock --select ${d.select}`,y.job_id,null),ge(y.job_id)}catch(y){Z(n,"error",y.message)}finally{B=!1}}}async function j(d){if(!fe.has(d)){fe.add(d),Z(n,"info",`Opening tuner for ${d}\u2026`);try{let y=await ft({metric:d});ne("tune",`tune --select ${d}`,y.job_id,y.url),window.open(y.url,"_blank")}catch(y){Z(n,"error",y.message)}finally{fe.delete(d)}}}async function re(d){let y=f();if(y.busy)return Z(n,"error",y.reason),null;try{let N=await bt(d);return N.stale_detectors.length===0&&N.stale_alert_states.length===0?(Z(n,"info",`Nothing stale for '${d}' \u2014 stored data matches the current config.`),null):N}catch(N){return Z(n,"error",N.message),null}}async function be(d,y=3e5){let N=Date.now()+y;for(;;){let oe;try{oe=await Ve(d,0)}catch{if(Date.now()>=N)throw new Error("lost track of the job \u2014 follow it in the jobs drawer");await new Promise(ee=>window.setTimeout(ee,1e3));continue}if(oe.status!=="running")return oe.status==="done";if(Date.now()>=N)throw new Error("the job is still running \u2014 follow it in the jobs drawer");await new Promise(ee=>window.setTimeout(ee,1e3))}}async function ae(d){if(B)return!1;B=!0;let y;try{y=(await gt({metric:d})).job_id,ne("clean",`clean --select ${d}`,y,null)}catch(N){return Z(n,"error",N.message),!1}finally{B=!1}try{let N=await be(y);return N?(Z(n,"info",`Stale data for '${d}' removed.`),a&&s===d&&a.reload(),de(d,r)):Z(n,"error",`clean --select ${d} failed \u2014 see the jobs drawer for the log.`),M(),N}catch(N){return Z(n,"error",N.message),!1}}async function ke(d){try{await ht(d),Z(n,"info","Stop requested."),M()}catch(y){Z(n,"error",y.message)}}function ge(d){o.followedJobId=d,o.followOffset=0,U(),E.resetLog(),pe(d)}function ve(){L(),R.render(o.jobs,Date.now(),o.followedJobId),E.refreshBusyState(),H()}async function M(){try{let d=await ut();o.jobs=d.jobs}catch{}ve()}function q(){if(l!==void 0)return;let d=()=>{M().then(()=>{l=R.isOpen()||o.jobs.some(N=>N.status==="running")?window.setTimeout(d,2e3):void 0})};l=window.setTimeout(d,2e3)}function X(){p!==void 0&&(window.clearTimeout(p),p=void 0)}function pe(d){X();let y=()=>{Ve(d,o.followOffset).then(N=>{if(o.followedJobId===d){if(E.appendLog(N.lines),o.followOffset=N.next_offset,N.status!=="running"){E.setLogStatus(N.status,N.returncode),p=void 0,M();return}p=window.setTimeout(y,1e3)}}).catch(N=>{Z(n,"error",`job ${d}: ${N.message}`),p=void 0})};p=window.setTimeout(y,0)}let ce=0;async function ue(){let d=++ce,y=o.windowPreset,N=r;if(o.metrics=N.map(Ne),u.classList.add("spinning"),g(0,N.length),I(),N.length===0){u.classList.remove("spinning"),g(0,0);return}let oe=[...N],ee=0;async function le(){for(;;){if(d!==ce)return;let A=oe.shift();if(!A)return;let Me;try{Me=await We(A.name,y),Me.pending=!1}catch(Ue){Me={...Ne(A),pending:!1,error:Ue.message}}if(d!==ce)return;let ye=o.metrics.findIndex(Ue=>Ue.name===A.name);ye!==-1&&(o.metrics[ye]=Me),ee++,g(ee,N.length),I()}}let he=Math.min(Wn,N.length);await Promise.all(Array.from({length:he},()=>le())),d===ce&&(u.classList.remove("spinning"),g(ee,N.length),E.refreshOptions())}I(),E.refreshOptions(),ue(),M()}window.__DTK_UI__={render:Qn};})();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|