## Summary
- The previous PR (#12229) fixed most instances of `200GB` in `en.json`
but missed the `open_source.badge_text` key which powers the \"Get
Enterprise Edition\" dialog shown to OSS users
- Fixed: `about.enterprise_offer.open_source.badge_text` → `Free up to
50GB / day`
## Test plan
- [ ] Open the app as an OSS user (no enterprise license)
- [ ] Trigger the Enterprise upgrade dialog
- [ ] Confirm badge reads "Free up to 50GB / day"
🤖 Generated with [Claude Code](https://claude.ai/claude-code)
fixes:
- [x] In the IAM users view, please show the roles assigned to each user
alongside the user (currently not visible). Currently we only show
system roles.
- [x] If a system role has been assigned to an existing user, there's no
way to modify it. we should allow edits.
- [x] Customer expected to be able to set up users/roles ahead of
ingestion, when we click in IAM, it goes there but when we try to
perform operations then it redirects back to data sources section.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
#11936
## What changed
Fixed `TraceDetails.vue` so that `traceServiceMap` captures services
from **all** root span nodes in a trace, not just the first one.
Previously, traces with two or more root spans (e.g., from misconfigured
instrumentation) would show service data only for the first root.
## Why
When a trace has multiple root spans, the service-map waterfall widget
and trace-graph display were incomplete — only the first root's services
appeared. Users investigating instrumentation issues or multi-root
traces (which the existing UI already supports rendering) were missing
service data for the second and subsequent roots.
Summary
Migrated the "Add Dashboard from Gallery" feature from GitHub API to S3
(direct bucket access), removing the GitHub rate-limit dependency, and
updated all corresponding test mocks to match the new S3 XML response
format.
What changed
1. Data source: GitHub API → S3 List Objects V2
The gallery was previously fetched from
api.github.com/repos/openobserve/dashboards/contents, which is subject
to GitHub's rate limiting (60 req/hr for unauthenticated requests). It
now reads directly from the S3 bucket openobserve-datasources-bucket via
the List Objects V2 XML API.
loadDashboards() — folder listing now calls:
GET
https://...s3.amazonaws.com/?list-type=2&prefix=dashboards/&delimiter=/
And parses the XML response via parseS3Folders(), which reads
<CommonPrefixes><Prefix> elements.
handleNext() — file listing inside a folder now calls the same S3
endpoint with a deeper prefix, parsed via parseS3Files() which reads
<Contents><Key> elements.
confirmAdd() — dashboard JSON download changed from
raw.githubusercontent.com/... to the direct S3 object URL.
2. Test mock format: JSON → S3 XML
All tests that mocked fetch were still returning the old GitHub JSON
format ([{name, type}]). Since the component now calls
DOMParser.parseFromString(xml, "application/xml"), the JSON strings were
unparseable as XML, resulting in empty dashboards arrays and causing the
"sort dashboards alphabetically" test to fail with undefined.
Added two helpers (s3FolderListXml, s3FileListXml) and updated every
affected fetch mock to return valid S3 List Objects V2 XML. Also
strengthened a few assertions that were previously passing vacuously (an
empty array also "doesn't contain .github").
---------
Co-authored-by: Shrinath Rao <shnath@openobserve.ai>
Co-authored-by: Bhargav <BJP232004@GMAIL.COM>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
#11841
## What changed
Added `queryParams.stream = effectiveStreamName.value` to the share URL
generation in `TraceDetails.vue` so the stream name is included when
generating a share/short URL.
## Why
When sharing a URL from the Trace Details view, the stream name
parameter was missing from the generated URL. This caused the shared
link to open without the correct stream context, making it unable to
display the trace properly on navigation.
## Approach
The stream name is already resolved by the `effectiveStreamName`
computed property — which handles both embedded mode (via
`props.streamNameProp`) and standalone mode (via
`router.currentRoute.value.query.stream`). The fix simply passes this
value into the `queryParams` object before the URL is serialized.
#11816
## What changed
Added an optional `skipSearch` parameter to `SearchBar.vue`'s
`applyFilters` method. When `true`, the method applies filters to state
without emitting a `searchdata` event. In `Index.vue`,
`onMetricsFiltersUpdated` now passes `skipSearch=true` when live mode is
ON, letting the datetime trigger (`triggerAbsoluteQueryDebounced`)
handle the search call. When live mode is OFF, `skipSearch=false` so the
search still fires (since the datetime trigger won't run).
## Why
When auto-search is enabled and a user drags on RED charts to select a
time range, both `applyFilters` and `triggerAbsoluteQueryDebounced` were
called simultaneously — each triggering a separate `searchdata` API
call. Per the user, "searchdata should only be called from
triggerAbsoluteQueryDebounced." The fix ensures only one search call
happens by having `applyFilters` skip its own search when live mode is
on.
#11815
## What changed
Fixed a bug in `TenstackTable.vue` where the virtual scroll row click
handler used `tableRows[virtualRow.index]` instead of
`formattedRows[virtualRow.index]?.original` to emit row data. When the
table is sorted server-side, `tableRows` retains the original unsorted
order while `formattedRows` reflects the sorted order, so clicking the
first visible row emitted data from the wrong source row. Also added a
regression test for the sorted virtual-scroll case.
## Why
When a user sorted the Traces search results by the spans column and
clicked the first visible row, the `click:dataRow` event emitted the
original unsorted row (e.g., "alpha" at index 0) instead of the sorted
row (e.g., "gamma" at index 0 after sorting desc). This caused
downstream consumers to receive incorrect row data.
#11615
## What changed
Extracted duplicate resize/mousedown/mousemove/mouseup logic from
`TraceDetails.vue` (horizontal resizer) and `FlameGraphView.vue`
(vertical resizer) into a shared `useResizer` composable. The flame
graph now embeds a `TraceDetailsSidebar` in a resizable bottom panel
directly, rather than only emitting `span-selected` events to a parent.
## Why
Both `TraceDetails.vue` and `FlameGraphView.vue` independently
implemented the same resize pattern (`mousedown` → `mousemove` delta
calculation → `mouseup` cleanup), creating duplicated logic that was
brittle and hard to maintain. Additionally, the flame graph view needed
to host the trace details sidebar inline to support the full span-detail
workflow without requiring a parent component to manage the panel.
## Approach
- Created `web/src/composables/useResizer.ts` accepting `direction`,
`initialValue`, `minValue`/`maxValue`, `unit`, `containerRef` (for
percentage mode), `throttleMs`, `invert`, and `onResize` callback —
returns `value`, `isResizing`, and `onMouseDown`.
- Replaced the manual event-binding code in `TraceDetails.vue` (both
left-panel and DAG resizers) with calls to `useResizer`.
- Replaced the duplicated resize code in `FlameGraphView.vue` with
`useResizer`; added a bottom panel section containing
`TraceDetailsSidebar`.
- Added `sidebarVisible` state and `selectedSpan` computed from a new
`spanMap` prop to `FlameGraphView.vue`.
- The `invert` option was added during the session because vertical
resizing worked in the opposite direction — moving the mouse up
increased the element height instead of decreasing it.
- Updated tests to cover sidebar visibility, `selectedSpanId` store
sync, and the new props.
#11740
## Why
Users viewing correlated logs from traces saw results from only one
stream (the "primary" stream). Multi-stream setups where different
streams use different field names for the same semantic concept (e.g.,
`k8s_namespace_name` vs `service_k8s_namespace_name`) would silently
drop streams whose schemas didn't match the filter field exactly. This
PR makes correlation queries multi-stream-aware across both traces and
logs.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## What changed
Replaced single-stream correlation log queries with multi-stream
support. The composable now builds independent SQL queries for each
correlated log stream and sends them as an array to
`_search_multi_stream`, merging and sorting results by `_timestamp` on
completion. Also temporarily disabled hover span selection in the trace
tree due to UX issues, and made the timestamp column configurable via
`store.state.zoConfig.timestamp_column`.
## Why
The previous implementation only queried the primary stream (first log
stream), missing correlated logs from other streams. Multi-stream
support is needed to show all correlated logs across streams. Hover span
selection was producing `null` span IDs on unhover, causing UX glitches
— disabled pending a proper fix.
This adds support for current cycle for stripe users as period for usage
page
---------
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>
- #11689: Service Catalog clear search filter blanks page regression
- #11687: Service graph side panel $ pattern fix verification
- Added clickServiceCatalogTab() and clickFilterClearButton() to
servicesCatalogPage
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
- #11565
Design At:
https://github.com/openobserve/designs/tree/main/dashboards/builder-tab-impr
- Implemented parseWhereClauseToFilter to convert raw WHERE clause text
into a structured filter format.
- Added extractWhereClause to retrieve the WHERE clause from a full SQL
query.
- Enhanced unit tests for both functions to cover various scenarios
including empty inputs, valid conditions, and error handling.
---------
Co-authored-by: ktx-akshay <akshay.patil@kiara.tech>
## Summary
Cherry-picks two correlation fixes from `branch-v0.90.0` to `main`:
- `a077b760c` fix: corelation custom groups (#11662) — adds `group`
field to `FoundGroup` and threads `semantic_groups` through
`calculate_dimension_analytics`
- `211876a97` fix: corelation settings fixes (#11666) — validates
tracked alias IDs against bundled defaults + custom DB groups; sanitizes
payload (drops `service` and orphan IDs) before save
Conflicts resolved by taking v0.90.0 versions (the fixes are the point
of the cherry-pick). Companion PR on o2-enterprise:
openobserve/o2-enterprise#1648 — that PR is currently red because it
depends on the new `FoundGroup.group` field landing here first.
## Test plan
- [ ] CI green (build, unit, playwright)
- [ ] Verify save Identity Config rejects invalid alias IDs but accepts
default + custom IDs
- [ ] Verify `_analytics` endpoint returns `group` category on
FoundGroup
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- **fix: llm insights tab**
- **remove custom attributes and use gen ai spec**
---------
Co-authored-by: sai nikhil kethe <nikhil@openobserve.ai>
Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
#11590
## What changed
Fixed sorting on the operations and resource tables in the service
details side panel. Previously, columns like P99, P95, and P75 sorted by
their formatted string values (e.g., "1.23ms") instead of their raw
numeric values, producing incorrect sort order. Sorting is now handled
client-side via a custom sort function that compares raw latency values,
and the TenstackTable receives explicit `sort-by`/`sort-order` props
with a `sort-change` event handler.
## Why
The TenstackTable's built-in sorting handler sorted on the formatted
display value, which is a string — making numeric sorting incorrect for
latency percentile columns. The fix aligns with how sorting is handled
in `ServicesCatalog.vue` (referenced implementation pattern).
## Summary
Fixes#9875
When creating an alert from a dashboard panel, the alert name may
contain
spaces or special characters that the backend rejects (HTTP 500). This
PR
adds frontend validation to catch these invalid characters before
submission.
## Changes
- **`useAlertForm.ts`**: Added regex `ALERT_NAME_UNSUPPORTED_CHARS`
matching
backend `RE_OFGA_UNSUPPORTED_NAME` pattern. Three validation checks in
`validateAndFocus()`: empty name, unsupported chars (:#?'"%& and
whitespace),
and forward slash.
- **`AddAlert.vue`**: Added `:rules` with `reactive-rules` on the alert
name
`q-input` for real-time inline error display.
- **i18n**: Added `nameRequired`, `nameNoSpecialChars`, `nameNoSlash`
keys
to 11 language files (en, zh, ja, de, fr, es, ko, it, nl, pt, tr).
## How to Test
1. Navigate to **Alerts → Add Alert**
2. Type `my alert` (with space) → red error shown immediately
3. Type `test:name` or `alert#1` → same validation error
4. Type `valid_alert` → passes validation
5. From **Dashboard panel → Create Alert** → auto-generated name should
have no spaces (existing `sanitizePanelTitle` logic)
## Checklist
- [x] Frontend changes only
- [x] Validation matches backend regex
- [x] i18n translations added for all supported languages
- [x] No lint errors