Commit Graph
488 Commits
Author SHA1 Message Date
Shrinath Rao 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).
2026-08-07 01:26:07 +00:00
Shrinath Rao 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`.
2026-08-06 13:33:22 +00:00
Ashish Kolhe 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.
2026-08-06 10:30:03 +00:00
Shrinath RaoandShrinath-O2 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>
2026-08-06 07:00:06 +00:00
Shrinath Rao 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.
2026-08-06 04:49:28 +00:00
Ashish Kolhe 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).
2026-08-06 04:47:02 +00:00
Shrinath Rao 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) |
2026-08-06 01:54:37 +00:00
Shrinath Rao 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`.
2026-08-06 00:57:05 +00:00
ktx-vaidehi dafc1ce7f7 feat(ui): dashboard query editor redesign (#13637) 2026-08-05 11:17:44 +00:00
ktx-vaidehiandKirtan Thakkar 3285a31e6f fix: i18n lint enforcement (#13439)
Co-authored-by: Kirtan Thakkar <kirtan@kiara.tech>
2026-08-05 10:16:00 +00:00
Hengfei Yang 98777be8be fix: update enterprise feature (#13639) 2026-08-05 07:49:04 +00:00
Shrinath Rao 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.
2026-08-04 13:14:04 +00:00
ktx-vaidehi 601ef75e2e fix: IAM page UI changes (#13618) 2026-08-04 12:43:36 +00:00
ktx-akshay 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".
2026-08-04 12:09:26 +00:00
Shrinath Rao 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.)
2026-08-04 07:44:15 +00:00
Shrinath Rao 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
2026-08-03 07:19:28 +00:00
Prabhat Sharma 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.
2026-08-02 05:44:01 +00:00
83d12fff04 feat(web): inline-rename page titles with auto-generated default names (#13520)
## What changed

Naming an alert, panel, workflow, pipeline or function meant inventing a
name up front in a form field before anything else could be configured.
Two pieces replace that.

**Inline rename** — the page title *is* the input. `OInlineEdit` /
`OFormInlineEdit` (`web/src/lib/forms/InlineEdit`): click to rename,
Enter or blur commits, Escape restores the pre-edit value. A `#trail`
slot carries the "Auto" badge in display mode only.

**Auto-generated names** — `utils/autoName.ts` builds the name,
`composables/useAutoName.ts` decides when it's allowed to win. A name is
AUTO until the user types, then it's theirs for good; clearing the field
and blurring re-arms auto. The generators describe only what is actually
configured, so a half-built panel yields a shorter name rather than a
speculative one, and an empty string when there is nothing to say.

- Panel names read as prose — `Avg of duration by service`, `Record
count`, `k8s_logs overview`. Both live panel-field shapes are handled
(builder `functionName` + `args`, and legacy flat `column` +
`aggregationFunction`); the time column is read from
`zoConfig.timestamp_column` rather than hardcoded. Hand-written queries
fall back to the stream, since naming a panel after `x_axis_1` is worse
than saying nothing.
- Alert names are identifiers — `anomaly_k8s_logs`,
`k8s_logs_status_gte_500` — built to survive the backend's
`RE_OFGA_UNSUPPORTED_NAME` rule, with operators spelled out and a
`slugify` backstop. A leading underscore is preserved so internal
streams (`_rumdata`) keep their names.

### Supporting library changes

| Component | Change |
| --- | --- |
| `OPageHeader` / `OPageLayout` | New `titleOverflow="visible"` — the
`<h1>`'s `truncate` clips an interactive title's focus ring and the
error message it floats below itself |
| `OSelect` | New `appearance="inline"` — borderless, no fixed height,
sized to content, for a value that reads as a word inside running text
("Add Alert **in KTX**") |

All new strings go through i18n (`common.inlineEdit.*`,
`dashboard.autoName.*`, `alerts.autoName.*`, per-module `renameHint`).
Interpolated identifiers — column names, SQL functions, stream names —
stay verbatim.

## Wired into

AddPanel, AddAlert (+ `useAlertForm`), WorkflowEditor, PipelineEditor,
Functions / FunctionsToolbar, IncidentDetailDrawer,
InlineSelectFolderDropdown.

## Tested

244 unit tests across the 5 affected suites, all passing — including new
specs for `OInlineEdit`, `useAutoName`, and `autoName`.

One pre-existing expectation in `autoName.spec.ts` was updated: it
asserted `Avg of duration, max of duration +1 more`, capitalising only
the first word of a multi-measure name. `measureLabel` capitalises per
measure by design, so the expectation now reads `Avg of duration, Max of
duration +1 more`.

---------

Co-authored-by: ktx-vaidehi <134508096+ktx-vaidehi@users.noreply.github.com>
Co-authored-by: ktx-vaidehi <vaidehi.akhani@kiara.tech>
2026-07-31 08:50:19 +00:00
4772df1723 feat: per-group and per-series alerting, and SLO measurement (#13547)
Design at: alerts_2.md

Per-group and per-series alerting, SLO measurement, and the UI for both.

## Alerts

**Multi-alerts (Feature 3).** A grouped alert can opt in to evaluating
and paging **per group** rather than collapsing to one verdict. Opt-in
only (`multi_alert`), so no existing alert changes behaviour: the flag
cannot be present in JSON written before it existed. Per-group state,
transitions, silence fingerprints, disappearance/reaping and a
cardinality cap, with the count-gate rules that make "most severe group"
and the legacy collapsed level provably the same verdict.

**Per-series alerting for PromQL.** The same feature for the metrics
family, where a group is one returned **series** keyed by its full label
set — that is a series' identity in Prometheus, and the expression's own
`by (…)` clause is already where the label set is chosen, so a second
picker could only disagree with it. One additive nullable column; NULL
means off, so stored alerts are untouched.

**Alert detail page**, replacing the row-click side panel: stat strip,
evaluation chart with threshold marklines, per-group table and history.
Simple alerts get a real history too — evaluations (one record per run)
by default, level changes alongside.

## SLOs

Count / time-slice / alert SLIs, error-budget and burn-rate arithmetic,
rolling windows, per-group slices with an exact rollup, coverage gating,
backfill, and SLO-based alerts.

Two capabilities the model could not express, both added tests-first:

- **Metrics-native counting** (`CountSource::PromQl`) — counter metrics
have no rows for a predicate to classify, so "good" exists only as
arithmetic between series, and correct counter arithmetic is
`increase()`.
- **Freshness semantics** (`absent_is_bad`) — for a pipeline SLO,
silence IS the failure, which the default gap rule can never report. A
*failed* query still freezes rather than pages; only a query that PROVED
emptiness counts as bad.

**SLO form**: live good/bad preview so a wrong predicate is caught
before saving rather than days later, real query editors with field
autocomplete, folders shared with alerts, and a move endpoint.

## Notes for review

- The SLO and composite features are **deferred (TODO)**:
`ZO_SLO_ENABLED` stays default **false** and the SLOs menu entry is
hidden until they ship; the SLO backend and UI remain in the tree behind
the flag, and composites stay pure logic + tests.
- One migration (schema 61): a nullable column for the PromQL opt-in. No
backfill.
- Two fixes outside the feature that it surfaced: query-editor
completions were duplicated per mounted editor (Monaco registers
providers per *language*), and the alert detail chart had no PromQL
branch, so it charted row counts against the series-count gate.
- Lands together with the matching o2-enterprise PR — `QueryType::Slo`
is new here and the enterprise dedup matches are exhaustive over it.
- `ratelimit::test_add_batch_missing_rule_id` fails intermittently on
`main` as well; unrelated to this branch.

---------

Co-authored-by: Shrinath Rao <shnath@openobserve.ai>
Co-authored-by: hengfeiyang <hengfei.yang@gmail.com>
Co-authored-by: sai nikhil kethe <nikhil@openobserve.ai>
2026-07-31 07:23:22 +00:00
6fb5eecdc5 fix: table migration to same components (#13451)
## What changed

Every table in the app now renders through the shared `OTable`
(`web/src/lib/core/Table`). Both legacy implementations are deleted —
`components/TenstackTable.vue` and `plugins/logs/TenstackTable.vue` —
for ~7,000 lines removed and one table behaviour contract instead of
three.

To get there, `OTable` gained: per-cell hover actions, per-column value
filter, opt-in column close "x", sticky pivot total row + right-pinned
total columns, pivot row-field cell merge, caller-owned pagination bar,
delegated scroll (shared scroller with the logs/traces histogram), and
variable-height virtual rows.

## Tables migrated

| Area | Tables |
| --- | --- |
| Logs | Search results grid, correlated logs |
| Traces | Search results grid, trace details sidebar (attributes /
events / links), service graph node panel |
| Dashboards | Table panel + pivot (incl. PromQL), panel pagination
controls, import error panel |
| RUM | Session player traces tab |
| Pipelines | Scheduled pipeline SQL preview |

## Tested

775 unit tests across the 12 affected suites, all passing.

Manually verified per table:

- **Columns** — resize, reorder, close "x", persistence across reload;
horizontal scroll on wide grids; wrap toggle with virtual scroll; client
+ 3-state server sort
- **Pagination** — custom records-per-page, enabling pagination after
mount, scroll-to-top on page change, no duplicate pager
- **Logs** — FTS highlighting, row expand → JSON preview and its
actions, hover actions + AI button, cell font / row density / status
spine, histogram pinned while scrolling sideways
- **Dashboards** — pivot multi-level headers, cell merge, sticky totals
staying aligned under horizontal scroll, cell colouring (auto palette /
value mapping / conditional rules / overrides), CSV + JSON export
- **Traces, RUM, Pipelines** — events table expansion, error-row border,
row click → trace navigation, SQL preview copy + send-to-AI

---------

Co-authored-by: ktx-vaidehi <134508096+ktx-vaidehi@users.noreply.github.com>
Co-authored-by: ktx-vaidehi <vaidehi.akhani@kiara.tech>
Co-authored-by: Shrinath Rao <shnath@openobserve.ai>
2026-07-30 12:18:23 +00:00
ktx-vaidehi c9fc8d3b55 fix: dashboard builder redesign (#13419) 2026-07-28 10:59:27 +00:00
7d212f4621 feat: workflows incident connection (#13472)
This connects incidents to workflows, so any lifecycle event of incident
will trigger workflow.

design at:
https://github.com/openobserve/designs/blob/main/infrastructure/workflows/design.md

---------

Signed-off-by: Yashodhan Joshi <yjdoc2@gmail.com>
Co-authored-by: Yashodhan Joshi <yjdoc2@gmail.com>
Co-authored-by: sai nikhil kethe <nikhil@openobserve.ai>
Co-authored-by: Shrinath Rao <shnath@openobserve.ai>
2026-07-28 10:04:35 +00:00
ktx-akshay 6e0a7374e5 test: add DashboardFavorites page object and associated tests for fav… (#13362)
## Summary

Adds a Playwright E2E test suite covering the dashboard Favorites
feature — favoriting/unfavoriting a dashboard, the `Favorites`
pseudo-folder view, and its interaction with single and bulk delete
flows.

## What's covered

New `dashboard-favorites.spec.js` (6 tests) + `DashboardFavorites` page
object:

- Add a dashboard to favorites and verify it appears in the Favorites
view
- Remove a dashboard from favorites — confirms it drops from the
Favorites view while the dashboard itself remains untouched
- Favorite state persists across a page reload
- Bulk-delete a favorited dashboard from the Favorites view completes
successfully with no error
- Deleting a dashboard directly also removes it from Favorites
automatically
- Bulk-deleting a dashboard from the Favorites view doesn't leave a
stale copy behind in its original folder

## CI

`dashboard-favorites.spec.js` runs in its own dedicated
`Dashboards-Isolated` shard with a fresh backend instance, keeping it
independent from the rest of the dashboard test suite.
2026-07-28 07:26:47 +00:00
Shrinath Rao 7ade62610a test: heal logs scroll-retention selector after histogram-pinning change (#13460)
## Problem

The scheduled Playwright Regression runs failed on `Logs-Regression` in
**both repos** on the same 3 tests in `logs-9044-7354.spec.js` (issue
9044 scroll-retention):

- OSS run
[30150748275](https://github.com/openobserve/openobserve/actions/runs/30150748275)
- ENT run
[30150717648](https://github.com/openobserve/o2-enterprise/actions/runs/30150717648)

All three failed identically — `expect(scroll).toBeGreaterThan(10)`
received `0`, i.e. scrolling the results container no longer moved it.

## Root cause

`web/src/plugins/logs/SearchResult.vue` now **pins the histogram** and
hands the scrollbar to the results table (`TenstackTable` →
`[data-test="logs-search-result-logs-table"]`). Its scroll parent is the
`ref="parentRef"` div (`.o2-scroll-container`, `overflow: auto`). The
outer `scrollContainerRef` pane is now `overflow: hidden` in the logs
view.

The page-object helpers `getScrollContainerPosition()` /
`scrollToResultsBottom()` walked *down* from the pagination header
looking for a scrollable sibling, which latched onto a non-overflowing
element — so `scrollTop` stayed `0`. (This is the same area healed once
before in #13316; the histogram-pinning change moved the scroller
again.)

## Fix

Discover the scroll container from the results table itself: walk **up**
from `[data-test="logs-search-result-logs-table"]` to the nearest
ancestor with a scrollable computed `overflow-y` (the
`.o2-scroll-container`). Matched by computed style so class renames
don't break it. The old pagination sibling-walk is kept as a fallback
for the patterns view (which still scrolls as one pane).

Only the shared OSS page object `logsPage.js` changes, so this heals
both OSS and ENT (ENT merges the OSS test folder).

## Verification

Ran against a fresh local build (localhost:5080):

```
3 passed (46.8s)
Scrolled to: 358   →   Scroll correctly reset to top on page change
```

Confirmed via a DOM probe that `.o2-scroll-container` is the real
scroller (scrollHeight 1112 > clientHeight 754; scrollTop → 358 after
scrolling to bottom).
2026-07-25 13:29:48 +00:00
Shrinath RaoandClaude Opus 4.8 c6b2829a5e test(autoe2e): generated E2E tests for #13025 (logs-stream-quick-pick) (#13030)
🤖 Auto-generated E2E tests for #13025 — **healed to passing** against a
live OpenObserve before this PR was opened.

- Branch `autoe2e/pr-13025` (stacked on `issue-ent-2038`), so the tests
run against the feature code and pass before it merges.
- Spec: `tests/ui-testing/playwright-tests/Logs/logsQuickPick.spec.js`

The repo Playwright CI re-validates here. Review is for **quality +
coverage** — the tests already pass.

_Generated by the E2E Council pipeline._


**Test cases added / changed:**

| Test case | Type | What it verifies |
|---|---|---|
| `should quick pick a stream from the sidebar` | new | clicking a
sidebar quick pick button selects the stream and loads the field list |
| `should show hero state on fresh arrival with no stream selected` |
new | the main content area shows both hero action cards when no stream
is selected |
| `should open stream dropdown when clicking select stream card` | new |
clicking the "Select a stream" hero card opens the stream dropdown
popover |
| `should reappear quick pick after deselecting and re-select works` |
new | after deselecting a stream the quick pick reappears and
re-selection works correctly |
| `should show more footer when org has more than 8 streams` | new | the
quick pick more footer is visible with the correct remaining count when
org has > 8 streams (skips otherwise) |
| `should select stream via hero recent chip` | new | clicking a
recent-stream chip in the hero state selects the stream and triggers
field list loading |
| `should open query guide documentation in new tab` | new | clicking
the "Read the query guide" card opens the OpenObserve docs in a new
browser tab |

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:40:14 +00:00
Shrinath RaoandClaude Opus 4.8 9842922521 test(pipelines): fix addPipeline mount-wait flake (isVisible timeout is a no-op) (#13420)
## What flaked

`Pipelines-Regression` → *"should validate scheduled pipeline SQL query
with metrics stream type"* (`pipeline-regression.spec.js:73`) timed out
in the ENT gate waiting for the editor mount signal
`[data-test="pipeline-node-sidebar-collapse-btn"]` (15s, all retries).

It's a **load-timing flake, not a real break**: OSS CI ([run
30005672782](https://github.com/openobserve/openobserve/actions/runs/30005672782))
and the ENT `main` baseline ([run
30005554375](https://github.com/openobserve/o2-enterprise/actions/runs/30005554375))
both pass this same test.

## Root cause

`addPipeline()` meant to poll for the mount signal across 3 attempts of
15s (re-clicking the add button non-destructively if the click was
dropped before navigation):
```js
for (let attempt = 1; attempt <= 3; attempt++) {
    if (await railToggle.isVisible({ timeout: 15000 }).catch(() => false)) break;
    ...
}
await railToggle.waitFor({ state: 'visible', timeout: 15000 });
```
But **`locator.isVisible({ timeout })` does not wait** — it returns the
current state immediately and ignores `timeout` (Playwright 1.50). So
the loop spun through instantly and the editor effectively got only the
**final 15s** `waitFor` to mount. Under concurrent cloud load VueFlow's
mount lags past 15s → timeout.

## Fix (page-object only)

Make each poll attempt actually block using `waitFor({ state: 'visible'
})` inside the loop (try/catch, re-click on the list page between
attempts), restoring the intended **~45s** of resilience before the
final assert.

## Verification

Local verification is currently blocked by a stale local build (the
selector was added in #13397 and isn't in the local `web/dist`), so this
is gated on a fresh CI regression run against the branch. The change
only lengthens the effective mount wait; it can't regress the happy path
(which already passes on fresh builds).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:50:21 +00:00
Shrinath RaoandClaude Opus 4.8 0e477f9918 test(workflows): de-flake K9 canary — log Save-intercept, don't hard-assert it (#13418)
## How this was found

The **Playwright E2E Crosscheck** bot (the ENT gate that runs
enterprise-only specs against OSS PRs) flagged a failing spec on an
unrelated logs PR ([#13414
comment](https://github.com/openobserve/openobserve/pull/13414#issuecomment-5058151842)):

> `Workflows/workflows-negative.spec.js` — *"enterprise-only e2e spec
failed against this PR … wouldn't show up in OSS CI."*

Digging showed it wasn't caused by that PR — the same test was **also
failing on #13413 and #13315**. It's a pre-existing **flake** in the ENT
gate, so this PR fixes it at the source.

## Evidence it's a flake, not a real break

The **same branch** produced both outcomes:

| ENT crosscheck run | PR | K9 test |
|---|---|---|
| 30005431754 | #13414 | ✅ passed (~50s, slow path) |
| 30008606974 | #13414 | ❌ failed |
| 30006996158 | #13315 | ❌ failed |
| 30006419247 | #13413 | ❌ failed |

## Root cause

`CT-19 K9` hard-asserted that a normal `.click()` on Save is intercepted
by a tooltip overlay:
```js
expect(await pm.workflowsPage.normalSaveClickIsIntercepted(4000)).toBe(true);
```
But the Save button has **no tooltip of its own** (`WorkflowEditor.vue`)
— the overlay that intercepts it is a **transient/adjacent tooltip**
that often never appears on a programmatic hover in headless CI. The
probe therefore conflates *"blocked by overlay"* with *"click landed"*,
and the assertion flips run to run. (A first attempt — waiting for the
overlay before probing — didn't help: the overlay simply isn't reliably
summoned.)

## Fix (test-only, no product/Vue changes)

- Treat interception as an **informational canary** —
`testLogger.info(...)` instead of a hard assert.
- Keep the **stable** assertion: the JS-click Save workaround still
reaches the app (`msg.length > 0`) — the adjacent trigger-only-save test
already exercises that same path and passes consistently.
- If K9 is ever genuinely fixed, the canary log shows
`intercepted:false` consistently — the signal to drop the JS-click
workaround.

This removes the flaky gate without losing meaningful coverage. Changes
are limited to the spec and its page object.

## Verification

`Workflows/*` are enterprise-only (skipped on OSS CI), so verified via
the **ENT gate against this OSS branch** (`e2e` label). The removed
assertion was the only flaky part; the retained assertion matches an
already-stable adjacent test.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:42:18 +00:00
Shrinath RaoandClaude Opus 4.8 1daa36b0f8 fix(logs): preserve restored SQL query on shared-link open + align log-detail default-tab test (13368) (#13414)
> **This PR contains two independent logs changes:**
> **(A)** a product fix for the shared-link SQL-query restore race, and
> **(B)** the log-detail default-tab test alignment (original scope of
this PR).

---

# (A) fix(logs): preserve restored SQL query on shared-link open
(fullSQLMode watcher race)

## The bug
Opening a **shared link** to an SQL search **sometimes lands on an empty
query editor** ("SQL query is missing or invalid") instead of the shared
search. Intermittent, worse under load — it's the recurring
Logs-Features alpha flake (`monaco-query-prefill` P0 "query editor never
contained SELECT").

**Not the short-URL mechanism** — the short URL correctly carries
`sql_mode=true` + the base64 query. The loss happens in the browser
during restore.

## Root cause — a watcher race
`restoreUrlQueryParams()` raises `shouldIgnoreWatcher`, flips
`meta.sqlMode = true`, then writes the decoded query into the editor.
Flipping `sqlMode` fires the **`fullSQLMode`** watcher in `Index.vue`,
whose two branches were **asymmetric**:

- **switch OFF** branch → already checks `shouldIgnoreWatcher` ✅
- **switch ON** branch → **did not** ❌ — it called `setQuery()`,
rebuilding a *default* `SELECT … FROM stream` over the value the restore
was mid-writing.

Under load the watcher wins the race; the editor briefly empties, SQL
mode auto-detects back **off**, and the editor is cleared entirely.

## The fix
Make the "switch ON" branch honour `shouldIgnoreWatcher` too — symmetric
with "switch OFF". During any programmatic restore the watcher **stands
down** and the restored query is the last word. (`shouldIgnoreWatcher`
is raised only by programmatic-state paths whose purpose is to suppress
watcher side-effects, so honouring it here is consistent.)

## Verification (A)
- ✅ **New unit test**: with `shouldIgnoreWatcher` set, flipping
`sqlMode` ON does **not** call `setQuery`/`updateUrlQueryParams`, and
the restored `SELECT` query is preserved.
- ✅ Existing `fullSQLMode` watcher test still passes; full
`Index.spec.ts` green (**69 passed**).
- ✅ Reproduced the failure on **alpha under CI-load** beforehand
(share-link P0 flaky, "query editor never contained SELECT").
- ⚠️ The race is only observable against a **deployed** frontend (the
alpha e2e suite runs against alpha's frontend, not a local build), so
the final "flake gone on alpha under load" check requires this deployed
to alpha, then re-running the Logs-Features share-link tests.

Files: `web/src/plugins/logs/Index.vue`,
`web/src/plugins/logs/Index.spec.ts`.

---

# (B) test(logs): align log-detail default-tab test with Table default
(13368)

## What
Updates the log-detail sidebar default-tab regression test (originally
Bug #9724) to match the **intentionally shipped** behavior from [PR
#13368](https://github.com/openobserve/openobserve/pull/13368) — *"logs
sidebar table will be default view and draggable tabs"*.

## Why
#13368 changed the log-detail sidebar default from the **JSON** tab to
the **Table** tab (`SearchResult.vue` — `detailTableInitialTab.value =
"table"`). The Bug #9724 test still asserted JSON-as-default, so it
fails on `main`: the JSON tab's `data-state` stays `inactive` for the
full timeout across all retries, on both OSS and ENT Logs-Regression.
Not a flake and not a product bug — the test expectation was simply out
of date after a deliberate default-view change.

## Changes
- Rename test → **"Log detail sidebar opens with Table tab by default
(#13368)"**.
- Add `verifyTableTabSelectedByDefault()` page-object helper
(auto-retrying `toHaveAttribute('data-state','active')`); remove the
now-invalid `verifyJsonTabSelectedByDefault()`.
- Reorder switch steps: assert Table default (+ wrap toggle, which
renders only on the Table tab), switch to JSON and back to Table, reopen
and confirm Table default persists.

## Note on #13407
Supersedes the earlier heal
[#13407](https://github.com/openobserve/openobserve/pull/13407), which
misdiagnosed the failure as a `data-state` timing flake. A
locally-hosted stale pre-#13368 build had masked the change.

Files: `tests/ui-testing/pages/logsPages/logsPage.js`,
`tests/ui-testing/playwright-tests/RegressionSet/Logs/logs-regression.spec.js`.

```
npx playwright test playwright-tests/RegressionSet/Logs/logs-regression.spec.js \
  -g "Table tab by default" --project=chromium
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:35:24 +00:00
Sai Nikhil 2cec0a0c94 fix: pipeline and workflows UI change (#13397) 2026-07-23 11:28:13 +00:00
ktx-vaidehiandClaude Opus 4.8 8886a03b99 feat(dashboards): redesign panel config sections (#13371)
- Collapse all config sections by default (was expanded)
- Add open-state accent to OCollapsible sidebar variant: left accent
bar, tinted header, and accent-colored icon/chevron when expanded
- Move sidebar chevron to the right of the label (rotates on open)
- Give every config section a leading icon via SECTION_ICONS
- Add theme-aware collapsible open-state tokens (light + dark)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:14:16 +00:00
Shrinath RaoandClaude Opus 4.8 8da11deec7 test(logs): heal Bug 9724 JSON-tab-default flake with retrying data-state assertion (#13407)
## What

Heals the flaky **Logs-Regression** spec `Log detail sidebar opens with
JSON tab by default (Bug #9724)`, which failed the scheduled main
regression run
[29990712453](https://github.com/openobserve/openobserve/actions/runs/29990712453)
(and its re-run) on all retries.

## Root cause

`logsPage.verifyJsonTabSelectedByDefault()` read the Reka `OTab`
(`TabsTrigger`) `data-state` attribute with a **one-shot** `.evaluate(el
=> el.getAttribute('data-state') === 'active')`. `DetailTable.vue` is
loaded via `defineAsyncComponent`, and its tabs moved to Reka UI in the
design-token migration (13173). On drawer open, the trigger can render a
tick before Reka's reactive `data-state` settles to `active`. A raw
`getAttribute` read does **not** auto-retry, so under CI load it
captured the pre-settle value and failed.

JSON **is** the genuine product default (`DetailTable.vue` `tab =
ref(initialTab || "json")`, `SearchResult.vue` `detailTableInitialTab =
"json"`) — this is a load flake, not a product regression.

## Fix

Replace the one-shot reads with the auto-retrying
`expect(tab).toHaveAttribute('data-state', 'active', { timeout: 10000
})` pattern already used elsewhere in the same page object
(regex-pattern / builder-type toggles), across all three tab-verify
helpers:

- `verifyJsonTabSelectedByDefault()`
- `verifyTableTabSelected()`
- `verifyJsonTabSelected()`

Test-only change; no product code touched.

## Verification

Local run against `localhost:5080`:

```
npx playwright test playwright-tests/RegressionSet/Logs/logs-regression.spec.js \
  -g "Bug #9724" --project=chromium --repeat-each=3
# 3 passed (16.9s)
```

The single spec exercises all three healed helpers (default-JSON at
steps 3 + reopen, Table tab at step 6, JSON switch-back at step 7).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 10:34:55 +00:00
BhargavandClaude Opus 4.8 ef2efdf5fc fix: logs sidebar table will be default view and draggable tabs (#13368)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 06:53:13 +00:00
4f458a0fab test(sdr): add traces SDR e2e suite (redact/drop/hash × ingestion/query) (#13390)
## What

Adds an end-to-end **traces SDR (Sensitive Data Redaction)** test suite,
extending SDR coverage from logs to traces. This validates the fix in
this PR branch (`feat/fix-traces-sdr-bug`) — SDR regex patterns were
previously applied to logs only; these tests assert the same policies
now apply to **trace span attributes** at both ingestion and query time.

Targets `feat/fix-traces-sdr-bug` so the tests land together with the
fix they cover.

## Tests added

**6 new spec files → 12 tests** (each spec = 1 `setup: cleanup patterns`
+ 1 combined functional test), covering **24 field-level policy
assertions** (4 sensitive fields × 6 specs). All tagged `@enterprise
@sdr @traces`.

| # | Spec | Policy | Timing | What it asserts |
|---|------|--------|--------|-----------------|
| 1 | `tracesIngestionTimeRedaction.spec.js` | Redact | Ingestion |
Span-attribute values matching the pattern are stored as `[REDACTED]` |
| 2 | `tracesQueryTimeRedaction.spec.js` | Redact | Query | Stored
values are untouched; the search response returns `[REDACTED]` |
| 3 | `tracesIngestionTimeDrop.spec.js` | Drop | Ingestion | Matching
fields are removed from the record at write time |
| 4 | `tracesQueryTimeDrop.spec.js` | Drop | Query | Fields present in
storage are dropped from the search response |
| 5 | `tracesIngestionTimeHash.spec.js` | Hash | Ingestion | Matching
values are stored as `[REDACTED:<hash>]` |
| 6 | `tracesQueryTimeHash.spec.js` | Hash | Query | Search response
returns `[REDACTED:<hash>]`; storage untouched |

Each combined test drives the full flow for **4 fields / patterns**:

- **email** (`user_email` = `john.doe@example.com`) —
`^[\w\.-]+@[\w\.-]+\.\w{2,}$`
- **US phone** (`phone` = `5551234567`) — `^\d{10}$`
- **credit card** (`cc_number` = `1234 5678 9012 3456`) —
`^\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}$`
- **SSN** (`ssn` = `123-45-6789`) — `^\d{3}-\d{2}-\d{4}$`

(drop/hash specs use `website_url`, `user_password`, `server_ip`,
`theme_color` with URL / password / IPv4 / hex-color patterns.)

Each functional test follows: ingest → assert field visible (no pattern)
→ create 4 patterns → associate to the traces stream's fields →
ingest/re-query → assert the field is redacted / dropped / hashed.

## How it works

Traces reuse the **shared** pattern create/associate/verify flow with
logs — only the ingest and read seams differ:

- **`sdrTracesIngestionPage.js`** (new): ingests via OTLP
`/api/{org}/v1/traces` (`stream-name` header). Each test field is a span
attribute that flattens to an identical top-level field; every span also
carries an `sdr_test_id` marker for batch isolation.
- **`sdrVerificationPage` / `streamAssociationPage`**: parameterized by
`streamType` — `?type=traces` search, Traces stream-type tab selection,
and schema-field filtering so a field row in the (virtualized,
~20-field) traces schema is reliably found.
- **`apiCleanup`**: `fetchStreams` / `deleteStream` / `cleanupStreams` /
`isStreamStillDeleting` / `waitForStreamDeletion` take an optional
`streamType` (default `'logs'` — no change for existing callers).

## Artifact cleanup

- `cleanup.spec.js` sweeps `sdr_traces_*` streams via `streamType:
'traces'` (the logs sweep is `type=logs`-only and never listed them).
- `cleanupRegexPatterns` adds the `traces_` prefix.
- **Verified live**: the sweep deleted 8 leftover traces streams + 32
traces patterns; 0 remained.

## Verification

- All **6 specs / 12 tests pass** against a local enterprise build
carrying the fix.
- The existing **logs** SDR suite still passes unchanged (no regression
from the shared page-object changes).

## Companion

CI wiring is a paired o2-enterprise PR (branch `test/traces-sdr-e2e`)
that splits the SDR matrix into `SDR-Logs` and `SDR-Traces` shards so
the new specs run as their own shard.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Chaitanya Sistla <sistlachaitanya2@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 06:46:10 +00:00
Shrinath RaoandClaude Opus 4.8 68946ed063 test: harden org-selector switch flows against virtualized dropdown (changeOrg + logoManagement) (#13391)
## What

Heals the two `GeneralTests` specs that flake on the redesigned
**`OrganizationSelector.vue`** (reka-ui `ODropdown` +
`@tanstack/vue-virtual` virtualized list, from the design-token
migration): `changeOrg.spec.js` and `logoManagement.spec.js`. Test-only
— no product/frontend change.

## Why it flakes (CI parallel load only — passes single-worker locally)

- **changeOrg** — virtual rows carry a `transform: translateY(...)` that
keeps shifting while the popper animates in and the list settles, so
Playwright's actionability *stability* check burns the click budget and
times out. A force-click on a still-moving row can also land on a
**neighbouring row** (often `default`) — the menu still closes, so the
wrong org is selected and the swallowed `waitForURL(...).catch(()=>{})`
hid it until a later assertion failed.
- **logoManagement** — `managementOrg` had no "menu opened" gate; a
blind `waitForTimeout` raced ahead of the popper open, so
`organization-search-input-field` never rendered and `fill()` timed out
(45s).

This is **not a regression from any single PR** — it reproduces on every
branch's ENT `GeneralTests` run (the org-selector redesign was never
hardened for the virtualized dropdown).

## Fix

- `homePage.js` `clickOrgRow`: `scrollIntoViewIfNeeded` + `force` click
+ gate on the menu **hiding**, so a missed click retries instead of
leaving an un-selected menu.
- `homePage.js` `selectOrgByIdentifier` (new): retry open → search →
click until the **URL** carries the target identifier — the only
authoritative signal that the right row was selected. `homePageOrg`'s
identifier branch uses it.
- `logoManagementPage.js` `managementOrg`: retry the open until the menu
list is visible, fill the `-field` input with `force`, hardened row
click with the same menu-hidden verification. Added
`organizationMenuList` locator.

## Verification (local enterprise build v0.92.0-rc1)

| Test set | Workers | Result |
|----------|---------|--------|
| changeOrg "change organisation validation" (14) ×3 | 4 | 14/14 pass
each (was 1-failed pre-fix) |
| changeOrg full spec | 4 | 28 pass, 0 fail (no regressions) |
| logoManagement ×2 | 1 | pass |

## Enterprise coverage

Carries the `e2e` label so the **ENT e2e gate** dispatches the
enterprise suite against this branch (built against ENT main) and
mirrors the result here — validating the `@enterprise` logoManagement
spec and ENT GeneralTests without a separate ENT PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 05:05:21 +00:00
Harsh Mahajan 9c66eda99f fix: frontend fix. found by playwright tests (#13389)
https://github.com/openobserve/o2-enterprise/actions/runs/29932597095/job/89019125595?pr=2227
2026-07-22 23:16:16 +00:00
Bhargav e0fe62a9a0 fix: traces page default flame graph and drag-drop option added (#13347) 2026-07-22 11:37:24 +00:00
Prabhat Sharma 21d0907342 fix(logs): redesign log patterns UI (#13337)
## What

Redesign of the log patterns UI.

- **`PatternCard`** reworked: template tokens, a badges row (trend /
rarity / anomaly), and inline frequency + percentage replace the old
fixed count and action columns.
- **`PatternVolumeCell`** (new) + **`usePatternVolume`** (new) render
per-pattern volume sparklines.
- **`PatternDetailsDialog`** now owns the include / exclude /
create-alert actions that previously lived on each card.
- **`patternUtils`** / **`usePatternActions`** extended to back the
above.

## Test plan

- `web` unit tests for the touched areas: 356 passing, 0 failing
(`plugins/logs/patterns`, `plugins/logs/data-table`, `SearchResult`,
`FieldValuesPanel`).
- New spec coverage for `PatternVolumeCell`, `usePatternVolume`, and
`patternUtils`.
- `npm run type-check` clean.
- `lint:design`, `lint:tokens`, `lint:token-purity` all clean.

## Notes

Rebased onto latest `main`. Five conflicts came from main's repo-wide
type-check pass (#13174), which made `OIcon`'s `name` prop required.
Main's fix (`name=""` + slot) was kept in `CodeQueryEditor.vue`,
`FieldValuesPanel.vue`, and `CellActions.vue`; in `PatternCard.vue` the
surrounding block was removed by this redesign, so the deletion stands.
2026-07-21 15:46:12 +00:00
Vamsi Karthik RandClaude Opus 4.8 899bb681a8 test(e2e): optimize/fix alpha1 Alerts, SDR & Pipelines shards (operator select scoping + editor/nav/data-flow races + ingestion 5xx resilience) (#13336)
## What

Consolidated stabilization of the **Alerts**, **SDR** and **Pipelines**
shards of the
alpha1 cloud E2E suite (`playwright_alpha1.yml`) to green — the shards
still failing
after the earlier per-module stabilization PRs merged. Rebased on
`main`.

Across these shards the original run had: **Alerts** 1 hard fail,
**SDR** 1 hard fail +
1 flake, **Pipelines** 1 hard fail + several flakes. Root causes were an
ambiguous
operator-select selector plus cloud data/UI-readiness races (editor &
node-sidebar mount,
hover-flyout nav, freshly-ingested destination streams lagging their
list/table) and
transient backend 5xx on ingestion.

**No `waitForTimeout` added as a fix, no `force:true`, no
`.first()`/`.nth()` band-aids,
no retry-count bumps to hide failures, no weakened assertions. No
worker-count,
parallelism, playwright-config or CI/yml changes** — test code only.

## Root cause & fixes

**Alerts**

1. **Operator select — strict-mode violation** (`alerts-e2e-flow`, state
management).
   The operator control is an OSelect that renders an aria-hidden native
`<select><option>=</option>` alongside the visible popover item, so the
unscoped
`getByText('=', {exact})` matched **two** nodes. Scope the option click
to
`[data-test="alert-conditions-operator-select-popover"]` +
`getByRole('option')`
(excludes the aria-hidden native select, mirrors the working
`alertCreationWizard.js`
pattern), and gate on the popover open/close instead of the trailing
`waitForTimeout`s.
   (`alertManagement.js`)

**SDR**

2. **Stream Detail button — 45s timeout under load**
(`multipleSDRPatterns` @slow,
`ingestionTimeHash`). `openStreamDetail` resolved the button by the
icon's title text,
which the OTable can render after the name cell, and the retry only
re-clicked a
possibly-detached row without re-fetching the list. Resolve by the
stable
`data-test="log-stream-schema-btn"` and reload + re-search the streams
list between
   attempts, keyed to the real "detail sidebar open" signal
   (`schema-update-settings-button`). (`streamAssociationPage.js`)

**Pipelines**

3. **Editor / node-sidebar mount race** (`selectStream`, all pipeline
flows). A bare click
on the stream-input button dead-waited the 45s action timeout when the
VueFlow editor +
NodeSidebar missed the first render under concurrent load. Moved a
**non-destructive**
mount guard into `addPipeline`: after clicking Add, if the button hasn't
rendered and
we're still on the list (add button visible), re-click to re-trigger
navigation — no
`page.reload()` (a reload of the editor route re-runs the auth callback
on cloud and
   stalls the shard). (`pipelinesPage.js`)

4. **`openPipelineMenu` — hover-flyout nav timeout.** Routed through the
left-nav hover
flyout, which self-closes on settle and, under load, burned ~30s
retrying to open before
its goto fallback fired — tipping long condition tests over the 180s
test timeout.
Promoted the already-proven `goto` to the primary path and skipped the
flyout (it adds
   no coverage here). (`pipelinesPage.js`)

5. **Destination-stream data-flow / render latency**
(`pipeline-dynamic`, query-source
flow). Extended `openTimestampMenu`'s re-search loop (destination stream
indexing can
lag past the old budget) and `waitForQueryNodeVisible` 30s→45s
(query-node canvas render
lags under full-shard load) — both within the CI test timeout, both exit
early on the
   real signal. (`pipelinesPage.js`)

**Ingestion resilience (Pipelines + shared helper)**

6. **Transient backend 5xx aborted ingestion.** `fetchWithRetry` only
retried thrown
network errors; a `503`/`502` is a "successful" fetch, so ingestion
threw on the first
one when the env returned transient 5xx during load spikes. Retry 5xx
with backoff in
both ingestion helpers — a persistent 5xx still surfaces after
`maxRetries`, so genuine
   outages aren't masked. (`pipelinesPage.js`, `ingestionPage.js`)

## Validation

- **CI — Alerts / SDR / Pipelines green (alpha cloud):**
[Pipeline](https://github.com/openobserve/o2-enterprise/actions/runs/29809833252).

[SDR,
Alerts](https://github.com/openobserve/o2-enterprise/actions/runs/29771293789)
- **Original failing run:**
https://github.com/openobserve/o2-enterprise/actions/runs/29720987587
- **Local (real alpha cloud, `playwright-alpha1.config.js`):** each
previously-failing test
re-run to green — `pipeline-conditions.spec.js` @ `--workers=3` 6/6,
`pipeline-dynamic`
72 & 97, `pipelines:180` (query source) solo; Alerts operator flow and
SDR
`openStreamDetail` verified against alpha. 5xx-retry control flow
verified (2xx/4xx
  unchanged, transient 503 recovers, persistent 503 still surfaces).

## Notes

- 4 files change (3 page objects + the shared ingestion helper). No
specs, shared
  cleanup/setup, config, or workflow files touched.
- Any residual Pipelines tail is cloud latency / env backend health
(e.g. runs where the
env returns sustained 503s) — not test code; the durable lever there is
cross-shard
  concurrency / env capacity, out of scope for this PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 15:16:03 +00:00
Shrinath RaoandClaude Opus 4.8 b1604cc7b6 test(workflows): e2e + API tests for Workflows (#13318)
Adds automated test coverage for the Enterprise-only **Workflows**
feature (now merged to main). Clean branch off `main` — test files only,
no feature-code churn.

**UI (Playwright · `tests/ui-testing`)**
- `pages/workflowsPages/workflowsPage.js` — page object (verified
`data-test` selectors, Save-tooltip JS-click workaround, slow-list
waits, enterprise-availability probe).
- `playwright-tests/Workflows/workflows-crud.spec.js` — build/name
validation, list + search.
- `playwright-tests/Workflows/workflows-negative.spec.js` — negative +
NFR sweep (long/unicode/emoji names, list latency, console/network
hygiene).
- `pages/page-manager.js`, `pages/apiCleanup.js` (`cleanupWorkflows()` +
cascade), `playwright-tests/cleanup.spec.js` (`wf_auto_*` prefixes).
- `.github/workflows/playwright.yml` — `Workflows` testfolder in the
matrix.

**API (pytest · `tests/api-testing`)**
- `tests/workflows/test_workflows.py` — full REST surface
(create/list/update/enable/test/history/errors/retry/delete) +
validation, auth (401), cross-org.

**Behaviour**: Enterprise-gated (skips on OSS where the feature is off);
self-cleaning (`wf_auto_*`). Verified live: **11 Playwright + 13 pytest
passing**. Paired with the ENT matrix PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 12:26:52 +00:00
ktx-vaidehi 784459fcf4 fix: login form migration (#13334) 2026-07-21 10:51:09 +00:00
Shrinath RaoandClaude Fable 5 79c524c7f9 test: heal dark-mode detection and logs scroll-container selectors after design-token migration (#13316)
## Why

The 2026-07-21 scheduled Playwright Regression runs failed on **both**
OSS ([run
29801668855](https://github.com/openobserve/openobserve/actions/runs/29801668855))
and ENT ([run
29801639539](https://github.com/openobserve/o2-enterprise/actions/runs/29801639539))
— same 4 tests, same shards (Traces-Regression, Logs-Regression).

Root cause: the design-token migration (#13173, `f15e27e5fd`, merged
2026-07-20 evening — the only code change between the last green
scheduled run and the failing one) removed Quasar entirely, breaking two
page-object seams:

| Failing test | Broken seam |
|---|---|
| `traces-bugs.spec.js` › trace values should be visible on hover in
dark mode (@bug-4151) | `homePage.isDarkMode()` read the retired Quasar
`body--dark` class on `<body>`. Dark mode is now the `.dark` class on
`<html>` (set by `utils/theme.ts`). `themePage.js` was already migrated
inside #13173 — `homePage.js` was missed. |
| `logs-9044-7354.spec.js` › all 3 scroll-retention tests (#9044) |
`getScrollContainerPosition()` / `scrollToResultsBottom()` navigated
`pagination → .search-list → [class*="overflow-y-auto"]` — both hooks
are gone. The results scroller is now the combined scroll area
(`ref="scrollContainerRef"` in `logs/SearchResult.vue`). Helpers
returned the `-1` "not found" sentinel, so
`expect(scroll).toBeGreaterThan(10)` failed. |

## What

Test-side only (no `web/` changes):
- `homePage.isDarkMode()` → checks
`document.documentElement.classList.contains('dark')`.
- Logs scroll helpers → walk up from the `logs-search-result-pagination`
anchor and pick the sibling child whose **computed** `overflow-y` is
`auto`/`scroll`, so future utility-class renames don't break it again.

Pagination helpers (`-page-N`, `-next`, `aria-current="page"`) already
matched the new OPagination markup and needed no change.

## ENT

ENT overrides none of these files — its regression workflow checks out
OSS tests (`cp -r o2-enterprise/tests/* openobserve/tests/` overlays
only ENT-owned files). The ENT scheduled run heals automatically once
this merges; verified pre-merge by dispatching ENT
`playwright_regression.yml` with `oss_branch:
test/heal-dark-mode-scroll-selectors`.

## Verification

All 4 previously-failing tests pass locally against a post-migration
build (`main` @ `c523d0034c`, enterprise features):
- `logs-9044-7354.spec.js` — 3 passed (49s)
- `traces-bugs.spec.js -g "trace values should be visible on hover in
dark mode"` — 1 passed (18s)

OSS + ENT regression runs seeded against this branch (links in
comments).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 07:07:47 +00:00
fd85566742 feat: workflows version 1 (#13156)
This PR introduces workflows 

design at:
https://github.com/openobserve/designs/blob/main/infrastructure/workflows/design.md

---------

Signed-off-by: Yashodhan Joshi <yjdoc2@gmail.com>
Co-authored-by: Yashodhan Joshi <yjdoc2@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 05:33:46 +00:00
f15e27e5fd refactor: design token migration + CI guards (#13173)
# Design System Unification — one visual language, enforced end-to-end

Establishes **one source of truth for every visual decision**, wires the
whole app to it, and **locks it in with CI** so it can't drift back.

### Foundations
- **Design-token system ("one knob per decision").** Every colour, text
size, spacing, corner radius, and shadow is a named token defined in
exactly one place — change the token, every screen updates. Collapsed
hundreds of near-duplicate definitions and removed "fake" duplicates
that pretended to be different but weren't.
- **Shared component library (O2).** Buttons, tables, dialogs, drawers,
form fields, badges, etc. already know the correct colours, spacing, and
dark-mode behaviour; new screens compose them instead of hand-styling.
Added new primitives on this branch (`OContent`, `KpiCard`) and
standardized existing ones.
- **One page structure everywhere** (`PageLayout` / `AppPageHeader` /
`AppPage` / `OContent`) — titles, breadcrumbs, spacing, and content
edges line up identically across every screen.
- **One table implementation** — all tabular data uses the same table
(sorting, density, sticky headers, empty states).
- **Styling consolidated onto Tailwind; old systems removed** —
hand-written CSS driven to the practical minimum, the legacy **Quasar**
framework fully removed, surviving stylesheets required to justify
themselves.
- **Two-tier corner radius** — a tight **4px** for controls and a soft
**12px** for surfaces (dialogs, cards, the app shell), plus a
full-circle option — replacing five radius names that all secretly meant
the same thing.

### Detailed improvements across screens
**Page structure & alignment** — unified page shell rolled across ~40+
screens (IAM, Settings, Alerts, Dashboards, Functions, Pipelines, RUM,
Metrics, Synthetics, Billing, editors, lists); one header height; one
page-edge grid driving headers, tables, rails, and tabs; unified
side-rail widths; inset rail selection/hover pills; every tab strip on
the grid line; tightened title/subtitle spacing.

**Tables (cross-screen)** — action columns consistently centered (incl.
Organizations); unified row-number column with no "#" truncation;
non-standard tables restyled to match; loading skeletons made
geometrically identical to the loaded table; symmetric edge inset; IAM
first-column grid alignment fixed.

**Traces** — flame graph + span-detail correlation panel fixes;
correlated logs/metrics placeholder fit; sticky headers; removed a
double scrollbar + a 1px sliver; aligned table fonts/badges; polished
the service detail drawer; stream-selector + correlation alignment;
aligned loading spinners; floating overlay arrows for the
disabled-services strip.

**Logs** — field-list controls aligned (focus ring no longer clipped);
detail-drawer spacing + metrics-tab overflow fixed; Run Query toolbar
tidied; listing sizing + stray border fixed.

**Metrics** — search added to the "Type" facet rail and aligned with the
other rails; proper empty states for the explorer and facet rail.

**Dashboards** — removed inconsistent card shadows; tightened
borders/resizers/field-list spacing; aligned View Dashboard chrome to
the grid; chart colours via the token helper.

**Home** — redesigned the Usage tab; added reusable KPI stat cards so
summary strips stop drifting.

**Dark mode** — new theme-switch animation; fixed a 1px content shift on
toggle and a white flash on load; fixed AI-chat text and assorted
light/dark mismatches; completed the token-driven dark migration.

**Empty states, controls & small polish** — restored 3 broken
empty-state animations; adopted the standard empty state; added the
sliding indicator to the toggle control; fixed the Quality-page inset +
drawer badge; refreshed Search History / Schedulers; fixed the
alert-history drawer scrollbar + timeline hover; removed a stray
menu-bar border.

### Dead code & cruft removal
- **Deleted the entire legacy `utilities.css`** global stylesheet (well
over a thousand lines) — evacuated in waves, roughly half of it dead
once traced.
- **Removed Quasar entirely**, including dead `.q-*` styles and ~25
phantom `--q-*` variables that were silently breaking bits of the UI.
- Stripped hundreds of **dead CSS classes and tokens that compiled to
nothing** — e.g. 46 uses of a colour class with no backing token, a
no-op shadow class on 51 elements, dead layout/utility classes, a
leftover `card-container` block, a dead table-actions token, and a
mis-registered gradient that rendered nothing.
- Cut **unused keyframe animations (19 → 3)** and removed **unused
components** + a stray build artifact.
- Net effect: a much smaller, leaner styling surface — less to maintain,
fewer dead ends to copy.

## Safety & verification
Large but low-risk: this is overwhelmingly a **styling and structure**
change, not product behaviour or data. Guarded by the
design-token/consistency/type checks above plus the existing test suite,
and reviewed screen-by-screen.

---------

Co-authored-by: Kirtan Thakkar <kirtan@kiara.tech>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: ktx-mihir <mihir.patel@kiara.tech>
2026-07-20 18:06:21 +00:00
Vamsi Karthik RandClaude Opus 4.8 ba57f76e9d test(e2e): stabilize alpha1 Traces & Pipelines shards (error-toggle data seeding + flyout-nav / loading-button / indexing races) (#13246)
## What

Stabilizes the **Traces** and **Pipelines** shards of the alpha1 cloud
E2E suite
(`playwright_alpha1.yml`) to green. Rebased on `main` — builds on
#13191's
protocol-aware ingestion agent (`selectAgent`), so no duplicate
transport fix here.

The failing run had 1 hard failure + 1 flake in Traces and 7 failures +
1 flake in
Pipelines. Root causes: a data dependency (error traces not guaranteed),
hover-flyout
navigation force-clicks that miss, a refresh button disabled while
loading, and logs
indexing latency. All fixed with deterministic data/waits — no
`waitForTimeout` as a
fix, no `force:true`, no retry-count bumps, no weakened assertions.

## Root cause & fixes

**Traces**

1. **`tracesAnalyzeDimensions` "P0: Error-only toggle filters trace
results"** (hard fail,
both attempts). The error-only toggle is the error-count badge in
`SearchResult.vue`,
rendered `v-if="errorCount != null && errorCount > 0"` — it exists only
when the search
returns an error span. The shared `default` trace stream has no
guaranteed error traces
(global-setup ingests only logs), so the badge was present or absent by
luck of the
window (hence the intermittent CI greens). Fix: `beforeAll` seeds
guaranteed error
traces via a new `ingestTraces(page, n, { forceScenario: 'error' })`
option in
`trace-ingestion.js`, and `tracesPage.waitForErrorBadgeAfterSearch()`
re-runs the search
until the seeded errors are indexed — a bounded wait for backend
processing, not a sleep.

2. **`traceQueryEditor` "P2: View error spans and their details"**
(flaky). `clickFirstErrorTrace()`
used a blind `waitForTimeout(2000)` that raced the trace-details render
before the test
   asserted on it. Now waits for `trace-details-tree` to be visible.

**Pipelines** (`pipelinesPage.js`)

3. **`pipeline-section-tab-streamPipelines` 45s timeout** (5 tests:
`pipeline-core:56/159/238`,
`pipelines:479`, `pipeline-conditions:297`). `openPipelineMenu()` /
`navigateToStreams()`
navigate via `openNavFlyoutChild`, which hovers a nav group tile and
force-clicks the
teleported flyout child. The flyout self-closes on settle, so the click
can miss and the
page never navigates — the follow-up tab/refresh click then dead-waits
the 45s action
timeout. Both now verify the target page rendered (`pipeline-list-page`
/ `log-stream-table`)
and fall back to a direct `page.goto()` of the route otherwise. (A
failure screenshot showed
   exactly this: the Data flyout open over a blank page.)

4. **`log-stream-refresh-stats-btn` 45s timeout** (3 tests:
`pipeline-dynamic:72/97/113`). The
refresh button is an `OButton` with `:loading` bound to the stream-stats
fetch, and `OButton`
renders `:disabled="disabled || loading"`. Clicking during the (slow, on
loaded alpha) stats
load waited on actionability until timeout. `refreshStreamStats()` now
waits `toBeEnabled()`
before clicking; `navigateToStreams()` waits for the table instead of a
blind 1s.

5. **`openTimestampMenu` empty-table dead-wait.** After exploring the
destination stream, a bare
`.click()` on the first logs row timed out 45s when the freshly-ingested
rows weren't indexed
yet (high indexing latency on loaded envs) — a latent flake exposed once
fix 3 let the test
reach this step. Now re-runs the logs query until a row appears, then
clicks.

## Validation

- **CI — both shards green (workers=3, alpha cloud):**
  https://github.com/openobserve/o2-enterprise/actions/runs/29563931877
  (`alpha1-e2e / Traces` ✅ · `alpha1-e2e / Pipelines` ✅)
- **Original failing run:**
https://github.com/openobserve/o2-enterprise/actions/runs/29481437880
- **Local (alpha, CI conditions):** each previously-failing test re-run
to green —
Traces error-toggle & error-spans; `pipeline-core:56/159/238`;
`pipeline-dynamic:72`.

## Notes

- Only 4 files change (`pipelinesPage.js`, `tracesPage.js`,
`tracesAnalyzeDimensions.spec.js`,
`trace-ingestion.js`). The https-ingestion agent fix these depend on
already landed on `main`
  in #13191 — this branch relies on it rather than re-adding it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 05:53:11 +00:00
Vamsi Karthik RandClaude Opus 4.8 fddf2cf264 test(e2e): stabilize alpha1 SDR, GeneralTests & Metrics shards (stream/pattern-readiness + langTranslation OOM + Reka-table & editor races) (#13259)
## What

Stabilizes the **SDR**, **GeneralTests** and **Metrics** shards of the
alpha1 cloud
E2E suite (`playwright_alpha1.yml`) to green — the last three shards
remaining after
the rest of the suite was greened. Rebased on `main`.

The original failing run had, across these shards: **SDR** 1 hard fail +
1 flake,
**GeneralTests** 21 fails + 2 flakes, **Metrics** a load-sensitive
query-persistence
flake. Root causes were cloud data/UI-readiness races (freshly-created
streams &
regex patterns lagging their list/table; browser OOM under parallelism;
revamped Reka
UI re-rendering mid-interaction), all fixed with deterministic waits on
real signals.

**No `waitForTimeout` as a fix, no `force:true`, no `.first()`/`.nth()`
band-aids, no
retry-count bumps to hide failures, no weakened assertions. No
worker-count,
parallelism, playwright-config or CI/yml changes** — test code only.

## Root cause & fixes

**SDR**

1. **`scrollIntoViewIfNeeded` 45s timeout** (`multipleSDRPatterns`,
`queryTimeDrop`).
The revamped Reka streams/schema table re-renders rows mid-animation, so
the
scroll's stability polling spun to the 45s action timeout even though
the element
was visible. Guard with `expect(el).toBeVisible()` + an instant native
`scrollIntoView`; removed the trailing sleeps.
(`streamAssociationPage.js`)

2. **Stream Detail `click()` 45s timeout.** One-shot JS-then-Playwright
click raced the
re-rendering row. Replaced with a `toPass` retry that re-resolves the
button fresh,
   fires a native DOM click, and verifies the detail sidebar opened.

3. **Regex-pattern create→list eventual consistency** (6 combined tests:
`ingestionTime*`,
`queryTime*`). Create is accepted (`verifyPatternCreatedSuccess` passes)
before it
   propagates to the list read-replica, so the UI text-count check threw
"not found in list". Gate on the backend source of truth:
`waitForPatternCreated`
   polls `GET /re_patterns` until present then confirms the UI rendered;
`waitForPatternDeleted` fixes the symmetric "Unable to delete … Reason:
unknown"
   delete race. (`sdrPatternsPage.js`)

4. **Freshly-ingested stream lags the `/streams` table**
(`multipleSDRPatterns` @slow).
`openStreamDetail` reloads + re-searches until the stream's row appears
(bounded),
instead of a one-shot 5s wait. (Local-caught gotcha:
`isVisible({timeout})` does
   **not** auto-wait — switched to `waitFor({state:'visible'})`.)

5. Transient cloud-gateway **connection timeouts** on `page.request`
pattern calls wrapped
   in a connection-error-only retry.

**GeneralTests**

6. **cipherKeys ×6 — tab never visible.** Cipher Keys shares the exact
`visible: isEnt`
gate as Regex Patterns (`settings/index.vue`), and SDR's regex
management passes on
this same cloud env — so the tab **does** render; the test was clicking
the Settings
menu, which lands on the SectionHub where per-tab data-tests aren't
rendered. Fixed
by a **direct `goto('/web/settings/cipher_keys')`**, mirroring the
working regex page.
   (Not skipped — that would have masked a real, fixable nav bug.)

7. **enrichment ×7 — `pipeline-section-tab-enrichmentTables` 45s
force-click.** The tab
only mounts after the pipelines page header renders; the
flyout→pipelines→section-tab
nav is fragile under load. Replaced with direct SPA nav to the
enrichment-tables route
+ `goto` fallback + a `toPass` settle-retry Add-button click.
(`pipelinesPage.js`)

8. **languageTranslation ×8 + landingPage ×1 — browser OOM cascade**
("Target page/context/
browser has been closed"). 10 exhaustive ~27-page full-app crawls ran
`mode:parallel`
under `--workers=5`; a worker's browser was OOM-killed and every test
after it
cascaded. **Kept parallel** (serializing overran the shard timeout) —
the crawl now
navigates `waitUntil:'domcontentloaded'` + a bounded settle instead of
waiting up to
10–30s for `networkidle` on chart/websocket-heavy pages, cutting each
heavy page's
peak-memory dwell ~10s→~3s (so 5 concurrent crawls no longer spike
together) and making
each crawl ~3–4× faster. Added fail-fast on a closed page/context so any
residual crash
   surfaces at its true origin instead of being swallowed/retried.

9. **schema ×2 — `selectStream` can't find just-created
`test1`/`test3`.** Local reproduction
proved the root cause: the **fixed** stream names hit `400 "stream is
being deleted"`
(a prior run's cleanup still finishing) → the stream got no data → never
listed. Fixed
with **unique per-invocation stream names**; also hardened the ingestion
helper
(status-check + transient retry) and added a streams-API readiness gate
before
   `selectStream`. (`schema.spec.js`)

10. **enrichment `@upload` ×2 — `_search` `waitForResponse` timeout.**
The 30s search wait
was armed **before** the up-to-120s `selectStream`, so it expired
mid-selection. Re-armed
it (200-gated) immediately before `applyQuery`, plus a streams-API
readiness gate for
`e2e_automate`. `schemaload` gated on the `streams?type=logs` response
before reload.

**Metrics**

11. Replaced `waitForTimeout`s in `metricsPage.js` with real signals
(`data-selected="true"`,
`data-state="on"`) and fixed a reka `OToggleGroupItem` state-detection
bug (active state
    is `data-state="on"`, not a `selected` class).

12. **`metrics-promql-query-persistence` load-sensitive flake.**
`selectFirstStream` returned
before the async auto-populate finished, and persistence tests read the
query editor
before Monaco re-rendered after tab switches. Added editor-readiness
gates on real
    signals (auto-populated query present; Monaco mounted + laid out) in
    `metricsQueryEditorPage.js`; assertions unchanged.

## Validation

- **CI — SDR / GeneralTests / Metrics green (alpha cloud):**
  https://github.com/openobserve/o2-enterprise/actions/runs/29633444186
- **Original failing run:**
https://github.com/openobserve/o2-enterprise/actions/runs/29481437880
- **Local (alpha cloud, CI conditions, single-worker):** each
previously-failing test re-run
  to green — `schema.spec.js` 3/3, `multipleSDRPatterns.spec.js` 2/2.

## Notes

- 21 test files change (8 page objects + 13 specs). No shared
cleanup/setup, config, or
  workflow files touched.
- RegressionSet was unaffected by this branch — a transient hang in the
workflow's
"pre-test cleanup" step (before any test runs), unrelated to these
changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 05:45:02 +00:00
Vamsi Karthik RandClaude Opus 4.8 96bbed8a6e test(alerts): stabilize alpha1 Alerts shard on cloud — robust empty-name validation + hardened self-seeded stream registration (#13270)
## What

Follow-up to #13209. In the full-suite alpha1 CI (runs 29576418415 →
29655287388) the
**Alerts** shard was failing on two independent issues. This PR makes
both deterministic so
the shard goes green. Test-infra / page-object only — **no product
code**.

✅ Green: alpha1-e2e / Alerts — 20 passed, 4 flaky (recovered on retry),
3 skipped, 0 failures

https://github.com/openobserve/o2-enterprise/actions/runs/29655287388/job/88116296475

## Root cause & fixes

### 1) `alerts-ui-operations:191` — empty-name validation assertion

**Root cause:** the check asserted an inline field-error element
(`add-alert-name-input-error`) that isn't reliably rendered for the
topbar name input, so
the assertion timed out even though the empty-name Save is correctly
blocked. Verified
against alpha with a live session: on empty-name Save the app surfaces
the block as a
**toast — "Alert name is required."**

**Fix:** assert the toast (the app's actual, visible signal), keeping
the inline field
error as an `.or()` fallback so the check stays robust regardless of
which surface renders.
Validated locally against alpha (PASS) and green in CI.

### 2) `alerts-e2e-flow:106/160` + `alerts-import:52/165` — self-seeded
stream registration

**Root cause:** these specs seed a unique per-test stream (`alert_e2e_*`
/ `alert_import_*`)
with custom columns, then wait for it to register in `GET
/api/{org}/streams?type=logs`
before opening the wizard. On the shared cloud alpha org under full
multi-shard concurrency,
that registration **intermittently takes minutes, not ~1s**, to reflect
in the list —
reproduced with both Playwright `page.request` and a raw HTTP client, so
it is **not** a
test-auth issue. The wizard's stream dropdown reads the same list, so
the stream is absent
there too. The old poll waited only 15/60s and **threw**, hard-failing
in `beforeEach`.

**Fix:** widen the registration poll to **90s** (matches global-setup's
indexing budget) and
make it **non-fatal** — warn and proceed instead of throwing. The stream
is already ingested,
and the point-of-use dropdown selection already retries (in-place ×4 +
wizard re-entry ×2);
with `retries: 2` those slow-to-register streams now recover as *flaky*
rather than
hard-fail. In the green run, 6 streams hit the 90s warning and all
recovered.

## Known follow-up (infra, not test-fixable here)

The deeper cause of the stream flakes is a **server-side streams-list
propagation lag with
session-sticky routing** on the shared cloud alpha org — a
freshly-ingested stream can take
minutes to appear in `/streams` for a given session (some sessions land
on a stale node).
No test-side wait fully resolves it; the retries absorb it. Flagged for
infra investigation.

## Scope / safety

- 2 files: `pages/commonActions.js`, `pages/alertsPages/alertsPage.js`.
No product code.
- No tests added/deleted/skipped, no `.only`, no assertions weakened
(191 asserts the real
  user-facing signal; the `.or()` keeps inline-error coverage).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 05:09:50 +00:00
Prabhat Sharma eaba77fa34 fix(i18n): DeepSeek translation pipeline, BCP-47/en-US locales, +ru/pl/vi, full backfill (#13263)
## Summary

Replaces the AWS Translate i18n pipeline with a DeepSeek (LLM) backend,
standardizes locale files to BCP-47 naming with an `en-US` base, adds
new languages, and backfills **every locale to 100%**.

## What changed

### Translation engine (DeepSeek)
- Swap AWS Translate → DeepSeek via its OpenAI-compatible API
(`scripts/translations/`). Auth via the `DEEPSEEK_API_KEY` secret;
per-request 60s timeout.
- **Batched** translation (50/call) with **per-string validation**:
interpolation placeholders (`{count}`, `%s`, `@:key`), vue-i18n
**pluralization pipes** (`{n} Day \| {n} Days`), and literal escapes
(`{'@'}`, `{'{'}`, `{'\|'}`) are preserved or the string is rejected and
retried.
- Robust recovery: index-aligned batches, split-on-mismatch to isolate a
single bad string, temperature-perturbed retries, and rejection of
empty/whitespace output (never blanks a label). Removed the old
`TRANSLATION_MAX_KEYS` safety cap.

### Locale naming + base language
- All 15 locale files renamed to **BCP-47 hyphen** form (`en-US.json`,
`zh-CN.json`, `zh-TW.json`, `fr-FR.json`, …) — matching
`navigator.language` / `Intl` / HTML `lang`.
- **English base switched `en-gb` → `en-us`** (app code,
`fallbackLocale`, BCP-47 map, selector, defaults). British-Pound
currency and date-formatting `en-GB` usages left untouched. Existing
`en-gb` cookies fall back cleanly to English — no migration needed.

### New languages
- **Russian (`ru`), Polish (`pl`), Vietnamese (`vi`)** — fully generated
and wired into `localeFileMap`, `APP_LOCALE_TO_BCP47`, and the language
selector.
- **Traditional Chinese (`zh-TW`)** now maintained by the translator
alongside Simplified (`zh-CN`).
- RTL languages (`ar`, `fa`) intentionally **deferred** until the app
has `dir="rtl"` support.

### Full backfill (one-time)
- Every pre-existing locale filled from ~5.9k up to the full **8,269
keys** (~26.9k strings). `.translation_state.json` rebuilt complete, so
future runs are incremental.

### Nav i18n bug fix
- The **Dashboards** and **Data** nav group labels were hardcoded
English (bypassing i18n) and stayed English in every locale. Now
resolved via `t()` (`menu.dashboard`, new `menu.data`), localized and
re-resolving on language change.

## Verification
- Full web unit suite: **39,035 passed / 414 skipped / 0 failed** (1,167
files).
- `type-check` clean (0 TS errors).
- Locale registry sync spec green; all 15 files = 8,269 leaves.
- Translation engine verified live against `deepseek-v4-flash`.

## Notes
- Since all locales are now 100%, the post-merge `update-translations`
workflow will find nothing pending (no follow-up translation PR).
- `ar`/`fa` to be added with RTL support in a follow-up.
2026-07-19 05:29:01 +00:00
Prabhat Sharma d9d128d61c fix: Serviceaccount1 (#13257)
Improve UI for creating service accounts.
Improve UI for accessing MCP server.
2026-07-18 09:06:26 +00:00
ktx-mihirandktx-vaidehi eaebff9e57 fix: alerts module migration with zod (#13227)
- alert module migration with zod

---------

Co-authored-by: ktx-vaidehi <134508096+ktx-vaidehi@users.noreply.github.com>
2026-07-17 13:03:17 +00:00
Vamsi Karthik RandClaude Opus 4.8 30b736e6e4 test: stabilize alpha1 Logs-Queries & Logs-Features shards on cloud (monolithic download-test split + share-link redirect hydration + SQL-commit reliability) (#13241)
## What

Stabilizes the **Logs-Queries** and **Logs-Features** shards of the
alpha1 cloud E2E
suite to green. Test-infra + page-object changes only; **no product
code** (5 files
under `tests/ui-testing/`).

> **Stacked on #13240** (Logs-Core). Base is `fix/logs-core-alpha1-e2e`
— please merge
> #13240 first; GitHub will then retarget this PR to `main`. The diff
here is only the
> Logs-Queries/Features work (5 files).

## Root causes & fixes

### Logs-Queries

**`logsDownloads.spec.js` — monolithic test exceeded the test timeout
(hard failure).**
All 14 download scenarios ran sequentially in **one** `test()` (each a
full `page.reload`
+ re-setup), needing ~7–8 min against a 360s budget. It hit 360s
mid-run, Playwright tore
the page down, and the remaining scenarios failed with **"Target
page/context closed"** (a
cascade, not a download bug). A `try/catch` wrapper also swallowed
per-scenario errors and
rethrew an aggregate, hiding the real stack. → **Split into 14 isolated
per-scenario tests.**
The `beforeEach` already yields a fresh, query-loaded page, so no
per-scenario reload is
needed; each test is short, isolated (one failing download can't close
the page for the
others), and parallelizes. Removed the error-swallowing wrapper;
`@downloadAll` tag preserved.

**`searchpartition.spec.js` — Reka OSwitch state asserted within a
hardcoded 5s (flaky).**
`verifyHistogramState` waits for the histogram OSwitch
`data-state="unchecked"` element, but
the Reka switch animates the checked→unchecked transition and the
settled state can appear
>5s after the toggle+execute under CI load. → Raised the poll ceiling to
15s (still asserts
the real end-state, no sleep).

### Logs-Features

All the share-link failures were **flaky, not product bugs** — the
redirect fully restores
every param; the tests raced the SPA under CI load.

**Reading UI/URL state before the short-URL redirect finished
hydrating.** `getQueryEditorText()`
returned `""` (lazy Monaco visible but not yet pre-filled) and
`captureCurrentState()` read
`show_histogram=null` (the SPA rewrites URL params in stages). → New
page-object helpers
`waitForQueryEditorContent`, `waitForUrlParam`, and URL-stabilization
inside
`waitForRedirectComplete` (`_waitForUrlStable`). No fixed
`waitForTimeout`.

**Bare `clickRefresh()` cancelled the in-flight SQL-mode auto-search**
("Running query
cancelled" toast), so `sql_mode`/query never committed to the short URL
→ empty editor after
redirect. → Commit via `runQueryAndWaitForResults()` (waits for the
Cancel state to clear
first), then confirm `sql_mode` is in the URL before sharing.

**SQL setup itself was unreliable.** `enableSqlModeIfNeeded` (Vue
`meta.sqlMode` flag)
didn't always stick, and `clearAndFillQueryEditor`'s focus-sensitive
`Ctrl+A` select-all
silently appended in headless CI (**doubled query**). → New
`setupSqlQueryForShare(query)`:
sets the Vue flag + writes the exact query via Monaco `executeEdits`
(verified) +
`runQueryAndWaitForResults`, then confirms `sql_mode` committed to the
URL — **retries once,
then strict-asserts** (writing SELECT text alone does **not** flip
`meta.sqlMode`; the flag
is what the app serializes to `sql_mode`). `waitForUrlParam` gained a
`required` mode that
throws instead of silently letting a bad state through to the share.

**Residual Monaco lazy-mount race after the short-URL hop** — the editor
occasionally
mounted without applying the query from the (resolved) URL. →
`waitForRedirectedQueryEditorContent`
self-heals with **one** reload of the resolved URL (the reliable
URL-param prefill path).

**Share success toast strict-mode violation** — the "Link Copied
Successfully!" toast
coexisted with the cancelled-query info toast, so the broad selector
matched 2 elements. →
Match the share-result toast by message with `.first()` in the share
helpers.

**`searchPatterns.spec.js` — async pattern extraction still
empty/timeout after 60s** under
alpha indexing load. → `setupPatternsView` re-runs the query and waits
once more before giving
up (resilience for the data dependency; callers still assert the
returned state).

## Scope / safety

- **5 files:** `pages/logsPages/logsPage.js` + specs `logsDownloads`,
`monaco-query-prefill`,
  `shareLink`, `searchPatterns`. **No product code.**
- **No tests deleted, no `.only`, no unconditional skips, no assertions
removed.**
- Every fix replaces a fixed sleep / wrong assumption with a
deterministic wait on the real
  condition — no `waitForTimeout`, no `force`, no retry-based masking.

## Validation

- Local on cloud alpha (`retries:0`, stricter than CI's `retries:1`):
- `logsDownloads` **14/14** (`--workers=3`) — no timeouts, no "Target
page closed".
- Previously-flaky share-link / SQL / searchpartition tests **12/12**
under `--repeat-each=3`
(`sql_mode` committed on the first attempt every time; retry never
needed).
- Full `shareLink` + `monaco-query-prefill` files **15/15** — no
regressions.
- alpha1 Logs-Queries + Logs-Features CI: green —
https://github.com/openobserve/o2-enterprise/actions/runs/29539009573


🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 09:27:04 +00:00