mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
6ca0eec1075053d4e97b35dfbf8ededcdcd1791a
830
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f112ac01a5 |
fix: dashboard layout improvements (#13815)
<h2 style="unicode-bidi: plaintext; color: rgb(204, 204, 204);
font-family: -apple-system, "system-ui", "Segoe UI",
Roboto, sans-serif; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; letter-spacing: normal; orphans: 2;
text-align: start; text-indent: 0px; text-transform: none; widows: 2;
word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color:
initial;">Dashboard layout & UX improvements</h2><p
style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em;
unicode-bidi: plaintext; color: rgb(204, 204, 204); font-family:
-apple-system, "system-ui", "Segoe UI", Roboto,
sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures:
normal; font-variant-caps: normal; font-weight: 400; letter-spacing:
normal; orphans: 2; text-align: start; text-indent: 0px; text-transform:
none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;">Polish
pass on the dashboard experience: settings layout, drag/resize grid
feedback, empty states, and per-tab panel counts.</p><h3
style="unicode-bidi: plaintext; color: rgb(204, 204, 204); font-family:
-apple-system, "system-ui", "Segoe UI", Roboto,
sans-serif; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; letter-spacing: normal; orphans: 2;
text-align: start; text-indent: 0px; text-transform: none; widows: 2;
word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;">✨
Highlights</h3><p style="white-space: pre-wrap; margin-top: 0.1em;
margin-bottom: 0.2em; unicode-bidi: plaintext; color: rgb(204, 204,
204); font-family: -apple-system, "system-ui", "Segoe
UI", Roboto, sans-serif; font-size: 13px; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal; font-weight:
400; letter-spacing: normal; orphans: 2; text-align: start; text-indent:
0px; text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(24, 24, 24);
text-decoration-thickness: initial; text-decoration-style: initial;
text-decoration-color: initial;"><strong>Grid feedback while
dragging/resizing panels</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/views/Dashboards/RenderDashboardCharts.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170,
252);">RenderDashboardCharts.vue</a>)</p><ul
style="padding-inline-start: 2em; color: rgb(204, 204, 204);
font-family: -apple-system, "system-ui", "Segoe UI",
Roboto, sans-serif; font-size: 13px; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal; font-weight:
400; letter-spacing: normal; orphans: 2; text-align: start; text-indent:
0px; text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; white-space: normal; background-color:
rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;"><li
style="unicode-bidi: plaintext;">Added a live alignment grid that
appears only during a drag or resize, drawn from GridStack's real cell
metrics (192 columns × row height).</li><li style="unicode-bidi:
plaintext;">The grid is<span> </span><strong>operation-aware</strong>:
lines snap to the top/left edges
while<span> </span><em>moving</em><span> </span>and the bottom/right
edges while<span> </span><em>resizing</em>, so the edge you're dragging
always lands on a line and every line is reachable (no skipped
positions).</li><li style="unicode-bidi: plaintext;">Panels are made
opaque during interaction (<code style="font-family: monospace; color:
rgb(208, 208, 208); background-color: rgb(60, 60, 60); padding: 2px 4px;
border-radius: 3px; word-break: break-word; font-size:
0.9em;">--color-surface-base</code>) so the grid only shows in the
gutters/empty cells, not through chart or table panels.</li></ul><p
style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em;
unicode-bidi: plaintext; color: rgb(204, 204, 204); font-family:
-apple-system, "system-ui", "Segoe UI", Roboto,
sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures:
normal; font-variant-caps: normal; font-weight: 400; letter-spacing:
normal; orphans: 2; text-align: start; text-indent: 0px; text-transform:
none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color:
initial;"><strong>Empty states</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/lib/core/EmptyState/presets.ts"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170, 252);">presets.ts</a>, <a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/components/dashboards/settings/VariableSettings.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170, 252);">VariableSettings.vue</a>, <a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/views/Dashboards/ScheduledDashboards.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170,
252);">ScheduledDashboards.vue</a>)</p><ul style="padding-inline-start:
2em; color: rgb(204, 204, 204); font-family: -apple-system,
"system-ui", "Segoe UI", Roboto, sans-serif;
font-size: 13px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: start; text-indent: 0px; text-transform: none;
widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
white-space: normal; background-color: rgb(24, 24, 24);
text-decoration-thickness: initial; text-decoration-style: initial;
text-decoration-color: initial;"><li style="unicode-bidi:
plaintext;">Replaced the generic<span> </span><code style="font-family:
monospace; color: rgb(208, 208, 208); background-color: rgb(60, 60, 60);
padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size:
0.9em;">NoData</code><span> </span>placeholder with<span> </span><code
style="font-family: monospace; color: rgb(208, 208, 208);
background-color: rgb(60, 60, 60); padding: 2px 4px; border-radius: 3px;
word-break: break-word; font-size:
0.9em;">OEmptyState</code><span> </span>for the Variables settings table
and the Scheduled Dashboards list.</li><li style="unicode-bidi:
plaintext;">Added a new<span> </span><code style="font-family:
monospace; color: rgb(208, 208, 208); background-color: rgb(60, 60, 60);
padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size:
0.9em;">no-variables</code><span> </span>preset (illustration + copy +
"Add variable" action); reused the existing<span> </span><code
style="font-family: monospace; color: rgb(208, 208, 208);
background-color: rgb(60, 60, 60); padding: 2px 4px; border-radius: 3px;
word-break: break-word; font-size:
0.9em;">no-reports</code><span> </span>preset for scheduled
dashboards.</li><li style="unicode-bidi: plaintext;">Fixed the Variables
table so a long
list<span> </span><strong>scrolls</strong><span> </span>instead of
clipping, and made the Scheduled Dashboards table fill the drawer height
so the empty state centers.</li></ul><p style="white-space: pre-wrap;
margin-top: 0.1em; margin-bottom: 0.2em; unicode-bidi: plaintext; color:
rgb(204, 204, 204); font-family: -apple-system, "system-ui",
"Segoe UI", Roboto, sans-serif; font-size: 13px; font-style:
normal; font-variant-ligatures: normal; font-variant-caps: normal;
font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start;
text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(24, 24, 24);
text-decoration-thickness: initial; text-decoration-style: initial;
text-decoration-color: initial;"><strong>Dashboard settings
layout</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/components/dashboards/settings/GeneralSettings.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170,
252);">GeneralSettings.vue</a>)</p><ul style="padding-inline-start: 2em;
color: rgb(204, 204, 204); font-family: -apple-system,
"system-ui", "Segoe UI", Roboto, sans-serif;
font-size: 13px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: start; text-indent: 0px; text-transform: none;
widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
white-space: normal; background-color: rgb(24, 24, 24);
text-decoration-thickness: initial; text-decoration-style: initial;
text-decoration-color: initial;"><li style="unicode-bidi:
plaintext;">Reworked the General settings layout.</li></ul><p
style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em;
unicode-bidi: plaintext; color: rgb(204, 204, 204); font-family:
-apple-system, "system-ui", "Segoe UI", Roboto,
sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures:
normal; font-variant-caps: normal; font-weight: 400; letter-spacing:
normal; orphans: 2; text-align: start; text-indent: 0px; text-transform:
none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color:
initial;"><strong>Tab panel-count badge</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/components/dashboards/tabs/TabList.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170, 252);">TabList.vue</a>)</p><ul
style="padding-inline-start: 2em; color: rgb(204, 204, 204);
font-family: -apple-system, "system-ui", "Segoe UI",
Roboto, sans-serif; font-size: 13px; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal; font-weight:
400; letter-spacing: normal; orphans: 2; text-align: start; text-indent:
0px; text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; white-space: normal; background-color:
rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;"><li
style="unicode-bidi: plaintext;">Each dashboard tab now shows a badge
with its panel count (section headers excluded), so tab density is
visible without opening each tab.</li></ul><p style="white-space:
pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; unicode-bidi:
plaintext; color: rgb(204, 204, 204); font-family: -apple-system,
"system-ui", "Segoe UI", Roboto, sans-serif;
font-size: 13px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: start; text-indent: 0px; text-transform: none;
widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color:
initial;"><strong>Variable dependency indicator</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/components/dashboards/settings/VariableSettings.vue"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170,
252);">VariableSettings.vue</a>)</p><ul style="padding-inline-start:
2em; color: rgb(204, 204, 204); font-family: -apple-system,
"system-ui", "Segoe UI", Roboto, sans-serif;
font-size: 13px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: start; text-indent: 0px; text-transform: none;
widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
white-space: normal; background-color: rgb(24, 24, 24);
text-decoration-thickness: initial; text-decoration-style: initial;
text-decoration-color: initial;"><li style="unicode-bidi:
plaintext;">Variables that depend on others show a "Depends on: …" chip
(tree icon + count) in the settings table.</li></ul><p
style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em;
unicode-bidi: plaintext; color: rgb(204, 204, 204); font-family:
-apple-system, "system-ui", "Segoe UI", Roboto,
sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures:
normal; font-variant-caps: normal; font-weight: 400; letter-spacing:
normal; orphans: 2; text-align: start; text-indent: 0px; text-transform:
none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;
background-color: rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color:
initial;"><strong>Panel header token</strong> (<a
href="vscode-webview://0vkpvjgb486eanj04qjfqcnqmnatevjacbbbqdp3ecrs4efo5krm/web/src/lib/styles/tokens/component.css"
target="_blank" rel="noopener noreferrer" style="color: rgb(77, 170,
252); text-decoration: rgb(77, 170, 252);">component.css</a>)</p><ul
style="padding-inline-start: 2em; color: rgb(204, 204, 204);
font-family: -apple-system, "system-ui", "Segoe UI",
Roboto, sans-serif; font-size: 13px; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal; font-weight:
400; letter-spacing: normal; orphans: 2; text-align: start; text-indent:
0px; text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; white-space: normal; background-color:
rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;"><li
style="unicode-bidi: plaintext;">Lightened<span> </span><code
style="font-family: monospace; color: rgb(208, 208, 208);
background-color: rgb(60, 60, 60); padding: 2px 4px; border-radius: 3px;
word-break: break-word; font-size:
0.9em;">--color-panel-bar-bg</code><span> </span>(grey-200 → grey-100)
for a softer chart-header band; the grey-300 divider still carries the
header/body edge.</li></ul><h3 style="unicode-bidi: plaintext; color:
rgb(204, 204, 204); font-family: -apple-system, "system-ui",
"Segoe UI", Roboto, sans-serif; font-style: normal;
font-variant-ligatures: normal; font-variant-caps: normal;
letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px;
text-transform: none; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; white-space: normal; background-color:
rgb(24, 24, 24); text-decoration-thickness: initial;
text-decoration-style: initial; text-decoration-color: initial;">
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
||
|
|
0dba67d638 |
feat: composite alerts (#13797)
Design at : alerts/composite_alerts/composite_alerts.md ## Summary - add composite alert graph persistence, evaluation, scheduling, lifecycle APIs, and deletion safeguards - add composite alert UI forms, preview, references, list/detail integration, and localization - add Rust, API, Vue, and Playwright contracts ## Verification - cargo fmt --all -- --check - cargo check -p openobserve-core - cargo check -p openobserve-api-management - npm run type-check:composite-alerts - npm run type-check:app - npm run lint:ci -- --quiet - design/token/style checks - targeted Rust/Vitest suites - browser QA against local alerts UI ## Follow-ups (intentionally deferred, documented in the spec) - `RunOutcome::Error`/`NotifyFailed` outcome records on composite delivery failure (§11.5) - Incident detail live-definition resolver for composites + "definition unavailable" retention (§9.6) - `alert_composite_*` observability metrics (§16) - SLO/stream delete-conflict 409 bodies with readable-vs-hidden parent split (§10.3) - Super-cluster startup preflight (§18) <img width="1650" height="979" alt="image" src="https://github.com/user-attachments/assets/3def5246-7bf7-48fe-9a42-c0ac08271ea9" /> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
bd28872ddc | test: improve stability of Alpha environment tests (#13817) | ||
|
|
d1f8941512 | test: stabilize test cases for the Alpha environment (#13551) | ||
|
|
496c0d5842 |
ci(tests): pure-API Playwright spec classifier + anti-drift guard (Phase 3) (#13794)
## What **Phase 3** of the Playwright→pytest API-test migration — the anti-drift guardrail. (Phase 1 = Correlation #13788 / o2-ent#2419; Phase 2 = Alerts #13791.) > 📚 **Stacked on #13791.** Base is the Phase 2 branch so the diff shows only these two files; GitHub auto-retargets this PR to `main` once #13791 merges. ## Changes - **`tests/ui-testing/scripts/classify-specs.js`** — codifies the migration classifier. Labels each `*.spec.js` as `UI_ONLY` / `UI+SETUP` / `PURE_API` / `REVIEW` from UI markers (`page.goto`, `.click`, `locator`, `getByRole`, `toBeVisible`, page-object imports, nav helpers…) vs API markers (`page.request`, `authedRequest`, `getAuthHeaders`, `/_json`, api-helper imports). Modes: - `--all` — regenerate the inventory (summary + PURE_API/REVIEW lists) - `--check <files>` — exit 1 if any file is pure-API (the guard) - `--json` - Conservative by design: a spec is `PURE_API` only when **not one** UI marker appears, so genuine UI tests are never nagged. - **`.github/workflows/pure-api-spec-guard.yml`** — runs `--check` on the **newly-added** `*.spec.js` files in a PR and **fails** if any is pure-API (backend/API assertions with no browser). Pushes new API tests into pytest (`tests/api-testing/`) from the start. Only added files are checked, so editing an existing UI spec never trips it. ## Why The migration removed 9 pure-API specs from the browser harness (Correlation ×5, Alerts ×4). Without a guard, new API tests get authored as Playwright specs again and the drift returns. This makes the rule enforceable in CI instead of relying on reviewer memory. ## Verification - Re-ran the classifier over all **257** specs → **`PURE_API: 0`** (both phases fully removed their targets; zero drift). Sole `REVIEW` = `cleanup.spec.js`, a teardown utility (not a test). - Self-tested the guard: ✅ flags a synthetic pure-API spec (exit 1 + actionable message), ✅ passes a UI spec (exit 0). - Resolved the 6 previously-uncertain "Category C" specs → all UI or teardown; **0 additional migrations**. |
||
|
|
673bedb468 |
test(alerts): migrate multi-alert API specs from Playwright to pytest (Phase 2) (#13791)
## What **Phase 2** of the Playwright→pytest API-test migration (Phase 1 = Correlation, #13788 / o2-enterprise#2419). Ports the 4 **pure-API** Alerts 4.0 (multi-alert) specs into pytest and deletes the Playwright versions — they launched a browser only to assert the raw API. ## Changes — `tests/api-testing/tests/alerts/` | File | Ported from | |---|---| | `multialert_helpers.py` | `utils/alerts-api-helpers.js` (v1/v2 endpoints, canonical payloads, seed fixtures, ingest, scheduler-outcome polling) | | `conftest.py` | `alerts` fixture — seeds template + destination + stream, auto-cleans created alerts | | `test_multialert_api.py` | `alerts-multialert-api.spec.js` — 8 tests (save-time guardrails, round-trip type contract, B1 group-endpoint RBAC guard, tag/priority facets) | | `test_multialert_regression.py` | `alerts-multialert-regression.spec.js` — 4 tests (zero-behaviour-change guards) | | `test_multialert_firing.py` | `alerts-multialert-firing.spec.js` — 4 tests (fires at critical/warning, per-group fan-out, simple rollup) | | `test_multialert_transitions.py` | `alerts-multialert-transitions.spec.js` — 1 test (Ok→Warning→Critical history) | **17 tests, 1:1 port.** Deletes the 4 API specs and trims them from `ci_matrix.json`'s Alerts `run_files`. Keeps `alerts-multialert-ui.spec.js` (UI) and `alerts-api-helpers.js` (still used by the UI + priority-tags specs). ## No workflow change needed Unlike the Correlation pilot (which needed a dedicated server env), the main `api_integration_tests` job **already** runs `tests/alerts/`, and its server env **already** sets `ZO_ALERT_SCHEDULE_INTERVAL: 3` — the exact scheduler cadence the firing/transitions tests need. So these tests are picked up automatically with no CI edits. ## Verified locally Full suite against a fresh single-node enterprise build: **17/17 passed** (~52s), including the timing-dependent firing (critical/warning/per-group/rollup) and level-transition history tests. |
||
|
|
c64a59865e |
test(correlation): remove 5 migrated API specs from Playwright (ported to pytest in ENT) (#13788)
## What
Removes the 5 **pure-API** Correlation Playwright specs now ported to
pytest. Part of the Playwright→pytest API-test migration (Phase 1
pilot).
Deleted (browser-launched only to make API assertions — no UI):
`correlation-{discovery,custom-groups,identity-sets,reset,edge-cases}.spec.js`
## The pytest port lives in the ENT repo
Correlation is **enterprise-only** (`service_streams` returns 403 on OSS
builds), so — like every other ENT-only api-testing suite
(cipher/dedup/rbac/…) — the pytest suite lives in **o2-enterprise** and
is merged into the OSS tree at CI time. Companion PR:
openobserve/o2-enterprise#2419 (adds
`tests/api-testing/tests/correlation/` + the `api_correlation_tests` job
+ matrix edit). Verified there: **14/14** green on the enterprise build.
## Kept in Playwright (not migrated)
The 4 UI Correlation specs — `settings`, `alert-grouping`, `cache`,
`drawer` (13–92 browser markers each) — render and assert on UI, so they
stay. `correlation-api-helpers.js` stays too (the UI specs still import
it for seeding).
|
||
|
|
2834186b8a |
test(e2e/alpha1): unique per-run alert destination/template so Add Alert button enables (#13783)
## Why After #13776 merged, the alpha1 **RegressionSet** shard still failed — but on a **new, different** cause than #13776 fixed. All 4 `alerts-regression` tests died at the very first step (`clickAddAlertButton`) because the button was **disabled**: ``` <button disabled aria-disabled="true" title="No destinations available" data-test="alert-list-add-alert-btn"> 19 × locator resolved to disabled → toBeEnabled() timed out after 15s ``` ## Root cause (reproduced live on the RegressionSet org, auto_org_2) [`AlertList.vue`](web/src/components/alerts/AlertList.vue#L51) disables the Add Alert button while `destinations.length === 0`: ```vue :disabled="!destinations.length || !templates.length" :title="!destinations.length ? t('alerts.noDestinations') : ''" ``` On the **shared** cloud org the **fixed** names `e2e_promql_dest` / `e2e_promql_template` were stuck ghost records — a concurrent run's cleanup couldn't fully delete them (UI delete timed out / `destinations_templates_fk` 500). So the beforeAll create returned `400 "already exists"`, yet the destinations list loaded **empty**, keeping the button disabled through the 15s `toBeEnabled` wait. Not a product regression — the org simply had no *loadable* destination. This is the same **shared-org fixed-name collision** class fixed for streams in #13776. ## Fix - `e2e_promql_dest` / `e2e_promql_template` → `..._<RUN_TOKEN>` (unique per run), so the beforeAll always creates a real, loadable destination. Keeps the `e2e_promql_` prefix so `cleanup.spec.js` still reclaims them. - Gate the beforeAll on the destination actually appearing in the `/alerts/destinations` list API before tests run, so the button is reliably enabled (`destinations.length > 0`) instead of racing the fetch. ## Verification (alpha, RegressionSet org auto_org_2 — reproduced 100% before) - Before: `Add Alert` disabled → `toBeEnabled` 15s timeout → 4/4 fail. - After: `Destination confirmed in list API | e2e_promql_dest_<token>` → button enabled → **alerts-regression 5/5 pass** (#9967, #10899, #10872, #10110, #10472); alerts saved for both `>=` and `<=`. ## Scope OSS-only test file. Picked up by the ENT alpha1 workflow the same way as #13776 (checks out opensource `main`, or dispatch with `o2_opensource_repo=test/alerts-regression-destinations-gate`). |
||
|
|
fa3d294999 |
test(reports): e2e regression coverage for dashboard scheduled reports drawer (#13569) (#13781)
## What Adds E2E regression coverage for the dashboard **Scheduled Reports drawer**, verifying the two bugs fixed in #13569. No production code is touched — this is test-only. ## Why #13569 (`fix: dashboard reports drawer duplicates entries and hides reports in custom folders`) shipped with unit-test updates only. The drawer had no E2E coverage at all, so both regressions could return unnoticed. | Bug | Root cause | Fix under test | |-----|-----------|----------------| | **1. Rows duplicate on reopen** | `scheduledReports` was seeded with the `reports` prop and `formatReports()` pushed onto it, mutating the prop. The drawer stays mounted between opens, so each reopen multiplied the rows. | `ScheduledDashboards.vue` now rebuilds the array with `.map()` | | **2. Custom-folder reports hidden** | `reports.list(org, folderId, dashboardId)` passed the **dashboard's** folder, but `folder_id` filters by the **report's own** folder | `ViewDashboard.vue` passes `""` so `folder_id` is omitted | ## Tests added — 9, all passing `tests/ui-testing/playwright-tests/Reports/scheduledReportsDrawer.spec.js` | # | Test | Covers | |---|------|--------| | 1 | P0: Drawer opens and lists the dashboard's cached report | baseline | | 2 | P0: Bug 13569-1 — reopening the drawer does not duplicate rows | **bug 1** — exact row count across 3 close/reopen cycles | | 3 | P0: Bug 13569-2 — report saved in a custom report folder is listed | **bug 2** — report in custom folder, dashboard in default folder | | 4 | P1: Reports list request omits `folder_id` | **bug 2** — pins the network contract the fix changed | | 5 | P1: Switching tabs re-filters the list without duplicating rows | `filterReports()`, the second path bug 1 corrupted | | 6 | P1: Search filter does not survive a reopen or leave stale rows | filter + rebuild interaction | | 7 | P2: Dashboard with no reports shows the empty state on every open | empty state across reopen | | 8 | P2: A report bound to another dashboard is not listed | guards against over-correcting bug 2 (`dashboard_id` scoping must survive) | | 9 | Cleanup: Remove all test resources via API | teardown | |
||
|
|
a28dcda276 |
test(correlation): standardize e2e suite onto framework harness (phase 0 — reference pattern) (#13775)
## What & why
Begins consolidating the **correlation (service-streams) e2e suite**
onto the standard `tests/ui-testing` framework. Today those specs live
in a self-contained parallel harness (own configs, own auth, own `O2_*`
env vars, per-test orgs with no teardown, non-standard names) and are
**not registered in any CI matrix** — so they never run automatically.
This is **Phase 0**: land the shared standard-shaped API helper and
convert the first spec as the **reference pattern** for review, before
batch-converting the rest.
## Changes
- **`utils/correlation-api-helpers.js`** (new) — single source of truth
for correlation API plumbing. Auth via `authedRequest`/`getAuthHeaders`
(framework session + 401/403 self-heal), per-test **fresh-org create +
teardown**. No `test`/`expect`.
- **`Correlation/correlation-discovery.spec.js`** (new) — converted from
`journeyA`: `enhanced-baseFixtures`, `@correlation`/`@P0` tags,
Copyright + JSDoc header, `testLogger.testStart`, standard `ZO_*` env
and naming. Assertions ported **1:1** (DISC-01/02/03).
- Remove `Correlation/journeyA-discovery.api.spec.js` (superseded).
## Deliberate deviation (documented)
Correlation discovery / identity config / `_reset` are **org-global and
destructive**, so each test provisions a **fresh org** and tears it down
in `afterEach`. This keeps the isolation the feature genuinely needs
while fixing the real defect in the old suite: **orgs were created but
never deleted** (leak).
## Validation
- `node --check` clean; requires resolve.
- Collects cleanly under `playwright.config.js` (`--list` → 3 tests,
tagged).
- ⚠️ **Green run pending an enterprise env** (service_streams 403s on
OSS). Not wired into CI yet, so `main` stays green. **Draft** until
validated.
## Follow-ups (later phases)
Batch-convert remaining 4 API + 3 UI specs · revive
`correlationSettings.spec.js` against the new UI · register a dedicated
**Correlation** shard in the ENT `ci_matrix.ent.json` · delete
`corr-*.config.js`.
|
||
|
|
6650950a50 |
test(e2e/alpha1): fix share-link redirect origin and cloud metrics ingest auth (#13776)
## Why The scheduled **Alpha1 (Cloud)** e2e run failed on three jobs ([o2-enterprise run 31547517666](https://github.com/openobserve/o2-enterprise/actions/runs/31547517666)): **Logs-Features** (7), **Functions** (11), **RegressionSet** (4). Root-caused each against a freshly-deployed alpha; two are genuine test heals, one was pure environment skew. ## Root causes & fixes ### 1. Logs-Features — shareLink + monaco-query-prefill (7 tests) ✅ fixed On cloud the app builds the share link from its **public** base URL (`*.external.zinclabs.dev`), while the tests authenticate against the ingress host (`*.internal.zinclabs.dev`). `page.goto(sharedUrl)` navigated **cross-origin**, dropped the auth cookies, and bounced to Dex — so every post-redirect state assertion read back `null`. **Fix:** re-point the short URL's origin to `ZO_BASE_URL` in `clickShareLinkAndGetUrl()` (right next to the existing HTTP→HTTPS "maintain auth context" step). `/short/<id>` resolves identically on the backend regardless of ingress host, so only the origin changes and the session stays valid. Same-origin envs (localhost / matching deployed host) are untouched. ### 2. RegressionSet — alerts Bug #9967 PromQL (1 test) ✅ fixed `ingestMetricsData()` authenticated with `ZO_ROOT_USER_EMAIL:PASSWORD`, but **cloud ingestion needs `email:passcode`**. The ingest silently 401'd → the `e2e_test_cpu_usage` metrics stream was never created → the PromQL alert flow timed out selecting it. **Fix:** build auth via `getAuthHeaders()` (passcode on cloud, root creds on self-hosted), refresh the passcode from the live browser session first, and poll until the stream is indexed so the wizard's stream-select doesn't race WAL lag. ### 3. Functions — radio → segmented toggle (11 tests) — no change needed The page object was already migrated to the segmented toggle in #13766; these failures were the **alpha frontend lagging the merged test code**. Green after the redeploy with zero code change. ## Verification (against alpha, `auto_org_1`) - `shareLink.spec.js` + `monaco-query-prefill.spec.js` → **11/11 passed** - `alerts-regression.spec.js` (full) → **5/5 passed** (#9967, #10110, #10899, #10872, #10472) - `Functions/js-transform-type.spec.js` → **7/7**, `row-expansion.spec.js` → green ## Scope OSS-only (test files). The ENT `playwright_alpha1.yml` checks out opensource at `main`, so merging makes the next scheduled run pick this up. It can also be pre-verified by dispatching that workflow with `o2_opensource_repo=test/alpha1-e2e-heals-0812`. |
||
|
|
fb50aaea7f |
fix(deps): resolve 39 Dependabot alerts (#13774)
## Summary - update vulnerable web transitive dependencies (`axios`, `brace-expansion`, `fast-uri`, `http-proxy-middleware`, `js-yaml`, `uuid`, and `websocket-driver`) - remove the unused `node-polyfill-webpack-plugin`, eliminating the unpatched `elliptic` dependency chain - update Playwright to 1.55.1 and `node-forge` to 1.4.0 in the UI test lockfile - adapt `BaseImport` to Axios 1.18's stricter response-header type This is expected to resolve 39 of the 41 currently open Dependabot alerts. ## Remaining alerts - `rmcp` remains on the project's custom `rmcp-openapi` fork. Updating it safely requires a coordinated change to the enterprise `Cargo.toml.openobserve`, which currently replaces the OSS manifest during enterprise builds and pins the old API. The compatible intermediate upstream releases also lack the fork's required `allOf`/`anyOf` support. - `thrift` 0.17.0 remains through `parquet` 58.4.0. The patched Thrift line (0.23+) is outside Parquet 58's version constraint. Parquet 59 removes the Thrift dependency, but adopting it requires a coordinated Arrow/DataFusion 59 upgrade. ## Validation - `npm ci` and `npm audit --package-lock-only` in `web/` (0 vulnerabilities) - `npm ci` and `npm audit --package-lock-only` in `tests/ui-testing/` (0 vulnerabilities) - `npm run type-check:app` - `npm run lint:ci -- --quiet` - `npm run lint:design:strict` - `NODE_OPTIONS=--max-old-space-size=8192 npm run build` - `npm run test:unit -- --run` (41,917 passed, 404 skipped) - `npx vitest run src/components/common/BaseImport.spec.ts --environment jsdom` (41 passed) - Playwright test discovery under 1.55.1 (2,076 tests in 265 files) - `cargo fmt --all -- --check` - `cargo test -p openobserve-mcp` (94 passed, 1 ignored) - `cargo audit` (0 vulnerabilities; 2 allowed unmaintained warnings) |
||
|
|
c451db0835 |
fix: tighten workflow permissions and CSS selector escaping (#13772)
## Summary - set explicit least-privilege permissions for audit, JavaScript license, and release workflows while preserving release-job write access - grant the spam-cleaner workflow the issue and pull-request scopes required to delete comments - escape quotes and backslashes before interpolating log toast text into CSS attribute selectors ## Validation - parsed the four modified workflow files as YAML - ran Node syntax checking on tests/ui-testing/pages/logsPages/logsPage.js - ran git diff whitespace validation |
||
|
|
360b989272 |
feat(slos): PromQL support for count and time-sliced SLOs, plus SLO/alert regression fixes (#13761)
Supersedes #13738, whose commit is included here as the first of four. Adds PromQL support to count and time-sliced SLOs, lets metrics streams choose SQL or PromQL, and fixes three shipped bugs found along the way. ## Shipped bug: every SQL time-slice SLO recorded wrong history `fetch_rows`' `SliQueryPlan::Single` arm normalized every hit with `with_good_column: true`, but that arm serves **two** shapes and only one projects `zo_slo_good`: | shape | projects | result | |---|---|---| | count single-query | `zo_slo_good` + `zo_slo_value` | correct | | time slice | `zo_slo_value` only | `good` defaulted to `0.0` | So every SQL time-slice slice was classified from `0.0` instead of its aggregate. With a positive threshold, `<`/`<=` (e.g. `p95 < 300ms`) recorded every slice **good** — the SLO read ~100%, the budget never burned, and no alert on it could fire. `>`/`>=` recorded every slice **bad** and fired continuously. Shipped in v0.92.0 (`4772df1723`); `to_row` had no time-slice test, which is how it got through. Fixed by deriving the flag from the SLI type in a new `single_query_rows`. Deliberately **not** fixed inside `to_row` by falling back to `total` — that would read a count bucket whose `SUM` came back NULL as *fully good*, inventing uptime. A test forbids it. **Stored history is not rewritten.** It ages out within one window; an operator can force a rebuild sooner by making a real edit (a no-op re-save does nothing — `update` bumps only on `definition_changed`). No auto-migration: bumping every time-slice SLO at boot would freeze every attached alert org-wide until backfill cleared the coverage floor, and double each org's row budget for 97 days — a self-inflicted monitoring gap to repair a reporting error. ## PromQL support **Time slice** carried a `query_language` field the planner ignored, so a PromQL time-slice SLO saved cleanly and measured nothing, forever. - `SliQueryPlan::PromQlValue` — one expression, not a good/total pair, planned at slice ends from the same helper the count arm uses. - The expression is passed through **verbatim**. Grouping comes from series labels; wrapping it in `sum by (...)` the way the SQL arm injects GROUP BY would destroy the aggregate (the sum of four pods' p95 is not a p95). - `promql_value_rows` **rejects** two series colliding on one `(slice_start, group_key)` via `RejectReason::AmbiguousSeries` instead of summing. Summing is right for counters (what `promql_rows` does) and meaningless here. Detection is unconditional, so the ungrouped case — an unaggregated `histogram_quantile` returning one series per instance — is covered. Rejects are plumbed through `fetch_rows` into `PassResult.rejected` on both the live and backfill paths. **Count** already had a working `CountSource::PromQl` backend that no UI could reach. ## Metrics streams choose SQL or PromQL `language_suits_stream` refused SQL whenever `stream_type == "metrics"`, and the form derived the language from the stream type — so metrics had no SQL option. A metrics stream is an ordinary stream with a `value` column, and `SELECT histogram(_timestamp, '5 minute'), avg(value) FROM cpu_usage` is a perfectly good SLI. SQL is now valid for any stream type; PromQL stays metrics-only. The form asks via a toggle (defaulting to PromQL) instead of deriving. ## Validation - `scope` refused for PromQL — a SQL `WHERE` fragment with nowhere to go in a PromQL plan. - Empty `query` refused for **both** languages (the SQL aggregate was previously never validated — same silent-freeze shape). - Expressions parsed with `promql-parser` at save, in `core` (`config` has no parser). - **Parse-only by design.** A grouping check requiring the root to be an aggregation whose `by(...)` matches `group_by` wrongly rejects `histogram_quantile(0.95, sum by (le, region)(...))` (function-call root; `le` is a necessary label superset) and binary-op roots like `sum by (region)(increase(a[5m])) - sum by (region)(increase(b[5m]))`. A "warn instead" variant needs a warnings channel the save API doesn't have. ## Also fixed - **Time-slice comparator 422.** `SliConfig::TimeSlice.comparator` has no serde default, so a dropdown the user never opened was omitted and the save died with a bare 422 — blocking creation of *any* time-slice SLO from the UI. Seeded to `<` only when blank, so a stored comparator survives an edit. - **SLO/alert/service-stream regressions** (the commit from #13738): fractional-threshold serde round-trip, `SloAlertCondition` UI, alerts table, service streams. ## Verification - 487 config · 206 core · 45 infra · 418 frontend — all passing; clippy `-D warnings`, `cargo fmt`, prettier, eslint, `vue-tsc` all clean. - Driven through a real browser against a running server (isolated instance, own data dir). All four SLI/language combinations create and store correctly: count·PromQL, count·**SQL over metrics**, time-slice·PromQL, time-slice·**SQL over metrics**. Also verified: the toggle swaps field shapes both ways, scope shows for SQL and hides for PromQL, PromQL-only hints appear only in PromQL mode, and editing a stored SQL-over-metrics SLO reopens as SQL with its predicate intact. - Validation rejections confirmed live with actionable messages: PromQL-with-scope, unparseable PromQL, and an empty SQL aggregate. Known limitation, pre-existing: `threshold` likewise has no serde default and is not seeded, so leaving it blank still 422s. That is genuine user error rather than an untouched-control trap; adding form validation was out of scope. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
b07b3d4229 |
feat(functions): replace language radios with a segmented toggle (#13766)
The Add Function header selected VRL vs JavaScript with a radio group and a single info icon. That icon only ever described the ALREADY-SELECTED language, so learning what the other one was for meant switching to it first. - Radio group -> OFormToggleGroup segmented control with a sliding indicator, each option carrying a language mark (V / JS). The badge variants match the transType column in FunctionList so VRL/JS read the same everywhere. - Give EACH option its own info icon and static tooltip, so both languages are readable without selecting either. Forced-language hosts (workflow function nodes are JS-only) hide the toggle, so the locked language's tip moves to a standalone icon. - Add a pipe divider between the two options, and one between the function-name title and the toggle. data-test renames `...-vrl-radio` -> `...-vrl-option` (same for js): "radio" described the old implementation. E2E page objects would have broken on this change regardless of naming -- toggle items expose data-state="on|off", not the radio group's "checked|unchecked". Verified: FunctionsToolbar.spec.ts 18/18 pass, vue-tsc clean. ESLint could not be run locally (@intlify/eslint-plugin-vue-i18n missing from node_modules). |
||
|
|
4531ae74d8 |
test(dashboards): e2e coverage for favorites cross-folder search fix (#13437) (#13758)
## Summary Adds E2E coverage for #13437 (`fix: dashboard all folder search for favorites`). That PR changed three things in `Dashboards.vue`; this adds one test per change. ## Test cases added | # | Test case | Covers | Priority | |---|-----------|--------|----------| | 1 | `should surface a non-favorited dashboard in the Favorites folder when searching across folders` | Favorites view yields to an active cross-folder search instead of short-circuiting to the stored favorites list | P0 | | 2 | `should restore the favorites-only list after clearing a cross-folder search` | Clearing resets both scope models (`searchQuery` + `filterQuery`), so the favorites-only list comes back | P1 | | 3 | `should expose a clear button for a current-folder search and restore the full list` | Search field is unconditionally `clearable` — the clear (X) button now renders in "This folder" scope too | P1 | ## What each test proves **1.** Seeds two dashboards in one folder, favorites only the first. Asserts the un-favorited one is **absent** from the Favorites view, then switches the scope toggle to "All folders", searches it by name, and asserts it appears. Before the fix the rows computed returned `favorites.value.map(...)` whenever the `__favorites__` pseudo-folder was active, so a cross-folder hit could never render. **2.** Runs that same cross-folder search, then clicks clear and asserts the field is empty, the searched-for dashboard drops out, and the favorite is listed again. **3.** Searches in the default "This folder" scope, asserts the filter is active (second dashboard filtered out), that `[data-test="dashboard-search-clear"]` is visible, and that clicking it empties the field and restores both rows. Previously `:clearable="searchAcrossFolders"` meant no clear button existed in this mode at all. ## Files changed - `tests/ui-testing/playwright-tests/dashboards/dashboard-favorites.spec.js` — 3 new tests (file now has 9) - `tests/ui-testing/pages/dashboardPages/dashboard-favorites.js` — 3 locators (`searchScopeAllFolders`, `searchScopeCurrentFolder`, `searchClearBtn`) + 5 methods (`searchAcrossFolders`, `clearSearch`, `verifySearchClearButtonVisible`, `verifySearchInputEmpty`) ## Test design Each test seeds a second, deliberately un-favorited dashboard (`DashB_<ts>`), named so neither dashboard's name is a substring of the other — that second row is the only thing that can prove the search reached past the favorites list. Every test asserts its own baseline *before* the action, so a pass is attributable to the change under test rather than to a permissive list. All selectors read from source; no new `waitForTimeout` sleeps; cleanup covered by the existing `afterEach`. ## Test results `9 passed` locally against `localhost:5080`. New tests verified green on repeated isolated runs. ## Caveats - Tests were **not** verified to fail against pre-fix code — the app is served from a prebuilt bundle (no dev server), so reverting the hunks would require a full frontend rebuild. The in-test baseline assertions mitigate this but don't replace it. - This spec file is **self-hosted-only**: `login()` in `dashLogin.js` waits for the `login-user-id-field` form, while alpha cloud uses Dex SSO. Confirmed pre-existing (an untouched test in this file fails at the identical line), but it means these tests won't run in a cloud-targeted CI job. |
||
|
|
56bedcb126 |
test(logs): fix flaky pattern-card click under OVirtualScroll windowing (#13752)
## Summary Fixes the flaky failure seen in ENT PR #2386's `e2e / Logs-Features` shard: ``` Logs/searchPatterns.spec.js:293 › should open pattern details dialog when clicking pattern card TimeoutError: locator.click: Timeout 45000ms exceeded. - waiting for locator('[data-test="pattern-card-0"]') ``` Failed all 4 attempts, took the rest of the shard down (`1 failed, 10 did not run, 57 passed`). **Unrelated to #2386's LLM-annotation changes** — it's pre-existing test-infra. ## Root cause `PatternList` renders cards inside `OVirtualScroll`, which stamps the **absolute** item index onto each card (`pattern-card-<absoluteIndex>`) and mounts **only the visible window**. The card getters were already migrated to address cards by *rendered position* (`patternCardAt()` / `patternCardPart()` — suffix + `.nth()`), but three code paths were left on the absolute-index selector: - `clickPatternDetailsIcon()` → clicked `[data-test="pattern-card-${index}"]` - `clickPatternIncludeBtn()` / `clickPatternExcludeBtn()` - the `waitForPatternsToLoad()` `'patterns'` visibility check When the mounted window starts above index 0, `getPatternCardCount()` (suffix `.count()`) still reports cards present, but the absolute `pattern-card-0` root is absent → the click waits the full 45s. Locally the whole list fits (no windowing), so `pattern-card-0` is always mounted and the bug hides — which is why it only surfaces in CI's headless viewport. ## Fix Migrate the card-root click helpers and the load-check to `patternCardAt(index)` (rendered position), consistent with `getPatternCardCount()` and the getters. Remove the now-unused absolute-index `patternCard` / `patternCardDetailsIcon` locators (the latter also misleadingly named — it resolved to the card root, not an icon). ## Validation Ran the full spec locally headless against a local **enterprise** build (v0.92.0-rc3): ``` playwright-tests/Logs/searchPatterns.spec.js — 15 passed (1.3m) ``` including the previously-failing `should open pattern details dialog when clicking pattern card`, with no regression to the other 14. Also verified via DOM probe that rendered cards are addressed correctly by rendered position while the absolute `pattern-card-0` root is the fragile anchor under windowing. ## Scope Test-only (`tests/ui-testing/pages/logsPages/logsPage.js`). No product code touched. |
||
|
|
053b1b8c09 |
test(metrics): E2E for explorer share URL and Visualize deep-link (#13747)
Adds E2E coverage for PR #13274 (metric page share URL), which shipped with unit tests but no Playwright coverage — the existing metrics-share-deep-link suite targets the legacy `/metrics/editor` route, not the Explorer. 15 tests covering: - F1 — share button presence, `metrics_data` blob written on chart build, stripped on leaving Visualize, absent on a blank canvas, volatile keys excluded, card drill-in, short-URL clipboard copy, full share round-trip - F2 — `?mode=visualize` stays on the Explorer; legacy no-mode `metrics_data` still redirects to the editor; corrupt and version-mismatched blobs absorbed New `MetricsExplorerPage` page object; registered in PageManager and the `Metrics` CI shard. Verified 15/15 on two consecutive runs against v0.92.0-rc3 (~36s). |
||
|
|
3886dff356 |
refactor(sentinel): dedup page-object methods + testLogger convention (follow-up to #13735) (#13746)
## Summary Post-POM-sweep cleanup (follow-up to #13727 / #13735): removes duplication and dead code introduced/surfaced during the sweep, and closes the `testLogger` convention gap. No production code — page objects + specs only. Net **−101 lines**. ## A) Duplicate method names — removed 22 shadowed dead methods 7 page objects each had **two class methods with the same name**. In JS the later definition wins, so the earlier copy was **unreachable dead code** (callers always ran the later one; tests pass with it). Removed the earlier/shadowed copy of each — behavior-preserving. `alertsPage` (5), `logsPage` (11), `pipelinesPage` (2), `metricsPage` (1), `streamsPage` (1), `cipherKeysFormValidationPage` (1), `correlationSettingsPage` (1). ## B) Duplicate implementations — consolidated - **crossLinkPage**: removed `crossLinkItemEditBtnLocatorByIdx` / `crossLinkItemDeleteBtnLocatorByIdx` — **0 callers anywhere** (incl. commented code); dead duplicates of the live `getCrossLinkEditBtnLocator` / `getCrossLinkDeleteBtnLocator`. - **alertsPage**: unified 3 identical-body pairs **via delegation** to a single impl — `getTemplateRowByText→getAlertRowByText`, `getDestinationsSelect→getAlertDestinationsSelectLocator`, `getAddAlertSubmitButton→getAlertSubmitButtonLocator`. Both names kept (zero spec edits), duplicated logic removed. ## C) Broad dead-code sweep — intentionally NOT in this PR The wider "defined-but-never-called" backlog (~890 candidates, mostly pre-existing) is a **risky, separate pass** and was deliberately excluded. ## D) testLogger — added to 22 specs missing it Added a `testLogger` import + `testLogger.testStart(testInfo.title, testInfo.file)` in `beforeEach` (or `testLogger.info` in the first test where there's no async `beforeEach`) to the 22 specs that didn't use it: 8 Correlation (5 api + 3 ui), 13 Dashboards, and `Login/auth`. Convention-only. ## Verification - **0 duplicate-name methods** remain across all page objects (was 22). - **Method-resolution scan** (every `pm.<obj>.<method>()` in all 264 specs must resolve): 4 unresolved, **all 4 pre-existing on `main`**, **0 introduced by this PR**. (This is the runtime-existence check that `node --check` can't do — the gap that caused the crossLinkPage regression on #13735.) - All changed `.js` pass `node --check`; all 22 specs have real (non-comment) `testLogger` usage. - CI-gated for browser execution. ## Stats 30 files changed (+82 / −183). |
||
|
|
cb78ef36fd |
test(sentinel): complete POM compliance — Dashboards + Correlation (follow-up to #13727) (#13735)
## Summary Completes the Sentinel **Page Object Model** compliance sweep of the Playwright suite (follow-up to #13727, which covered the non-Dashboards shards). Every raw `page.locator(...)` / `page.getBy*(...)` selector — in **actions and assertions** — is relocated out of the spec files into the relevant page object; specs now call page-object methods/getters only. **Result: 0 raw fixture-`page` selectors across the entire `playwright-tests` suite** (single-line *and* multi-line, verified with a dotall/multiline scanner). Together with #13727, the whole suite is POM-clean. ## What's in this PR **Dashboards shards — ~1,460 selectors** relocated into their page objects (`dashboard-panel-configs/actions/edit/time`, `dashboard-chart`, `dashboard-variables-scoped`, `dashboard-filter`, `dashboard-drilldown`, `crossLinkPage`, `visualise`, `dashboard-share-export`, `dashboard-create`, `dashboard-settings`, `dashboard-variables`): | Shard | selectors | |-------|----------:| | Dashboard-Config-Settings (11 specs) | ~255 | | Dashboards-Variables (12 specs, 4 batches) | ~693 | | Dashboards-Tables (7 specs) | ~127 | | Dashboards-Charts (9 specs) | ~81 | | Dashboards-Core + Visualize (10 specs) | ~144 | | Dashboards-Settings + Panel-DateTime (8 specs) | ~107 | | Dashboard-Regression (1 spec) | ~52 | **Correlation UI specs** (3 new `Correlation/*.ui.spec.js` that arrived via main's merge, after the original audit) — converted into a new `correlationDrawerPage` + an extended `correlationSettingsPage`, with `PageManager` wired into specs that previously used none. **Audit stragglers** the original **single-line** audit grep undercounted — multi-line `page\n.locator(...)` chains in `logstable.spec.js` (→ `logsPage.getTableHeaderByField()`) and `dashboard-streaming.spec.js` (2 add-panel selectors). **AI-review fixes** (DeepSeek, on this PR) — removed 2 dead-code duplicate getters + 1 redundant method alias (merge artifacts from the sequential batch commits). One Node-context `console.log` (`dashboard-general-setting`'s `beforeEach`) → `testLogger.info`. ## Approach Nearly every Dashboards spec shares the same page objects, so the work was done in **sequential batches** (one committed, verified unit at a time) to keep page-object edits conflict-free. 13 commits, mapping 1:1 to those batches. ## Not changed (by design) - **`waitForTimeout`** left as-is — logged in the audit, not rewritten (per direction). - **Browser-context code inside `page.evaluate()` / `waitForFunction()`** (`document.querySelector`, `window.*`) left as-is — it runs in the page's JS engine, not Node, so `testLogger` (a Node module) can't be called there. *No `console.*` remained in dashboards specs*; the Node-context ones were converted to `testLogger`. - **`newPage.locator(...)`** on separate popup `Page` instances left as-is (not the fixture `page`). ## Verification - **0 raw fixture-`page` selectors** across all specs — single- and multi-line, comments stripped. - All changed `.js` files pass `node --check`. - **CI-gated** for browser execution (no local runs), consistent with #13727. The enterprise E2E crosscheck already passed against this PR. ## Stats 82 files changed (+3,355 / −2,211) — 61 specs, 21 page objects. Selectors **moved into page objects, not deleted**. |
||
|
|
82d14e8458 |
test(sentinel): POM compliance across Playwright suite (non-Dashboards) (#13727)
## What & why Sentinel (Council of Agents) audit-driven **Page Object Model compliance** across the Playwright suite. Many specs (a lot added recently, some AI-generated) had raw `page.locator(...)` / `page.getBy*(...)` selectors directly in spec files — including inside `expect(...)` — which the Sentinel flags as CRITICAL. This PR relocates those selectors into their page objects and calls page-object methods/getters instead. A full audit of **all 256 specs** was generated first (stored locally under `tests/ui-testing/MD_Files/sentinel-audit-2026-08-10/`, which is gitignored). Original totals: **1,609** raw selectors, **190** inside assertions, plus console/testLogger items. ## Scope of THIS PR (non-Dashboards) Every non-Dashboards spec is now **100% raw-selector clean** (verified: 0 occurrences). Shards covered: - **GeneralTests, Logs (Core/Builder-Advanced/Features/Regression), Traces (+Reg), Streams (+Reg), Metrics (+Reg), Pipelines, Reports (+Reg), Anomaly, Login/auth, auth-warm, and the unmatched Alerts specs.** - `console.*` → `testLogger` where it was Node-context (kept `console.*` **inside `page.evaluate()`** — that's browser context; `testLogger` doesn't exist there). - `testLogger` import/use added where missing. - **`waitForTimeout` intentionally left as-is** (logged in the audit, not rewritten — per direction). ## Deferred to a follow-up PR The **heavy Dashboards shards** (Variables 693, Config-Settings 255, Tables 127, Charts 81, Core 79, Visualize 65, Settings 52, Panel-DateTime 55, Dashboard-Regression 52 raw selectors) are **not** in this PR — they're the bulk of the work and will be a separate, focused pass. (dashboard-streaming console cleanup is included here.) ## Verification Fixes were applied and executed **shard by shard** against a local env, gated green before commit where the env allowed: | Group | Local result | |-------|--------------| | GeneralTests (edited specs) | 52 passed / 11 skipped / 0 failed | | Logs (shareLink, logsQuickPick, indexquery) | 21 passed | | Traces / Streams / Metrics | 49 passed / 2 skipped / 0 failed | | Pipelines | 56 passed / 17 skipped / 0 failed | | logs-bugs :548, dashboard-streaming | verified not regressed (isolation) | **Alerts create-wizard specs** (Alerts shard, Alerts-Regression, unmatched Alerts) could not be gated locally — the alert-creation wizard's stream popover times out on this env **on unmodified code too** (reproduced on original, test `:363`), so those refactors are 1:1 selector→method mappings, syntax-clean (`node --check`), and rely on CI to gate. Every changed `.js` passes `node --check`. `waitForTimeout` unchanged; no behavior changes intended. ## Stats 51 files changed. Selectors moved into page objects, not deleted. |
||
|
|
b3e6a77270 |
fix(correlation): service-streams P2 behavioral fixes + discovered services flat table (#13710)
Correlation P2 round: behavioral/security fixes across the service-streams backend and correlation FE, plus the Discovered Services UX rework and the correlation e2e suites. **Companion enterprise PR (must merge together):** openobserve/o2-enterprise#2381 — the enterprise side calls the new 3-arg `put(org, record, max_streams_per_type)` introduced here. ## Commit 1 — behavioral fixes (F2–F38) **Backend** - F25/F26: RBAC on `list_services` (`service_streams` GET — the one previously-unenforced endpoint in the module) + validate `distinguish_by` ids on identity-config save - F2: validate trace filter param before WHERE-clause interpolation - F6: `_reset` invalidates caches on all nodes via reload event; org deletion clears service-streams caches - F8: shared coverage-based identity-set ranking for ingest and read - F10: purge rows of removed/changed identity sets on config save - F19: `put` returns deleted orphan keys for cache eviction - F28: discriminate no-match from failure; stop aliasing 404 to no-match - F32: cap DB-side stream union at `max_streams_per_type` - `all_dimensions` unions on put so late-tracked dimensions surface - F14: `StreamInfo.dropped_dimensions` contract field; allow empty `tracked_alias_ids` when identity sets exist **Frontend** - F35/F36/F31: per-stream filter-edit resolution via semantic groups; dimension edits in both key spaces; subject overrides never guess fields - F27/F30: echo `source_stream`/`source_type`; stop guessing another stream's filters; chip dedup - F2/F38: SQL field/value escaping via shared `quoteSqlLiteral` helper ## Commit 2 — Discovered Services UX + e2e - Flat table (one row per instance), same-name services merge their name cell (OTable `pivotRowColumns`); optional per-service collapse with aggregated summary row; search/filters override collapse - Fixes an OTable pivot-merge bug (value-keyed merge map blanked single-column runs) + regression test - Semantic Field Groups: category tabs with counts + cross-category search with match highlighting - Correlation Phase-1 API + Phase-2 UI Playwright suites ## ⚠️ Release note (enterprise + RBAC deployments) Viewing Discovered Services now requires the **Service Streams** permission (previously unenforced). Root/admin users are unaffected; custom roles may need a one-time grant via the role editor (resource already exists in the OFGA model). ## Checks - `cargo fmt --all --check` ✅ · `cargo clippy --all-targets` ✅ enterprise + OSS feature sets (0 warnings) - prettier ✅ · eslint 0 errors · 207 unit tests on touched specs ✅ - Compiles with paired enterprise branch ✅ |
||
|
|
7ab93c04d5 |
test(reports): heal reports-regression timezone spec (edit-prefill race + toast selector) (#13724)
## What Heals the Reports regression spec `reports-regression-bugs.spec.js` → *"Report save should not shift timestamp by timezone offset"* (@bug-11231), which was failing deterministically (all 4 retries) in both the OSS and ENT **Playwright Regression** runs: - OSS: https://github.com/openobserve/openobserve/actions/runs/31364820545 - ENT: https://github.com/openobserve/o2-enterprise/actions/runs/31364817885 This is **test-only** — the product is unaffected (the historical #11231 fix and normal report save both work; a save actually succeeds in the failing run). ## Root cause (two independent defects) 1. **Wrong success-toast selector (deterministic line-118 failure).** The save assertion used `page.getByRole('alert')`. `OToast` renders the **success** variant with `role="status"` — only **error/warning** toasts get `role="alert"` ([`OToast.vue`](https://github.com/openobserve/openobserve/blob/main/web/src/lib/feedback/Toast/OToast.vue) `rootRole`). So the assertion could never match a successful save and timed out. → now asserts on the success toast `[data-test-variant="success"]`, consistent with the rest of the file. 2. **Edit-prefill race (line-84 failure, the one captured in the trace).** On the edit flow, step-1 `Continue` could fire before the async edit prefill (`form.reset()` after the report GET) populated folder/dashboard/tabs. `goToStep()` then failed validation and silently stayed on step 1, so the schedule toggle never rendered and the test timed out looking for it. → `createReportContinueButtonStep1()` now retries the click until the schedule step is actually reached, **keeping** the original post-advance settle so downstream step-2 interactions (schedule-later toggle, step-2 Continue) don't race. Also dedups the spec's inline date/time entry through the existing `createReportDateTime()` helper (logic unchanged). ## Verification (local, `localhost:5080`) | Suite | Result | |---|---| | `reports-regression-bugs.spec.js` (target) | ✅ stable across repeated runs (1 + 3× repeat-each) | | `reportsScheduleLater.spec.js` | ✅ 6/6 | | `reportsScheduleNow.spec.js` + `reportCsvMediaType.spec.js` | ✅ 13/13 | The two changed page-object methods are shared with the sibling Reports specs above; all pass, confirming no regression. ## Scope The spec lives in OSS `tests/` and is tree-merged into the ENT regression run, so this single OSS change fixes both pipelines. No ENT repo change required; the ENT regression will be re-triggered against this branch. |
||
|
|
087e1498ab |
feat(slos): add SLO burn-rate alerts (#13704)
design at /slo ## What Adds **SLO burn-rate alerts** — an alert family that fires off an SLO's error budget rather than a raw query — and finishes the SLO surface around it: navigation entry, detail-page fixes, and the flag removal now that SLOs have shipped. ## Changes **SLO burn-rate alerts (backend)** - New burn-rate evaluation (`config/src/meta/slo/burn.rs`, `condition.rs`) with multi-window burn conditions, and `core/src/slo/evaluate.rs` extended to evaluate them on the SLO job. - Alerts carry an `slo_id`; `infra/src/table/alerts` gains the column, filtering, and query support so an SLO's alerts can be listed and deleted with it. - Alert levels (`meta/alerts/level.rs`) and tags extended for the SLO family; scheduler handlers route SLO alerts through the same notification path. **SLO alert UI** - `SloAlertForm` + `AlertDetailSlo`: create, edit and view burn-rate alerts from the SLO detail page and the alert list. - Payload/routing helpers (`utils/alerts/sloAlertPayload.ts`, `sloAlertRouting.ts`, `alertPayload.ts`) with unit tests. - `AlertDestinationsField` extracted as the complete Destination form field — side label, tooltip, combined destinations/workflows picker, inline error, refresh, and create-in-new-tab. It replaces two verbatim copies in the generic alert form and is reused by the SLO form and synthetics `CheckAlerts` (which sets `supportsWorkflows: false`, since a check has no workflow routing). Fixes the SLO form's previously unwired refresh and Add Destination buttons. **SLO detail page fixes** - Burndown and burn-rate charts drew as bare axes when coverage was sparse: `showSymbol: false` means an isolated measured bucket between gaps has no segment and paints nothing. Symbols are now sized per point, and a sparse-coverage note states how many buckets actually recorded events. - Nothing scrolled below ~700px of viewport height — `OPageLayout`'s fixed flex body plus `OTabPanels` `scroll="none"` clipped the panels. Panels now grow and scroll; the stat strip and tab bar stay pinned. Verified at 1024x500, 1280x620, 1512x945. **Other** - `ZO_SLO_ENABLED` removed — SLOs have shipped, so the flag and its status/route gating are gone. - SLOs surfaced in the main nav. - Dashboard chart panel header gets its own tint via new `--color-panel-bar-bg` / `--color-panel-bar-border` tokens, and the bar is extracted into `PanelBar.vue` (it existed as five hand-copied class strings that had already drifted). - `tsconfig.vitest.tsbuildinfo` untracked; third-party vendor name removed from comments and test names. ## Testing - New Rust tests across `meta/slo/burn.rs`, `condition.rs`, `core/src/alerts/alert.rs` and `infra/src/table/alerts`. - New frontend suites: `sloAlertPayload.spec.ts`, `sloAlertRouting.spec.ts`, `alertPayload.spec.ts`, `AlertDetailSlo.spec.ts`, `SloDetailAlerts.spec.ts`, `SloListDelete.spec.ts`, `SloTimeSlicePreview.spec.ts`. - `cargo clippy --all-targets` and `web` `lint:ci` clean. |
||
|
|
735dc7d58d |
feat(traces): restore in-page Service Graph / Service Catalog tabs alongside standalone routes (#13698)
## What #13659 converted Service Graph and Services Catalog from in-page tabs on the Traces page into standalone routes reached from the nav-rail flyout. This PR restores the in-page tabs as a **second access path** — both now coexist, with distinct semantics: | Path | Semantics | |---|---| | Toolbar tabs on `/traces` | In-page view switch (`?tab=service-graph` / `?tab=services-catalog`), shares the page's stream + time context — the pre-#13659 UX, including old `?tab=` bookmarks | | Nav-rail flyout | Navigates to the standalone routes `/traces/service-graph`, `/traces/services` — unchanged from #13659 | Both paths render the same inner components (`ServiceGraph.vue`, `ServicesCatalog.vue`); only toolbar chrome differs. ## How A guided **reverse-apply of #13659's diff to `Index.vue` + `SearchBar.vue` only** (verified byte-identical to the pre-PR files — both were untouched on main since), with four deliberate adaptations: - **Re-added `applyHandoffFilter`** + its two hook call sites, which the revert would have deleted — the standalone pages' "View Traces" handoff (`?filter=` landing) depends on it. Covered by a new unit regression test and verified live. - The restored in-page `view-traces` handlers call `viewTracesHandoff.ts` (`buildViewTracesFilter` / `normalizeViewTracesPayload`) instead of resurrecting the inline filter builders that #13659 extracted from them — no re-duplication. - **Fixed a latent pre-#13659 bug**: the graph tab's refresh button called `serviceGraphRef?.loadServiceGraph()`, which was never in `ServiceGraph.vue`'s `expose()` — now `refresh()`. - **Flyout highlight now follows the visible view** on both paths: new `SubnavChild.activeOnTab` alias marks the Service Graph / Service Catalog flyout items active when `/traces?tab=…` shows their view in-page. Previously the same view highlighted different flyout items depending on how you reached it — the only submenu that deviated. Also: - Renamed the "Services" submenu / page header / route title to **"Service Catalog"**, matching the toolbar tab label (single `menu.services` locale value covers all). - `global-setup.js` login verification moved to `navbar-main-nav` — the same stale-selector fix #13659 applied to `enhanced-baseFixtures.js`; suites fail setup on main without it. ## Tests | Suite | Result | |---|---| | Unit: `SearchBar` 69, `Index` 76, `ONavGroup` 18 (5 new `activeOnTab` cases), `viewTracesHandoff` 21, `navGroups` 28 | all pass (233 total, 2 pre-existing skips) | | E2E (new) `Traces/traces-toolbar-tabs.spec.js` — in-page tab switches, shared-datetime carry, `?tab=` bookmark reload, flyout→standalone-route coexistence | 4/4 vs live enterprise build | | E2E `Traces/service-catalog.spec.js` (standalone-route regression) | 18 pass | | `type-check`, `eslint` (0 errors), `prettier`, `lint:design:strict` | clean | Not run: `Traces/service-graph.spec.js` — its `beforeAll` ingests via `ZO_BASE_URL`, which requires a single-origin instance (CI); the dev vite+backend split can't satisfy it. Nothing in this PR touches `ServiceGraph.vue` or the standalone views. ## Notes for review - `Index.vue` / `SearchBar.vue` restored regions are intentionally verbatim pre-#13659 (including its 16 pre-existing lint *warnings*) — deviations are limited to the four adaptations above, so the diff-vs-pre-PR is auditable. - Two known-inert quirks restored deliberately, not bugs to fix here: `hide-splitter-separator` has no CSS rule (was a no-op pre-#13659 too), and `@update:activeTab` writes to a getter-only computed. --------- Co-authored-by: Shrinath Rao <shnath@openobserve.ai> |
||
|
|
47d510aa16 |
feat: rebuild the RUM error detail page around issue impact (#13697)
Design at: designs/mobile-rum-sdk-evaluation/design-docs The page showed a single error event: header, tag strip, stack trace, replay button, event list. It could not say how bad the error was, who it reached, whether it was new, or where it concentrated — it never queried anything beyond that one row. It is now a two-column triage surface: the diagnosis path (occurrences chart, stack trace, breadcrumbs) on the left, corroborating evidence (replay, backend trace, breakdown, who hit it) on the right. - ErrorHeader: error type as the title with handling/source badges, the message in an alert banner, and a context line carrying event id, route and the service/version/env chips. Copy-permalink and copy-event-id actions. - ErrorImpactStrip: occurrences, users, sessions, first/last seen. A dash, not a zero, when a figure is unavailable. - ErrorOccurrencesChart: this signature over time, marking the bucket that holds the event the page was opened on. - ErrorFacetBreakdown: browser / OS / release / page as share-of-occurrences bars, calling out any value that owns 80%+ of the traffic — usually the fix. - ErrorContextCard: identity, device, geo and deployment for this occurrence. Supersedes ErrorTags, which is removed. Backed by useErrorDetail + errorDetailQueries: an impact aggregate gates a histogram and two facet group-bys. Three searches, staged inside the server's work-group cap and aborted when the view is left. Facets are split across two group-bys on purpose — one query over all four columns returns their cross product. Also fixes the breadcrumb trail: it read an hour of the whole stream with no session filter, so "what the user did before the crash" could be other people's clicks. It is now scoped to the session id. |
||
|
|
93cfbee117 |
fix: Issue ent 2343 alert improvements v3 (#13670)
Co-authored-by: ktx-akshay <akshay.patil@kiara.tech> |
||
|
|
06afa242fb |
chore(deps): bump uuid, @openobserve/browser-logs and @openobserve/browser-rum in /tests/ui-testing/fixtures/rum/npm-app (#13688)
Removes [uuid](https://github.com/uuidjs/uuid). It's no longer used after updating ancestor dependencies [uuid](https://github.com/uuidjs/uuid), [@openobserve/browser-logs](https://github.com/openobserve/browser-sdk/tree/HEAD/packages/browser-logs) and [@openobserve/browser-rum](https://github.com/openobserve/browser-sdk/tree/HEAD/packages/browser-rum). These dependencies need to be updated together. Removes `uuid` Updates `@openobserve/browser-logs` from 0.3.4 to 0.4.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/openobserve/browser-sdk/commits/HEAD/packages/browser-logs">compare view</a></li> </ul> </details> <br /> Updates `@openobserve/browser-rum` from 0.3.4 to 0.4.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/openobserve/browser-sdk/commits/HEAD/packages/browser-rum">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/openobserve/openobserve/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
739054c7bd |
feat: metric chart improvement (#13546)
Design At: designs/dashboards/metric-chart-override-support/ 1. For metric chart conditional text color, background color, value override support. 2. sparkline for metric chart. --------- Co-authored-by: ktx-akshay <akshay.patil@kiara.tech> |
||
|
|
18a53716f6 |
test(traces): heal service-graph Metrics-tab correlation detection (#13674)
## What Fixes the one remaining alpha1 Traces failure after the service-graph route deploy: **`service-graph.spec.js` → P1: Show telemetry correlation from node panel via Metrics tab**. Test-only, no product change. ## Root cause The test asserted on two hooks that never reach the DOM: - `service-graph-side-panel-metrics` sits on an `OTabPanel` whose `data-test` is **swallowed by `<Transition>`**. - `service-graph-side-panel-metrics-dashboard` is passed to `<TelemetryCorrelationDashboard>`, which has **multiple top-level roots** (dialog `ODrawer` / embedded `div` / `ODialog`) → it renders a **Vue fragment**, and Vue 3 **drops fallthrough attrs on fragment roots**, so the `data-test` is never applied. On alpha (which seeds only traces, no metrics), the correlation returns a **zero-stream dashboard object**: the dashboard branch renders (so the parent empty-state is suppressed), but there are no stream rows and the dashboard hook doesn't exist → the test's `else` branch `expect(hasError || hasEmpty)` fails. The test only ever passed before when correlation happened to return *empty*; it broke as soon as real correlation data appeared. Confirmed live on the deployed build: after clicking Metrics, the panel wrapper `data-test` is absent, while the correlation view's real content (`correlation-event-header-*`, metric selector) renders fine. ## Fix Wait on the correlation view's **real rendered content** — the correlation event header, or a terminal empty/error state — instead of the swallowed/dropped wrappers, and assert only that the Metrics tab **resolves** (the helper throws if nothing renders, catching a genuinely broken tab). Metric-stream rows are asserted only on the happy path when data is present. Deploy-independent: every element it waits on ships on the current build (verified), so it won't reintroduce the main-vs-deployed skew. ## Validation `--workers=1 --retries=0` against alpha on the previously-failing test: - 1 run → passed - `--repeat-each=2` → 2/2 passed `Metrics tab resolved: streamsPresent=false → resolved with no correlated streams (acceptable) → Test PASSED` ## Context The other 9 service-graph failures were the missing `/traces/service-graph` route (#13659) and cleared on deploying latest `main`. Sibling fixes from the same alpha1 triage: openobserve#13672 (alerts move flake), o2-enterprise#2370 (per-org cleanup). |
||
|
|
e1a265d7f0 |
test(alerts): heal Move-across-folders selection-wipe flake (#13672)
## What
Heals the recurring flake in `alerts-e2e-flow.spec.js:160` — **E2E:
Alert Folder Management - Move, Search, Verify** — which fails with
*"Move drawer failed to open after retries"* (the
`alert-list-move-across-folders-btn` never becomes visible). Also
hardens the sibling caller in `alerts-ui-operations.spec.js`.
**Test-only change. No `web/` product code is touched.**
## Root cause
`AlertList.vue`'s `getAlertsFn()` runs `selectedAlerts.value = []` at
the **start of every folder fetch**. The move / export / pause buttons
are `v-if="selectedAlerts.length > 0"`.
- Switching to a freshly-created (**uncached**) folder kicks off an
async `listByFolderId` fetch.
- `navigateToFolder` returns as soon as the folder tab is active and a
table is on screen — so `select-all` can fire **before** that fetch
resolves.
- When it resolves it **wipes the selection** → the move button
disappears → the drawer never opens.
- **Cached** folders serve synchronously with no wipe.
This precisely explains the observed signature:
- **Always failed attempt 1** (folder uncached), **passed attempt 2**
(retry warmed the cache).
- **Failed all 3 attempts under parallel load** — the slower API
guarantees the wipe lands after `select-all` every time.
`networkidle` doesn't catch it because streaming/websocket
(`ZO_STREAMING_ENABLED=true`) keeps connections open.
## The fix (`pages/alertsPages/alertBulkOperations.js`)
1. Before selecting, wait for the source folder's **own** row to render
(`expectAlertName`) — this proves the fetch resolved (wipe already
happened) and that we're on the right folder, not a stale table. Falls
back to "any row" when no name is passed (backward compatible).
2. Retry **select-all → click Move → assert drawer open** as **one
atomic `expect(...).toPass()`**. A fixed stability window isn't enough
(a second fetch can resolve later and wipe). The drawer is driven by its
own `showMoveAlertDialog` ref and captures the selection **at click
time**, so once open a later wipe cannot close it — the click just needs
to land while the selection is valid, which it always eventually does
once the folder is cached.
Both spec callers now pass `{ expectAlertName: alertName }`.
## Validation
Ran against the alpha cloud env on the exact failing scenario
(freshly-created uncached source folder, `--workers=1 --retries=0`):
- 1 initial run → **passed**
- `--repeat-each=3` → **3/3 passed**
`Move drawer opened with a valid selection` → `Moved all alerts to
target folder` on every run.
## Note
Not related to the concurrent Traces service-graph failures on alpha —
those are a separate main-vs-RC route skew (#13659 not in the deployed
RC build) and resolve on deploying latest `main`.
|
||
|
|
32d02d6781 |
chore(traces): make Service Graph and Services their own routes (#13659)
## What Service Graph and Services Catalog were tabs on the Traces page, switched via a `?tab=` query param on a single keep-alive route. They are now real routes, reached from a hover flyout on the Traces rail tile: | Route | Notes | |---|---| | `/traces` | Traces search — keeps the **Spans / Traces** toggle | | `/traces/service-graph` | enterprise-gated; redirects to Traces on OSS | | `/traces/services` | | **Spans stays an in-page toggle** on purpose. It's a view *granularity* that shares the query, stream and time range — you switch to it mid-investigation and expect context to carry over. Datadog's Trace Explorer does the same. Service Graph and Services are destinations; Datadog, New Relic and Grafana all treat them that way. ## Why this wasn't just cosmetic As tabs, all three views shared one `meta.title`, one history entry, and the traces page's `searchObj`. That last part is why Service Graph and Services Catalog inherited the traces page's selected stream — the coupling this PR removes structurally. ## UI Both pages now use the Agent Graph header pattern (`OPageLayout` + title/subtitle/icon, date picker and last-run refresh in `#actions`), with a subnav row carrying stream selector + search on the left and view-type + layout on the right. ## Handoff `view-traces` no longer mutates the shared store from a sibling tab. Both views build the same filter string — extracted verbatim into `viewTracesHandoff.ts` — and navigate to Traces with it as query params, so the URL survives a reload. (Traces then canonicalises `filter=` to its own base64 `query=` via existing code in `useTraces.ts:290`.) ## Two bugs this surfaced Both were things the tab views inherited for free and now have to set themselves — and both would have hit real users deep-linking these pages: - **`organizationIdentifier`** was only assigned inside the Traces page's `loadPageData()`. Without it the catalog issued requests to `/api//_search_stream` (empty org segment) and rendered nothing. - **`?period=` / `?from=`+`?to=`** were only applied by the Traces page's `restoreUrlQueryParams()`. Without it a shared link carrying a time range silently opened on the 15-minute default. ## Tests | Suite | Result | |---|---| | `Traces/service-graph.spec.js` | 14 / 14 | | `Traces/service-catalog.spec.js` | 10 / 10 | | `RegressionSet/Traces/traces-ent.spec.js` | 1 / 1 | | Unit (`Navbar` + `plugins/traces`) | 2514 pass | Also clean: `type-check`, `eslint` (0 errors), `lint:design:strict`. Test-side changes: navigation POMs go through the rail flyout instead of the removed toggles; the graph POM pins an explicit window, since on its own route the graph no longer inherits the traces page's range. The shared auth fixture now verifies against `navbar-main-nav` — it keyed off `menu-link-/-item`, which the current rail no longer renders, so suites failed setup even after a successful login. Filter-building coverage moved with the code into `viewTracesHandoff.spec.ts` (21 tests) rather than being deleted alongside the component tests that asserted the old in-page handlers. ## Known / follow-up - `RegressionSet/Traces/traces-regression.spec.js` has 2 failures (trace column sorting, pagination). **Pre-existing** — they fail identically against production on `main`, and the Service Catalog test in that file passes. - Both views still default their stream picker to the traces page's selected stream. Defaulting Service Graph and Services to **all streams** is a deliberate follow-up: on our own instance the `default` stream shows 22 topology nodes vs 71 across all streams, and services like `o2-ai` span 4 streams. Graph is a one-line change (the API already supports it); the catalog needs a backend decision, so it's out of scope here. |
||
|
|
fbe558b463 |
test(autoe2e): generated E2E tests for #13652 (stream-schema-timezone) (#13657)
🤖 Auto-generated E2E tests for #13652 — **healed to passing** against a live OpenObserve before this PR was opened. - Branch `autoe2e/pr-13652` (stacked on `main`), so the tests run against the feature code and pass before it merges. - Spec: `tests/ui-testing/playwright-tests/Logs/streamSchemaTimezone.spec.js` The repo Playwright CI re-validates here. Review is for **quality + coverage** — the tests already pass. _Generated by the E2E Council pipeline._ --------- Co-authored-by: Shrinath-O2 <214651540+Shrinath-O2@users.noreply.github.com> |
||
|
|
4d91f91a41 |
test(logs): fix alpha1 unflattened drawer-close detach flake (#13656)
## Problem On the **alpha1 (cloud)** e2e run, the **Logs-Core** shard failed and did not recover across all 3 retries. The single hard failure was: `Logs/unflattened.spec.js:220 › Unflattened testcases › stream to toggle store original data toggle and display o2 id` ### Root cause After switching to the **unflattened** tab, the test closed the log-detail drawer with a bare `closeDialog.waitFor()` + `closeDialog.click()`. Switching that tab re-renders the drawer, so the close-button node **detaches mid-click** — Playwright logs `element was detached from the DOM, retrying` and the click hangs for the full 45s, failing every retry identically. It's a deterministic race, which is why retries never helped. The secondary retry-failure signature (JSON detail panel lagging behind tab activation) is the same drawer instability, wider on the slower shared alpha env. ## Fix - Close the drawer via the file's existing resilient `closeLogDetailDrawerIfOpen()` helper (Escape fallback + wait-for-hidden) in **both** the failing test and its identical quick-mode sibling (`unflattened.spec.js` lines ~283 and ~426). - Harden `openJsonDetailTab()` (`pages/logsPages/unflattened.js`) to re-assert the JSON tab and re-wait once when the panel content lags, then fall back to the original throwing wait so a genuine non-render still fails loudly. Test-only change; no product code touched. ## Verification Seeded the **Run E2E Tests on Alpha1 (Cloud)** workflow against this branch (`o2_opensource_repo=test/alpha1-unflatten-drawer-close-flake`, enterprise on `main`): [run 31067277452](https://github.com/openobserve/o2-enterprise/actions/runs/31067277452) — Logs-Core and the overall run passed green. |
||
|
|
58c7dafa55 |
fix: notification templates v2 — rich content templates + alert chart images (#13640)
## Summary
Two coupled alerting features:
**1. Notification Templates v2 ("content" templates)**
- New `kind: content` template type: a structured spec (title, body
markdown, fields, links, rows, per-channel title overrides,
severity-filtered visibility) rendered natively per channel — existing
`custom` (raw body) templates are untouched and byte-identical on the
send path.
- Per-channel renderers: Slack Block Kit, Teams (Adaptive Card +
MessageCard), Discord embeds, PagerDuty Events v2, Opsgenie, ServiceNow,
SNS, HTML/text email, and a stable machine `webhook` envelope.
- Escaping is renderer-owned (mrkdwn entities, HTML encoding, markdown
stripping) with a shared URL-scheme allowlist; golden-fixture tests per
channel.
- Template editor UI: guided content form (fields/links row tables,
compact rows config, channel title overrides), live preview panel with
per-channel preview + payload tab, test-send (rate-limited,
`[TEST]`-marked).
- Migration `m20260802_000001_add_template_kind`; prebuilt default
template + org backfill.
**2. Alert chart images (stateless, storage-free)**
- Alerts can attach a metric-history chart PNG rendered from the
triggers self-reporting stream (`actual_value` per evaluation), with
warn/crit threshold lines and the firing point appended.
- Zero storage: the chart URL *is* the data — deflate+base64url payload
signed with truncated HMAC-SHA256 (org-bound, expiry embedded), rendered
on fetch by the HTTP-terminating node (`GET
/api/v2/{org}/alerts/charts/render`). Signature verified before inflate
(decompression-bomb guard), uniform 404s, per-node render semaphore +
per-minute query budget + small LRU.
- Renderer: plotters + embedded DejaVu Sans (Bitstream Vera license
included), gap-broken line segments so sparse evaluation history doesn't
draw false plateaus.
- Channel delivery: Slack image block, email inline CID (no remote
fetch), Discord multipart attachment, Teams/PagerDuty image URLs;
per-destination opt-in via template chart flag.
- Slack layout live-A/B'd on a real channel: content + buttons/chart
split across two same-colored attachments so the severity stripe spans
everything while staying under Slack's "Show more" fold; clickable link
title; "View in OpenObserve" keeps a reserved primary-button slot.
- Slack image-delivery fallback: Slack validates image URLs server-side
and rejects the ENTIRE message with `400 invalid_attachments` when its
proxy can't fetch the chart (VPN-only/private `ZO_WEB_URL`) —
live-verified. On that rejection the send strips the image blocks and
resends once (alert always delivers), sets a process-wide flag so later
sends pre-strip (reachability is deployment-wide, not per-destination),
and re-probes hourly. Zero config; observable via `slack_image_rejected`
/ `slack_image_pre_stripped` metric events.
## Testing
- 147 notification unit tests (resolve/render/preview/test-send incl.
per-channel goldens and hostile-input/injection coverage), 8 chart
payload tests, renderer PNG tests.
- Live-verified end to end: Slack (Slackbot chart fetches ~100ms,
cache-immutable semantics), SES email inline image, multi-severity
firing scenario (warning→critical) with correct threshold lines.
- FE: AddTemplate/ContentTemplateForm/preview specs; UX audit pass with
fixes.
- `cargo clippy -D warnings` clean in both OSS and enterprise
arrangements.
## Enterprise pairing
Must merge together with openobserve/o2-enterprise#2353 (workspace
twin-manifest mirror for the new OSS deps).
|
||
|
|
13acdd61da |
fix(web): hide LLM Model Pricing settings on OSS builds (#13651)
## What Hide **LLM Model Pricing** on OSS builds and make it an enterprise/cloud-only feature, end to end (UI + e2e coverage). Paired with o2-enterprise PR on branch `fix/hide-llm-model-pricing-oss`. ## Why Model Pricing was surfaced on OSS (settings rail + navbar flyout), gated only on the `model_pricing_enabled` backend flag with **no** enterprise/cloud check — unlike its sibling AI feature **LLM Providers** (`(isEnterprise || isCloud) && online_evals_enabled`). Product decision: it should not appear on OSS. This brings it in line with that sibling. ## Changes **Web (hide on OSS)** - `web/src/components/settings/index.vue` — settings rail item now `visible: (isEnt || isCloud) && !!z.model_pricing_enabled`. - `web/src/lib/core/Navbar/navGroups.ts` — `modelPricing` gate predicate now requires enterprise/cloud (mirrors `llmProviders`), so the collapsed-navbar flyout matches the rail. - `web/src/composables/shared/useManagementRoutes.ts` — `model_pricing` + `model_pricing/edit` routes registered only inside the `isEnterprise || isCloud` block (defense-in-depth; matches `llm_providers`), so the route isn't reachable by direct URL on OSS. **E2E (move coverage to ENT)** - `tests/ui-testing/ci-matrix/ci_matrix.json` — drop `model-pricing.spec.js` from the OSS `GeneralTests` shard. It's added back on ENT via the enterprise overlay (`ci_matrix.ent.json`, in the paired ENT PR), so the merged ENT matrix runs it exactly once (verified with `build-ci-matrix.js`). - `.github/workflows/playwright.yml` — remove `ZO_MODEL_PRICING_ENABLED: true` (OSS no longer exercises the feature; ENT `playwright.yml` keeps it). - `tests/ui-testing/playwright-tests/GeneralTests/settings-form-validation.spec.js` — gate the *ModelPricingEditor* describe block to a clean SKIP on OSS, mirroring the existing Domain Management / Org Storage / Correlation blocks. - `tests/ui-testing/pages/generalPages/settingsFormValidationPage.js` — `navigateToModelPricing()` now returns a boolean so the suite can detect the OSS build and skip (mirrors `navigateToDomainManagement()`). ## Not changed (deliberately) The backend `ZO_MODEL_PRICING_ENABLED` default (`true`, [config.rs](src/config/src/config.rs)) is **left as-is**. It lives in the shared config crate used by both editions, so flipping it to `false` would also regress real ENT/Cloud deployments (feature off by default). The UI gate already ensures the page never shows on OSS regardless of the flag. Making the backend itself enterprise-only would be a separate, backend-owned change. ## Behavior | Build | Model Pricing UI | e2e | |-------|------------------|-----| | OSS | Hidden | `model-pricing.spec.js` not run; settings-form-validation block SKIPPED | | Enterprise / Cloud | Shown (if flag set) — unchanged | `model-pricing.spec.js` runs (via ENT overlay) | |
||
|
|
98e03bca15 |
test(e2e/alpha1): stabilize the alpha1 cloud suite — auth self-heal, infra, and per-test heals (#13626)
## Stabilize the Alpha1 (cloud) e2e suite + regression carryover Root-caused and fixed the failures surfacing on the Alpha1 cloud runs — investigated live via Playwright MCP against alpha and, where possible, a local build. Grouped by theme. Every fix is non-masking (still fails if the underlying is genuinely broken). Pairs with ENT #2351 (`max-parallel` + Logs-SelectStar `quick_mode`). ### Runtime / infra resilience (whole-suite) - **Auth self-heal on 401 / session expiry** — the shared cloud session + per-org passcode are minted once and reused all run; on load/contention they expire mid-run (`User not authenticated`, `HTTP 401 Unauthorized`). `cloud-auth.authedRequest` refreshes the passcode and retries on 401 (escalating to a full Dex re-login if the session is dead); `navigateToBase` re-authenticates and resumes instead of throwing. Also routed the alert **template-creation** API through it (401 there cascaded into "Failed to navigate to templates"). Gated on `isCloudEnvironment()` — no self-hosted change. - **`--disable-dev-shm-usage`** on the alpha1 Chromium launch — the EKS pods used the default 64MB `/dev/shm`; under 5 workers on long/heavy shards Chromium exhausted it and the pod OOM-killed → "runner lost communication" (frozen step + 404 logs). Route shared memory to /tmp; eliminates the infra deaths. - **Service graph queries a wide window** (`period=6h`) — the tab defaulted to Past 15 Minutes and rendered "No service graph data" before the daemon-processed topology fell inside the window. ### Pipelines - `queryStream(stream, expectedMinCount)` **polls until the record count lands** (pipeline output arrives async) — was single-shot ("Expected 5, got 3"). - `openPipelineForEdit` **searches + polls-with-reload** for the edit button (list not refreshed after save → 45s click timeout). - `exploreStreamAndNavigateToPipeline` **reloads the streams list** while polling for Explore, and **falls back to a direct logs URL** when a freshly-ingested source stream never surfaces in the list (stream-stats lag). ### Alerts - Alert-destination URL → **public `example.com` webhook** (self-host URL hit the cloud **SSRF guard** → form never closed). - **Force-click the virtualized folder item** (#9484) — the row re-rendered mid-click → 45s "not stable". - **Export button readiness** — it's rendered only on selection; wait for visible+enabled (re-selecting if needed) before clicking. - **`deleteAlertByRow` cleanup readiness** — the just-created alert's more-options kebab needs longer than 5s under load. ### RegressionSet - **Use the shard's org** (`getOrgIdentifier()`), not hardcoded `org_identifier=default`, in `logs-bugs` — on cloud the data lives in `auto_org_N`, so the logs page never rendered. - **Unique stream names** for `logs-9754` / `logs-bugs:1419` — fixed names collided with concurrent shared-org runs ("stream is being deleted"). ### Traces / correlation - **Migrated `logs-bugs:995` (bug-11469)** to the redesigned correlation UI — the old `log-correlation-btn` / `correlation-dashboard-close` are gone; repointed to the inline `correlated-traces-tab`, assertion (`expectNoContextMenuVisible`) unchanged and **verified live on alpha** (no fake-pass). ### Workflows (ENT-only) + misc - **Healed the workflows destination flow** and forced-type Connection-step assertion; alert/report list-readiness hardening. - **Enrichment tables list** readiness (30s + re-nav retry) — "slow under load". ### Notes - Validated live via MCP (alpha) and a local build where the feature exists. - Alpha1 config already runs `retries: 2`; the remaining first-attempt flakes are shared-env load, addressed on the ENT side via `max-parallel`. |
||
|
|
dafc1ce7f7 | feat(ui): dashboard query editor redesign (#13637) | ||
|
|
3285a31e6f |
fix: i18n lint enforcement (#13439)
Co-authored-by: Kirtan Thakkar <kirtan@kiara.tech> |
||
|
|
98777be8be | fix: update enterprise feature (#13639) | ||
|
|
a384dd5ddd |
test(e2e/alpha1): robustness — auth self-heal + service-graph wide window (#13622)
## Alpha1 e2e robustness — self-healing auth + service-graph window Builds on **#13621** (re-auth self-heal). Both branches share the slug `test/alpha1-e2e-robustness` is stacked on `test/alpha1-reauth-on-401`; review/merge #13621 first (or merge this, which contains it). Root-caused against alpha1 runs 30892800970 / 30900015839 / 30902942856 (each investigated live via Playwright MCP). ### 1. Auth self-heal (from #13621, included here) Shared cloud session + per-org passcode are minted once and reused all run; on long runs / org-contention they expire mid-run → `User not authenticated` (UI) and `HTTP 401 Unauthorized` (API). Now: `authedRequest` refreshes the passcode and retries on 401; `navigateToBase` re-authenticates and resumes instead of throwing. **Verified working** in run 30902942856 — the auth storm cleared (Metrics/SDR/Streams recovered, zero `User not authenticated`), and `[auth] Refreshed cloud passcode after 401` fired and recovered mid-run. ### 2. Service graph queries a wide window All 9 `service-graph.spec.js` chart tests failed with `service-graph-chart` "element(s) not found" **despite** `beforeAll` confirming topology via API (25 nodes). **Reproduced live**: the service-graph tab defaults to **Past 15 Minutes** and shows *"No service graph data / 0 entities"* (no chart element) when the daemon-processed topology sits outside that window. The tab **honours the `period` URL param** (verified: label → "Past 6 Hours"). → `navigateToServiceGraphUrl` now navigates with `period=6h`; added `navigateToServiceGraphAndWaitForChart()` (poll + refresh, tolerates daemon lag). Non-masking. ### Honest scope - **Not included (can't validate locally / not test-code):** - **Pipelines ×5** (`Explore`/`update-pipeline` 45s timeout) — persistent across *every* run; pipeline/stream data unavailable. Env/data, needs CI-side repro. - **OTLP metrics ingestion 401** (a PromQL-prereq `beforeAll`) — a node-`fetch` ingest path with no page context to re-fetch the passcode; narrow, needs a small refactor to self-heal. - Singles: `logoManagement` (@enterprise `_meta`), `shareLink` (known race), `alerts-ui-operations:131` (#9484) — pre-existing flaky/env. - Service-graph is **enterprise/feature-gated** (403 in my org), so its fix is evidence-reasoned + validated at the URL-param level, but final proof is the seeded CI run. |
||
|
|
601ef75e2e | fix: IAM page UI changes (#13618) | ||
|
|
7999fd33f3 |
test: enhance logs visualization error handling and persistence tests (#13591)
## Summary Adds **10 E2E tests** covering the two defects fixed in #13244, plus the `SELECT *` behaviour change that shipped alongside them. Also introduces per-shard backend configuration so the `SELECT *` tests can actually run in CI. ## Test coverage ### `logsVisualizePersistence.spec.js` — 7 tests (quick mode **off**) | # | Test | Defect | Fix code exercised | |---|---|---|---| | 1 | Renders without the false required-fields error | A | `convertPanelData.ts` `!query?.customQuery` | | 2 | Restores chart type, query and chart after URL refresh (h-bar) | B | `setupLogsTab` re-run + `isInitialVisualizeRestore` | | 3 | Re-renders after reload with the default chart type | B | permanent No-Data half | | 4 | Restores a non-default chart type (area) after refresh | B | `restoreVisualizationFromUrlOnLoad()` | | 5 | Chart still renders after reload with a VRL function applied | B | `prepareVisualizeMode()` VRL copy | | 6 | Never shows required-fields error toggling Visualize → Logs → Visualize | A | manual-toggle rebuild path | | 7 | No `SELECT *` toast opening Visualize with no stream in the URL | B | page-load ordering guard | **Defect A** — false "Please select required fields to render the chart" on the custom-query Timechart panel. **Defect B** — URL refresh produced a `SELECT *` toast plus permanent No Data. ### `logsVisualizeSelectStar.spec.js` — 3 tests (quick mode **on**, dedicated shard) | # | Test | Behaviour verified | Call site | |---|---|---|---| | 8 | Table chart on `SELECT *` → toast shown **and** chart type reverts | Table is blocked | `Index.vue:2265` (watcher) | | 9 | Histogram chart on `SELECT *` → no toast, renders | Line/bar/area/scatter allowed | entry path | | 10 | `SELECT *` line chart survives browser refresh → no toast, state restored | Restore path doesn't re-emit | `Index.vue:2465` (restore) | ## Infrastructure changes | File | Change | Why | |---|---|---| | `ci_matrix.json` | New `Logs-SelectStar` shard with `quick_mode_enabled: "true"` | `isSelectStarForTable()` only exists when the server runs with quick mode on | | `playwright.yml` | Per-shard `ZO_QUICK_MODE_ENABLED` env on `Start OpenObserve` | The flag is read once at server start — a shard is the smallest unit that can vary it | | `build-ci-matrix.js` | Emit `quick_mode_enabled` (defaults `"false"`) | The field was being silently stripped by the emit whitelist | | `logsPage.js` | 13 assertion helpers + fixed chart-type detection | Detection read `data-selected` off the wrong element and matched retired CSS classes, so it always returned `null` | All 24 existing shards are unaffected — they omit the field and default to `false`. ## Notes on test quality - Every negative assertion ("no toast", "no error") is sequenced after a deterministic positive end-state, and gated on a precondition so it cannot pass vacuously. - Toast absence is proved with a MutationObserver recorder installed before the navigation under test, since toasts auto-dismiss. - The quick-mode precondition is a hard assertion, not `test.skip` — a misconfigured shard fails loudly instead of silently reporting "skipped". |
||
|
|
cc759bb6e0 |
test(e2e): fix Alpha1 shard failures (Alerts SSRF, sanity time-range, lazy Monaco, traces settle) (#13614)
## Alpha1 (Cloud) E2E — shard-by-shard failure fixes Fixes real, root-caused failures from Alpha1 run [30876689608](https://github.com/openobserve/o2-enterprise/actions/runs/30876689608) (5 red shards, 16 hard failures). Each root cause was reproduced live against alpha via Playwright MCP. **8 of 16 hard failures are fixed here in code**; the remaining 8 are environment/data-timing driven (backend instability during the run's 04:15–04:18 ingest window) and need a re-run, not a code change. ### Fixes | Shard | Fix | Root cause | |---|---|---| | **Alerts** (4) | `alerts-advanced.spec.js` destination URL → `https://example.com/webhook` | The self-host URL `${ZO_BASE_URL}/…/alerts_notify_sink/_json` resolves to a **private IP** on cloud, so the backend **SSRF guard rejects the save** → the New Destination form never closes → `createDestination()` times out, failing all 4 Alerts-Advanced tests. Verified live: private-IP URL is blocked, `example.com` (public, IANA-reserved, never delivered to) saves and closes the form. | | **GeneralTests** (2 + 2 flaky) | sanity `beforeEach` → `setDateTimeToPast1Hour()` (+ new `logsPage` helper) | The result-summary/pagination tests query the default **Past 15 Minutes**. `e2e_automate` ingestion is bursty on shared/cloud envs — **0 rows in 15m vs 7,850 in 1h** (confirmed via API) — so the result table never renders. This is exactly the failed-vs-flaky split seen on the run. | | **Logs-Features** (1) | `monaco-query-prefill.spec.js` → poll `getQueryEditorTextWhenReady()` | Lazy Monaco prefills its model asynchronously after a saved view is applied on a fresh page load. A one-shot read after a fixed 2s caught an empty editor (`Received: ""`). Now polls until the query lands. Non-masking: if it never prefills, the poll still times out and the test fails. | | **Traces** (1 of 2) | `tracesSearch.spec.js` → poll for a settled results/no-results state | The "no stream selected state" test read `hasTraceResults()`/`isNoResultsVisible()` once each; the async search settle left both momentarily false. Now polls until one terminal state renders. | ### Not changed (deliberately) - **Traces `traceQueryEditor.spec.js:151`** — the detail-tree check already waits 10s; its failure means the error-trace detail didn't open, which needs error-trace data in-window to validate. Weakening the assertion would mask real behavior. - **GeneralTests `enrichment.spec.js:101`, `logoManagement.spec.js:18`** — ran during the backend-instability window and can't be reproduced live. `[name='home']` is **not** stale (present live) and `_meta` access is fine for the test user. Env/timing. - **Pipelines (all 5)** — UI-click timeouts (`…-update-pipeline` / `Explore` button not found) because pipeline creation / stream data was unavailable while the backend returned *"No online node" / "Proxy request" / "Expected N records, got 0"*. Same selectors 42 passing tests in the shard use. Env-driven → re-run to confirm. ### Validation - All fixes reproduced/verified live on alpha via Playwright MCP (`e2etest1@o2-qa.com`, `auto_org_1`). - All 4 edited specs parse and list (`playwright test --list`). - Full local runs are blocked by an unrelated issue: the Dex login UI changed (new "Continue with Email" flow) so `global-setup.js` can't authenticate locally; CI uses the shared-auth artifact. (Worth a separate fix.) |
||
|
|
624425a08a |
feat(editor): rebuild query autocomplete, and fix the value path behind it (#13586)
Design at autocomplete/autocomplete.md
Rewrites the query editor's autocomplete across every surface that has
one, and
follows the field-value path far enough to fix the bugs it was hiding.
53
commits, in six phases; each phase was written test-first, reviewed
adversarially, and checked in a browser before the next one started.
## What was wrong
The completion providers were wired inconsistently. Six surfaces bound a
resolver that was never defined, so their value completion could not
resolve at
all — SLO, dashboards and anomaly detection among them. Traces never
bound
`:suggestions`. Alerts never called `updateStreamKeywords`. PromQL ran a
second
editor runtime purely for its grammar, and asked
`/prometheus/api/v1/series`
— the heaviest endpoint available — for data the stream schema already
has.
## Phases
**1 — icons, staleness, quoting.** Correct `CompletionItemKind` glyphs,
stream
keywords refreshed when the stream changes, `spath` quoting.
**2 — the function catalog.** Custom functions get one tab stop per
argument,
org VRL functions stop appearing twice, column types read from
`dataType` as
well as `type`.
**3 — signature help, hover, async completion.** Providers return real
`CompletionList`s with `incomplete: true`, so a list that arrives late
is
re-queried rather than pinned.
**4 — numeric ranking.** Numeric columns sort first inside a numeric
aggregate.
**5 — values for streams nobody has searched.** The value cache only
ever held
what a search had already returned, so a stream you had not queried
offered
nothing. Values are now fetched on demand, bounded (10s timeout, 60s
cooldown,
one in-flight request per key), and shared between the editor and the
builder.
PromQL joins the same path: labels from the stream schema, values from
the
shared cache. `/series` now has zero production callers.
**6 — one way to fetch a value.** Item 22 only, in this PR.
## The dashboard filter 400
Clicking the ✕ beside "Select Field" in a filter's dropdown sets the
column to
`{}`, and the watcher on `condition.column` then asks for that column's
values.
`loadFilterItem` built `fields: [row.field]` out of `undefined`,
JSON.stringify
turned that into `null`, and the server answered
```
400 {"code":400,"message":"SerdeJsonError# invalid type: null, expected a string"}
```
`_values_stream` answers 400, not an empty result, for each way a piece
of the
payload can go missing — and every one is reachable: an unresolved
stream alias
(`.find(…)?.stream`), a stream not yet chosen (`""`), a range not yet
set. The
range fails differently: `meta.dateTime` starts as `{start_time: ""}`
and
`""?.toISOString()` does not short-circuit, so it throws and both
callers
surface "Something went wrong!" for a lookup the user never asked to
fail.
Guarded at the two callers, where the payload is built and where the
throw
happens. Not at `fetchFieldValues` — a guard there is too late to stop
the
throw and would duplicate validation the callers need anyway. The
trigger is
left alone: re-picking a field must still load its values.
## Notable removals
CodeMirror is gone — it was still bundled for the PromQL grammar alone.
Bundle 26.3 MB → 25.43 MB; the PromQL chunks 442.7 KB → 20.6 KB. The
PromQL
term catalog went from 7 entries to 113, generated from Prometheus's own
tables
and vendored with its MIT notice.
## Verification
- 76 files, +10.5k/−1.4k, ~9,100 tests passing across the touched areas.
- `vue-tsc` clean, `npm run build` exit 0.
- Every phase checked in a running browser against a live instance,
including
the 400 above: the ✕ now produces no request and no toast, adding a
filter and
re-picking a field each still fetch once, and the value list still
populates.
## Known, deliberately out of scope
- A filter still fetches twice (once on add, once on open) — that is
item 23,
the cache read, not this PR.
- `useMetricsExplorer.loadFilterItem` has the same unguarded
`toISOString()`
pattern on a different surface.
- `services/metrics.ts` and `services/search.ts` still carry dead
`get_promql_series` wrappers now that nothing calls `/series`.
|
||
|
|
d76c0a6bbb |
ci(playwright): single-source ALL shard matrices via ci-matrix/ manifests (#13606)
## Why
The OSS and ENT Playwright shard matrices (`run_files` per `testfolder`)
were hand-maintained inline in each `playwright.yml` and had to be
synced on every spec add — error-prone and drift-prone (ENT was even
missing `dashboard-favorites`). This makes the shard list a **single
source of truth** for **every** Playwright workflow.
## What (OSS side)
All matrices are generated at run time from JSON manifests in
`tests/ui-testing/ci-matrix/`:
- **`ci-matrix/ci_matrix.json`** — PR-gate base (24 shards). The only
place shared shards live.
- **`ci-matrix/ci_matrix_regression.json`** — regression base (10
shards); `RegressionSet/<Feature>` mapping now carried in
`actual_folder`.
- **`.github/scripts/build-ci-matrix.js`** — merges base (+ optional ENT
overlay) → GitHub matrix; validates uniqueness / no dup specs / no spec
both active+disabled. Reused by ENT from its OSS checkout.
- **`ci-matrix/README.md`** — manifest index + how to add/move/disable a
spec.
- Workflows `playwright.yml` + `playwright_regression.yml`: new
`generate_matrix` job → `strategy.matrix: fromJSON(...)`; `case` blocks
→ `${{ matrix.actual_folder }}`.
Disabling a spec (JSON has no `//`): move it into that shard's
`disabled: [{file, reason}]` array — never emitted (won't run), record
survives. Every shard ships a `"disabled": []` placeholder.
## Safety (verified)
- **OSS `playwright.yml` and `playwright_regression.yml` matrices are
byte-identical to before** — zero behavior change.
- Companion ENT PR (same branch slug
`test/playwright-matrix-single-source`) derives its matrices from these
manifests + overlays.
## Validate
Add the `e2e` label; confirm `generate_matrix` prints the shard count
and the `e2e /` jobs fan out.
|
||
|
|
49448334ed |
test(alpha1): split shard logins across multiple Dex users (#13602)
## What Lets alpha1 shards log in as **different Dex users** instead of all hammering the cloud env as one user. Paired with **openobserve/o2-enterprise#2333** (the workflow wiring). ## Why - **Load distribution** — spreads API/session load across users if the env rate-limits per user. - **Blast radius** — one user's account/session issue stops ~1/3 of shards, not all. - Test **data isolation is unchanged** (still per-org); this is purely about the login user. ## Changes (OSS) - `global-setup-alpha1.js` — new `ALPHA1_USER_INDEX` (1|2|3) selects the Dex user: email resolves from `ALPHA1_USER_EMAIL_<N>`, **falling back to `ALPHA1_USER_EMAIL`** when the indexed secret isn't set (safe incremental rollout). Password shared (`ALPHA1_USER_PASSWORD`). - Auth **filenames stay canonical** (`user.json` / `cloud-config.json`) — ~20 specs + shared utils read those exact paths. The per-user split happens at the CI layer (each shard downloads only its user's artifact into the canonical path), so no spec changes needed. - New `auth-warm.spec.js` — a login-only spec the barrier uses to mint auth artifacts for users 2..N **without** running the heavy org-wide cleanup. ## Default behaviour With no index set, everything resolves to user 1 — identical to today. ## Enterprise PR openobserve/o2-enterprise#2333 |
||
|
|
503eca6264 |
fix(e2e): deflake logs autocomplete value-suggestion capture (#13593)
## Problem In [o2-enterprise run 30791574230](https://github.com/openobserve/o2-enterprise/actions/runs/30791574230) the **Logs-Features** shard logged **2 failed, 6 flaky, 3 skipped, 63 passed** with **52 retries**. Seven of the eight troubled tests are in `logs-autocomplete-suggestions.spec.js` (the eighth `code`-field test shares the cause), and every one dies on the identical assertion: ``` Error: Expected to find a field with captured values expect(received).not.toBeNull() Received: null ``` — i.e. the shared `findFieldWithStringValues()` helper returned `null`. ## Root cause A **click-time race**, not missing data (the `e2e_automate` stream holds 3848 rows ingested at shard start). The helper clicked a field's sidebar expand button and then polled IndexedDB for 10s — but the 10s window started at **click time** and raced the `/_values_stream` fetch. In the failing run the runner was slow (a perf assertion showed queries ~2.6× over baseline: 1055ms vs <403ms). The values response landed **after** the IndexedDB poll had already given up, so the record read as `null` and the assertion failed hard. Because `findFieldWithStringValues()` is shared across ~8 tests, one slow window knocked out the whole cluster, and each burned up to 4 attempts → 52 retries. An intended fix (`clickFieldExpandAndWaitValues`, a deterministic `/_values_stream` response wait) already existed in the file but was **never wired in**. ## Fix - **`expandFieldAndCaptureValues()`** — anchor the IndexedDB confirmation **after** the actual `/_values_stream` response instead of racing it from click time; re-click to re-expand if a prior collapse meant no fetch fired. Replaces the dead `clickFieldExpandAndWaitValues` helper and the bare click+poll in the `code`-field test. - **`findFieldWithStringValues()`** — scan via the anchored capture, with a bounded refresh-and-retry round so a transient empty `/_values` response self-heals rather than failing the test. - **Readiness gate** — add `waitForStreamData()` to every `beforeEach` so freshly-ingested data is searchable before the UI drives value capture (WAL → index lag). Best-effort so an already-warm shared stream never blocks. ## Testing - `node --check` passes; no linter is configured for the suite. - The slow-runner condition can't be reproduced deterministically locally; the change is a test-harness reliability fix (deterministic response-anchoring + readiness gate) that removes the timing dependency that caused the flake. Will confirm green via the ENT playwright regression this PR dispatches. |
||
|
|
de95f7f2d8 |
fix: restore Table default log-detail view (#13368) + heal alert-name inline-edit read (#13585)
## What & why Two **Playwright Regression** nightly failures, reproduced identically on both OSS ([run 30785096054](https://github.com/openobserve/openobserve/actions/runs/30785096054)) and ENT ([run 30785071382](https://github.com/openobserve/o2-enterprise/actions/runs/30785071382)) — same two shared-`tests/` specs, all 3 retries failed each. Both are OSS-owned specs (ENT overlays only its own `tests/*` and builds OSS `web/`), so this single OSS PR fixes both nightlies. ### 1. Logs — real product regression (`logs-regression.spec.js:1158`) `Log detail sidebar opens with Table tab by default (#13368)` → `Error: Table tab should be selected by default`. **Root cause:** [#13368](https://github.com/openobserve/openobserve/pull/13368) (Jul 23) deliberately made the log-detail sidebar open on the **Table** tab. [#13451](https://github.com/openobserve/openobserve/pull/13451) (Jul 30, *"table migration to same components"*) silently flipped `detailTableInitialTab` back to `"json"` in `SearchResult.vue` (both the `ref` init and the per-open reset). The unchanged test correctly caught the reverted behavior. **Fix:** restore `"table"` as the default log-detail tab. Product fix — no test change. ### 2. Alerts — stale test vs redesigned component (`alerts-stream-switching.spec.js:443`) `Bug #11577: Alert preview chart y-axis displays numeric values` → `TimeoutError: locator.inputValue: Timeout 45000ms exceeded`. **Root cause:** the alert name became an **`OInlineEdit`** title (`OFormInlineEdit`, from the [#13547](https://github.com/openobserve/openobserve/pull/13547) Alerts revamp). In display mode the value lives in the `…-value` span; the `…-input` only exists **while editing**. The test read `.inputValue()` on the non-existent input → 45s timeout. **Fix:** read the committed display value via a new `getAlertName()` page-object helper (with an edit-mode `inputValue()` fallback). ## Verification - **Alerts #11577** — ✅ passed locally against a local O2 build (`1 passed`); `getAlertName()` reads the name and the full save/verify/delete flow works. - **Logs #13368** — restores the exact `detailTableInitialTab = "table"` value #13368 set and the unchanged test already validated as green. Confirmed by this run's Logs-Regression job + the dispatched ENT e2e gate. ## Scope - `web/src/plugins/logs/SearchResult.vue` — 2 lines (product) - `tests/ui-testing/playwright-tests/RegressionSet/Alerts/alerts-stream-switching.spec.js` — read display value - `tests/ui-testing/pages/alertsPages/alertsPage.js` — `alertNameValue` locator + `getAlertName()` helper |
||
|
|
d99ecff3e8 |
feat(nav): add Reliability menu, restore deferred SLO routes (#13577)
Groups the alerting surface under one left-rail tile, and un-defers the SLO backend that shipped disabled. > **Lands with** openobserve/o2-enterprise#2321, which adds `ROUTE_PERMISSIONS` for the restored SLO endpoints — the route-coverage test pairs the two, so this one alone fails it. ## Reliability menu New `reliability` nav group absorbing **Alerts, SLOs, Incidents**, plus **Notification Destinations** and **Templates**, which move out of Settings — they are alerting configuration, not deployment configuration. Settings keeps Pipeline Destinations (that one really is pipeline config); its group is renamed "Destinations". Their routes are **top-level and flat** (`/alert-destinations`, `/alert-templates`) rather than nested under `/alerts`. They are siblings of Alerts, not sub-pages of it — nesting them made the URL claim otherwise and the rail believed it, highlighting Alerts alongside them. - Route **names** are unchanged, so the ~15 call sites that navigate by name are untouched. - Old `/settings/*` paths redirect, with the query preserved — `?action=import` deep links keep working. ## SLO routes `/api/{org}/slos` answered **404**. The routes were deliberately unregistered before the last release (`6977b4020d`, `ac78a622e1`) while the rest of the feature — `core/src/slo/*`, the infra tables, both migrations, the `slo_maintenance` job, all seven handlers — stayed in the tree. This restores the five registrations and the OpenAPI entries, recovered from the pre-strip commit rather than rewritten. `ZO_SLO_ENABLED` still **defaults to false**. It is now published as `slo_enabled` on `/config`, so the menu entry follows the flag instead of offering a page the API answers with 501. ## Nav active-state Active state was decided per child, so any section whose path prefixed the current route lit up alongside it. It is now resolved once per flyout: exact route-name match wins, else the **deepest** path prefix — so a genuine drill-down like `/alerts/detail/:id` is still attributed to Alerts. `placeAfter` also accepts a group key, letting Data anchor on the Reliability tile it follows rather than on an item that tile absorbs. ## Tests `tests/ui-testing` referenced `[data-test="alert-destinations-tab"]` / `alert-templates-tab` in six files — those data-tests were on the Settings rail items removed here, so the locators would have matched nothing and hung until timeout. Those paths now go through the existing `openNavFlyoutChild` helper, extended with the Reliability group. Two URL regexes that would have silently mismatched on the hyphen are fixed (one ended in `.catch(() => {})`, so it would have degraded to a silent 15s stall). ## Verification - 3597 unit tests pass; `vue-tsc` and eslint clean; enterprise build compiles. - `playwright test --list`: all 141 tests across 23 files load, no module errors. - Against a live server: `GET /slos` → 200, `POST /slos/move` → 422 (so the literal wins over the `{slo_id}` catch-all), `GET /slos/x` → handler-level `{"code":404,"message":"SLO not found"}`. - In the running app: `/alert-destinations`, `/alert-templates` and `/alerts` each highlight exactly one row; `/settings/alert_destinations?...&action=import` redirects with the query intact; rail order unchanged. |