Skip to content

Upgrade @elastic/charts to 71.8.1 - #2

Closed
angle943 wants to merge 88 commits into
mainfrom
elastic-charts-71.8.1-upgrade
Closed

Upgrade @elastic/charts to 71.8.1#2
angle943 wants to merge 88 commits into
mainfrom
elastic-charts-71.8.1-upgrade

Conversation

@angle943

Copy link
Copy Markdown
Owner

Summary

Upgrades @elastic/charts from 31.1.0 → 71.8.1.

Changes

  • Dependency bump (package.json, packages/osd-ui-shared-deps/package.json): 31.1.0 → 71.8.1. This pulls uuid ^14, removing the vulnerable uuid 3.x and resolving CVE-2026-41907.
  • scripts/postinstall.js: patch charts dist/theme.scss for constructs incompatible with OUI 1.22.1 / Dart Sass:
    • euiFocusRing(null, 1)euiFocusRing (OUI's mixin takes a single arg)
    • wrap legacy $euiSizeXS Sass division in calc()
  • Discover histogram (histogram.tsx):
    • deep-clone the charts default theme before applying overrides — the theme object is frozen in charts >=71, which otherwise crashes the histogram with Cannot assign to read only property 'axisTitle'
    • set timeAxisLayerCount={0} to keep the single-row time axis so the existing tickFormat continues to drive x-axis labels (charts >=71 defaults to a multi-layer ordinal time axis)

Testing

  • yarn osd bootstrap succeeds; all 61 dev bundles compile.
  • Verified live against an OpenSearch snapshot with sample data: Discover histogram and TSVB render correctly; histogram x-axis tick format matches the prior 31.1.0 output.

Note: charts >=71 uses an adaptive, width-aware tick algorithm, so the histogram shows fewer x-axis labels than 31.1.0 at the same width (format is unchanged).

angle943 and others added 30 commits June 12, 2026 21:20
…osdCustom rule (opensearch-project#12215)

In joi 17, calling .osdCustom() multiple times on the same schema
overwrites the previous rule instead of stacking. This caused:
- schema.string({ minLength: 1, maxLength: N }) to only enforce maxLength
- schema.string({ minLength, maxLength, validate }) to only enforce validate

Combine all string length validations and user validate function into a
single osdCustom call. Also prevent the base Type class from adding a
separate osdCustom for the validate option when StringType already
handles it.

Signed-off-by: Justin Kim <jungkm@amazon.com>
…arch-project#11395)

* Fix duplicate shortcut registration for focus_query_bar

Renamed the shortcut ID to be unique per instance in the data plugin and distinctive in the explore plugin to prevent crashes when multiple query bars are rendered.

Signed-off-by: Mumukshu D.C <phoenixrising656@gmail.com>

* Address maintainer feedback: registerKeyboardShortcut prop and useCallback

Signed-off-by: Mumukshu D.C <phoenixrising656@gmail.com>

* Fix lint errors: extract useCallback, fix prettier formatting

- Move useCallback out of conditional useKeyboardShortcut call
- Add editorRef to useCallback dependency array
- Fix prettier formatting for documentation object indentation
- Remove extra space in empty arrow function body

Signed-off-by: Abby Hu <abigailhu2000@gmail.com>
Signed-off-by: Abby Hu <qingyah@amazon.com>

---------

Signed-off-by: Mumukshu D.C <phoenixrising656@gmail.com>
Signed-off-by: Abby Hu <abigailhu2000@gmail.com>
Signed-off-by: Abby Hu <qingyah@amazon.com>
Co-authored-by: Qingyang(Abby) Hu <abigailhu2000@gmail.com>
Co-authored-by: Abby Hu <qingyah@amazon.com>
…-project#12223)

After grunt was removed, packages/osd-ui-framework/package.json still
declares opensearchDashboards.build.intermediateBuildDirectory: 'target',
but its 'build' script ('grunt prodBuild') that used to populate target/
was deleted (scripts is now empty).

In the production build (@osd/pm buildProductionProjects) the per-project
flow is: deleteTarget() wipes target/, buildProject() is now a no-op (no
build script, no build targets), copyToBuild() then copies from the empty
target/. As a result only package.json is shipped and the committed
dist/kui_*.css files are dropped from node_modules/@osd/ui-framework.

At runtime core_app.ts serves /node_modules/@osd/ui-framework/dist/{path*}
from disk, so the missing kui_*.css returns a JSON 404 and the browser
blocks it on an X-Content-Type-Options: nosniff MIME-type mismatch,
briefly flashing the fatal-error (red) banner on initial load.

The KUI stylesheets are now pre-compiled and committed in dist/, so no
build step is required. Remove the stale intermediateBuildDirectory so the
package is shipped from its source root (which contains dist/). The build's
CleanExtraBuildFiles task strips source .scss/tests/docs from node_modules
while preserving .css.

Verified with a full distributable build: node_modules/@osd/ui-framework/dist/
now contains all six kui_*.css files (kui_v9_light.css included).

Signed-off-by: Justin Kim <jungkm@amazon.com>
…helper (opensearch-project#12208)

* Replace @amoo-miki/numeral fork with stock @elastic/numeral + BigInt helper

The @elastic/numeral dependency was aliased to a personal-scope fork
(npm:@amoo-miki/numeral@2.6.0) whose only delta over stock @elastic/numeral
2.5.1 is a BigInt (long-numeral) format branch. This removes the fork in
favor of the unmodified upstream package plus a small, well-tested in-repo
helper that reproduces the BigInt path byte-for-byte.

- package.json + packages/osd-ui-shared-deps/package.json: alias both back to
  stock @elastic/numeral@2.5.1 (the latter feeds the browser shared-deps bundle)
- field_formats/utils/format_bigint.ts: faithful port of numeral's BigInt
  format path (number/currency/abbreviation/sign/grouping; percent/bytes/ordinal
  throw on BigInt exactly as the fork did)
- converters/numeral.ts: route the isBigInt branch through formatBigInt
- format_bigint.test.ts + __fixtures__/numeral_bigint_golden.json: 576-case
  golden corpus captured from the fork proves bug-for-bug parity, incl. throws

Number-path output is unchanged: stock 2.5.1 is byte-identical to the fork for
all Number inputs (the fork is just 2.5.1 + the BigInt branch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Joey Liu <jiyili@amazon.com>

* Trim comments and drop fork references in BigInt format helper

Addresses review feedback: shorten the verbose comments in
format_bigint.ts and stop referencing the removed personal-scope
numeral fork so future readers aren't confused by a dependency that
no longer exists. Describe the helper on its own terms (numeral's
BigInt format path) instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Joey Liu <jiyili@amazon.com>

---------

Signed-off-by: Joey Liu <jiyili@amazon.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…Engine data sources (opensearch-project#12216)

* fix(sample-data): exclude Observability (otel) sample set on AnalyticEngine

The sample data list route already limits the available sample sets for an
AnalyticEngine (Mustang) data source. It kept both 'logs' and 'otel', but the
Observability sample set (otel) cannot be installed on a Mustang domain: its
trace index mappings declare 'nested' fields (events/links), which the
pluggable data format rejects at index creation:

  mapper_parsing_exception: nested type is not supported with pluggable data
  format on field [links]

so the install fails with an internal server error
('Unable to install sample data set: Sample Observability Logs, Traces, and
Metrics'). Restrict the AnalyticEngine sample set list to 'logs' (Sample web
logs), which has no nested fields and installs cleanly.

Updates the route's unit test to assert only 'logs' is returned for an
AnalyticEngine data source; non-AnalyticEngine sources are unchanged.

Signed-off-by: Shenoy Pratik <pshenoy36@gmail.com>

* chore: add changelog fragment for opensearch-project#12216

Signed-off-by: Shenoy Pratik <pshenoy36@gmail.com>

* Update src/plugins/home/server/services/sample_data/routes/list.ts

Co-authored-by: Joshua Li <joshuali925@gmail.com>
Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>

---------

Signed-off-by: Shenoy Pratik <pshenoy36@gmail.com>
Signed-off-by: Shenoy Pratik <sgguruda@amazon.com>
Co-authored-by: Joshua Li <joshuali925@gmail.com>
opensearch-project#12258)

* fix(data_source): prevent privilege escalation via unauthorized data source usage

The getClient(dataSourceId) context provider passed the calling user's
scoped SavedObjects client directly to configureClient/configureLegacyClient,
which then fetched and decrypted the data source's stored credentials with no
authorization check on whether the caller was permitted to USE that data source.
Any authenticated user with read access to a tenant could use any data source's
stored credentials to execute requests as that data source's identity, bypassing
index-level, document-level, and field-level security (CVE pending).

Fix (two layers):

Layer 1 — Strip credentials from read APIs in DataSourceSavedObjectsClientWrapper.
The wrapper previously only intercepted write operations (create/update).
get(), find(), and bulkGet() now strip auth.credentials from data-source saved
objects before returning them to any caller, so encrypted credential material is
never exposed through the SavedObjects API.

Layer 2 — Internal repository for credential access in getClient.
DataSourcePlugin.start() creates an internal SavedObjects repository that bypasses
the credential-stripping wrapper. configureClient and configureLegacyClient now
perform a two-step fetch:
1. getDataSource(id, scopedClient) — access check; throws 404/Forbidden if the
   calling user's tenant/workspace does not include this data source.
2. getDataSourceInternal(id, internalRepo) — fetches with full encrypted
   credentials only after step 1 passes.

internalSavedObjects is optional in DataSourceClientParams for backward
compatibility; callers that do not provide it (e.g. test-connection routes,
existing unit tests) retain the previous single-fetch behavior with no change
in call count or semantics.

Affects: open-source self-managed deployments with data_source.enabled: true.
Not affected: managed service (token_exchange auth model, no stored credentials).

Signed-off-by: Zilong Xia <zilongx@amazon.com>

* fix: address lint errors (prettier formatting, array type style)

Signed-off-by: Zilong Xia <zilongx@amazon.com>

---------

Signed-off-by: Zilong Xia <zilongx@amazon.com>
…12234)

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
* fix auto creation field detection

Signed-off-by: Adam Tackett <tackadam@amazon.com>

* address comment

Signed-off-by: Adam Tackett <tackadam@amazon.com>

---------

Signed-off-by: Adam Tackett <tackadam@amazon.com>
Co-authored-by: Adam Tackett <tackadam@amazon.com>
* fix side nav

Signed-off-by: Adam Tackett <tackadam@amazon.com>

* address comment

Signed-off-by: Adam Tackett <tackadam@amazon.com>

---------

Signed-off-by: Adam Tackett <tackadam@amazon.com>
Co-authored-by: Adam Tackett <tackadam@amazon.com>
…12266)

* chore(deps): hono 4.12.25

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): markdown-it 14.2.0

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): js-yaml 4.2.0

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): ws 8.21.0, 7.5.11

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): form-data 4.0.6

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): tar 7.5.16

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

---------

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
…alcite proxy routes (opensearch-project#12255)

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>
Co-authored-by: Hanyu Wei <weihanyu@amazon.com>
…rds) (opensearch-project#12272)

- Replace old backport workflow (VachaShah/backport + GitHub App) with reusable workflow
- Remove delete_backport_branch.yml (now handled by reusable workflow)

Signed-off-by: Peter Zhu <zhujiaxi@amazon.com>
…pensearch-project#12221)

visualization snapshot

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
… column identifier (opensearch-project#12218)

* clean up uniqueValuesCount/validValuesCount

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

* fix lint

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
…ersion (opensearch-project#12270)

* chore: use major version in .nvmrc to avoid requiring exact Node.js version

.node-version pins the exact runtime version used by the build system
for downloading Node.js binaries; .nvmrc only needs to guide developers
to the correct major version via nvm.

- Change .nvmrc from exact version to major version (22)
- Update build config to read .node-version for exact version

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

* Update DEVELOPER_GUIDE.md for nodejs version usage

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
…earch-project#12280)

The Data Table visualization was missing from the "Create New
Visualization" type picker. createBaseVisualization() was being
called after `await core.getStartServices()`, which only resolves
once the plugin's start phase runs. Since vis types must be
registered during the setup phase (before the registry is read to
build the picker), the type was registered too late and silently
never appeared.

Move createBaseVisualization() ahead of the getStartServices()
await so registration happens synchronously during setup. The
expressions renderer registration still awaits start services
since it genuinely needs the CoreStart contract.

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
…ss CVEs (opensearch-project#12282)

* chore(deps): postcss-selector-parser from 6.0.10 to 6.1.4

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): remove not need it resolutions

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): dompurify 3.4.11

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): pixelmatch from 5.2.1 to 5.3.0

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): pngjs 7.0.0

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

---------

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
…pensearch-project#12281)

When a slash command is registered or unregistered at runtime, the
command suggestion dropdown now updates immediately. Previously,
suggestions only refreshed on user input change, causing stale
entries to remain visible if a command was dynamically removed.

Adds an onChange listener to SlashCommandRegistry that notifies
the useCommandMenuKeyboard hook to re-evaluate suggestions.

Signed-off-by: Lin Wang <wonglam@amazon.com>
* chore(build): upgrade Rspack to v2

Disable import/no-unresolved for @rspack/core require

@rspack/core v2 is published as a pure ESM package ("type": "module"
with no CJS entry in exports). ESLint's import resolver cannot resolve
ESM-only packages in a require() context. Node.js 22 handles this at
runtime via native require(esm) support, so the import works correctly
despite the resolver limitation.

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

* update test snapshots

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

* update failing snapshots

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
SuZhou-Joe and others added 28 commits July 10, 2026 17:35
… plugin registration) (opensearch-project#12362)

* fix: don't terminate lint on ESLint 10 concurrency warning

ESLint 10 emits an advisory ESLintPoorConcurrencyWarning when
`concurrency: 'auto'` (src/dev/run_eslint.js) selects multithreading for a
small workload, such as linting a single plugin directory. The process-warning
handler in setup_node_env/exit_on_warning.js treats any unlisted Node
process-warning as fatal and calls process.exit(1), so `yarn lint` exited 1
even with zero lint errors, breaking CI for downstream plugins.

Add ESLintPoorConcurrencyWarning to the ignore list alongside the other
advisory warnings so it no longer terminates the process. Real lint errors
still exit 1.

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: share plugin registration via @elastic/eslint-config-kibana

Plugins that consume the shared flat config should not have to know which
ESLint plugin owns a rule or re-register it. In ESLint 10 flat config, `plugins`
registration is scoped per matched file and is not inherited between config
objects, so a plugin spreading the shared config and referencing e.g.
`@typescript-eslint/no-explicit-any` in its own block would fail with
'Could not find plugin' unless it re-required and re-registered the plugin.

Register every bundled plugin once in an unscoped config object
(`globalPluginRegistration`) placed first in the exported array, so downstream
rule references resolve at any file scope with no per-plugin boilerplate.

- plugins.js: single source of truth for plugin instances + global registration
- eui.js: opt-in EUI config block (EUI is not part of the base config)
- extras.js: aggregates { eui, plugins, restrictedGlobals } behind one subpath
- eslint.config.js: sources instances from plugins.js; global registration first
- package.json: add exports map (., ./eslint.config.js, ./extras); align peers
- plugin generator template + README: use the spread pattern, no registration

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* style: apply prettier 3 formatting to workspace/server/utils

These files (added in opensearch-project#12343) carry nested-ternary indentation that Prettier 3
reformats but that landed before this branch surfaced it under the ESLint 10 /
Prettier 3 lint. Pure formatting change; no logic change.

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
…0.2 tar 7.5.19 (opensearch-project#12364)

* chore(deps): hono 4.12.28 immutable 5.1.9 js-yaml 4.3.0 linkify-it 5.0.2 tar 7.5.19

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* fix: formatting issues after eslint 10 merge

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

---------

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
…project#12345)

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
opensearch-project#12346)

When starting a new conversation while tool calls were in pending/executing
state, the input remained disabled because stale toolCallStates from the
previous run persisted in the global AssistantActionService singleton.

Add eventHandler.clearState() to handleNewChat to drain all pending tool
calls and reset the input-blocking hasActiveToolCalls check.

Signed-off-by: Lin Wang <wonglam@amazon.com>
* Refactoring get_query_with_source
* Fix mangled regex and handle quotes
* Fix prettier lint test issue
* Fix Regex
* Fix backtick edge case

Signed-off-by: Ajimelec Gonzalez <ajimelec@amazon.com>
…t#12319)

* feat(ppl-lint): add 3 structural rules (STRUCT-A)

Port invalid-capture-group-name, unsupported-window-function-in-eventstats,
and multisearch-min-subsearch from poc-ppl-linter-v3. All three are structural
rules with no context dependency — they fire the moment they merge.

- invalid-capture-group-name: flags Java-invalid regex group names in
  rex/parse/grok, with quick-fix suggestions (sanitize or convert Python opener)
- unsupported-window-function-in-eventstats: flags rank/dense_rank/ntile/etc
  in eventstats/streamstats (only row_number is supported)
- multisearch-min-subsearch: flags multisearch with fewer than 2 subsearches
  (runtime-only, minVersion 3.4.0)

Also adds DiagnosticFix interface to diagnostic.ts (additive, no consumers yet
on this branch — enables the capture-group quick-fix).

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* feat(ppl-lint): add 4 more structural rules + address review feedback

Add four rules ported from poc-ppl-linter-v3:

- disabled-join-type (warning): flags right/full/cross join types that are
  disabled unless plugins.calcite.all_join_types.allowed is set. Reachable on
  the compiled surface through the type=<keyword> option form; suppressed when
  the allJoinTypesAllowed setting is on.
- dedup-consecutive-unsupported (Calcite warning): flags dedup consecutive=true,
  which is not natively supported on Calcite and relies on engine fallback.
- union-min-datasets (runtime-only, Calcite, minVersion 3.7.0): flags union with
  fewer than two datasets. No-op on the compiled surface (unionCommand absent).
- replace-wildcard-asymmetry (runtime-only, Calcite, minVersion 3.4.0): flags a
  replace whose pattern and replacement have asymmetric, non-zero wildcard
  counts. No-op on the compiled surface (replacePair absent).

Also address PR review feedback on invalid-capture-group-name:

- Emit a dedicated message for an empty group name "(?<>...)" instead of the
  generic "Invalid capture group name """ text.
- Build the capture-group opener regex per call rather than sharing a global
  regex, removing any lastIndex state hazard.
- Add regression tests asserting the diagnostic and quick-fix ranges land on
  the exact column of the group name and the P character (the reported offset
  concern is not a real defect; the offsets are measured consistently from the
  token, quotes included).

Each rule is wired into detector_registry, rules_catalog.json, and the
query_enhancements uiSettings defaults. 134 lint tests pass; tsc and eslint
clean.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): widen empty-capture-group range + grok regression test

Address the persistent-review focus areas on the STRUCT-A rules:

- invalid-capture-group-name: for an empty name "(?<>...)", the diagnostic
  range previously covered only the closing ">"; widen it one column left so it
  spans the whole empty "<>" pair. Add a regression test asserting the range.
- Add a regression test confirming grok semantic names (typed "%{NUMBER:x:int}"
  and dashed "%{DATA:my-field}") are not flagged — the (?<name>) opener scan
  never matches %{...} syntax, so there is no false positive.
- replace-wildcard-asymmetry: document why countUnescapedWildcards runs on the
  raw getText() literal (it lints the escapes as written in the editor).

135 lint tests pass; tsc and eslint clean.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* refactor(ppl-lint): drop invalid-capture-group-name rule (quick-fix lands with opensearch-project#12298)

The invalid-capture-group-name rule was the only rule here that emitted a
DiagnosticFix, but this PR ships no code-action provider to render it — that
machinery (fix_registry + code_action_provider + registerCodeActionProvider)
lives on opensearch-project#12298. Rather than carry a rule whose quick-fix cannot surface and
duplicate the DiagnosticFix interface across two PRs, drop the rule and the
unused fix data model here; the rule can re-land alongside its quick-fix on
opensearch-project#12298.

Removes the detector, its tests, the catalog entry, the uiSettings default, and
the DiagnosticFix interface + Diagnostic.fix field from diagnostic.ts.

This PR now adds 6 structural rules. 123 lint tests pass; tsc and eslint clean.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): wire local-cluster version fallback and calcite settings into lint context

buildPPLLintContext now falls back to the grammar cache's resolved version
when the dataset metadata does not carry one (common on local clusters),
fixing Calcite-gated rules staying disabled on local datasets.

A new calcite_settings_cache module fetches and caches per-datasource
Calcite cluster settings, wiring allJoinTypesAllowed into the lint context
so that the disabled-join-type rule can be suppressed when the cluster
has all join types enabled.

Both caches notify the editor on resolution so lint context is refreshed
without a user-triggered revalidation.

Signed-off-by: Hanyu Wei <hanyuwei@amazon.com>
Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): fix prettier formatting for eslint 10 / prettier 3.9.4

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): address Joshua + Eric review on 6 structural rules

Fixes the three findings from Joshua's Claude Code review plus a gating
bug and a test-coverage gap surfaced while re-verifying Eric's comments.

J3 / P0-a — union-min-datasets fired an error on every valid mid-pipeline
union (`... | union [subsearch]`), where the upstream pipeline is the
implicit first dataset. Only enforce the >=2 check when the unionCommand is
query-initial (parent rule `pplCommands`); stay silent mid-pipeline. Uses a
positive gate so an unresolved parent defaults to not firing.

J2 / P0-b — disabled-join-type used a recursive joinType descendant search,
which on nested joins (`join type=inner b [ ... | join type=cross d ]`)
reported the nested keyword twice and masked the outer join's own type. Read
joinType only from each join's own direct `joinOption` children, matching the
grammar (`joinCommand : JOIN (joinOption)* ...`). The sqlLikeJoinType prefix
form is unchanged.

J1 / P0-c — all six detectors hardcoded `message` and ignored config.message.
Static rules now use config.message; the three interpolated rules move their
dynamic detail into hoverFacts (joinType, windowFunction, wildcard counts) and
the hover card renders those facts.

P1 — the Calcite settings cache warmup was gated behind
query:enhancements:runtimePplGrammar, so with the flag off the compiled-surface
disabled-join-type rule could never be suppressed by allJoinTypesAllowed. The
warmup handler now subscribes unconditionally (the grammar cache self-gates on
the flag internally); only the runtime validation provider stays gated.

P2 — add a product-path plumbing test that drives the runtime-only rules
through getBundledCatalog + the detector registry + runLint, so a catalog
disable, runtimeOnly-filter break, registry unregistration, or rule-name
divergence is caught (the prior tests exercised only bare detectors).

Also map the `@osd/monaco/ppl-lint` subpath to its Monaco-free source barrel
in the Jest config. The `@osd/monaco` barrel is globally jest.mock()'d, but
the subpath resolved to `target/` (blocked by modulePathIgnorePatterns), so
runtime_lint.test.ts could never load without a build. The mapped source
barrel depends only on antlr4ng/@osd/antlr-grammar/semver.

Adds nested-join, mid-pipeline-union, catalog-message, and settings-warmup
tests.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

---------

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>
Signed-off-by: Hanyu Wei <hanyuwei@amazon.com>
Co-authored-by: Hanyu Wei <weihanyu@amazon.com>
…pace, or tab (opensearch-project#12383)

* fix(workspace): split configUsers and configGroups string by comma or space

When configUsers or configGroups is a string (e.g. from YAML config),
split it by commas or whitespace so multiple values are handled correctly.

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* test(workspace): add tab delimiter test cases for configUsers and configGroups splitting

Signed-off-by: Hailong Cui <ihailong@amazon.com>

---------

Signed-off-by: Hailong Cui <ihailong@amazon.com>
* feat: add user/workspace setting page

Signed-off-by: yubonluo <yubonluo@amazon.com>

* update getAllUserProvidedWithScope name and test snapshot

Signed-off-by: yubonluo <yubonluo@amazon.com>

* optimize the code

Signed-off-by: yubonluo <yubonluo@amazon.com>

* use saveobject as the permission control source

Signed-off-by: yubonluo <yubonluo@amazon.com>

---------

Signed-off-by: yubonluo <yubonluo@amazon.com>
…#12380)

* fix(chat): serialize tool-result run to avoid ConcurrencyException (opensearch-project#11881)

  A frontend-tool round-trip dispatches a second run once the tool executes
  in the browser. When a parallel backend tool is still resolving, the first
  run still holds the thread, so dispatching the tool-result run hits the
  agent server's per-thread concurrency guard and throws ConcurrencyException.

  Wait for other active runs to drain (bounded, best-effort) before
  dispatching the tool-result run, serializing the two runs instead of
  racing them.

  Fixes opensearch-project#11881

Signed-off-by: cicimiao31 <cicimiao31@gmail.com>

* Prioritize AG-UI routing over ML Commons in proxy

Signed-off-by: YiyuanMiao <miaoyiyuan31@gmail.com>

---------

Signed-off-by: cicimiao31 <cicimiao31@gmail.com>
Signed-off-by: YiyuanMiao <miaoyiyuan31@gmail.com>
Co-authored-by: cicimiao31 <cicimiao31@gmail.com>
…ect#12375)

- Dashboard URLs now store only variable selections as { id, current }.
- Full variable definitions stay in saved dashboard variablesJSON.
- URL selections are hydrated back onto saved/current variables by id.
- Deleted or unknown URL variables are ignored.

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
…mponent 0.5.0 (opensearch-project#12366)

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
…rch-project#12333)

Renders tool results by shape (JSON, {text=...} wrappers, tables,
markdown, plain text). Centralizes truncation in CodeBlock only;
MarkdownBlock never truncates. .text extraction requires the object
have no other keys, to avoid dropping sibling fields.

Signed-off-by: Lin Wang <wonglam@amazon.com>
…saved_search_in_dashboards -> ciGroup 16) (opensearch-project#12389)

Move two mis-bucketed explore Cypress specs into feature-coherent ciGroups
so each group maps to a single feature area:

- ai_editor.spec.js: 10 -> 19 (ciGroup 19 groups AI features alongside
  results_summary.spec.js)
- saved_search_in_dashboards.spec.js: 12 -> 16 (ciGroup 16 groups dashboard
  integration tests: add vis/log to dashboard, download CSV from dashboard)

Both are pure git renames. Source and target directories are at the same
relative depth, so imports are unchanged. The ciGroup scripts in package.json
glob each bucket directory (explore/<n>/*.spec.js), so they pick up the moved
files automatically with no workflow or package.json changes required.

Histogram specs are intentionally left in ciGroup 14 as Discover features.

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
Signed-off-by: Adam Tackett <tackadam@amazon.com>
Co-authored-by: Adam Tackett <tackadam@amazon.com>
* chore(deps): jest 30.4.2

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore: jest-30-migration-recipe codemod

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* test: adjust tests to jest 30 and jsdom 26 part1

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* test: add jest-location-mock

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* test: adjust

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* fix: add MIT-0 license as allowed, tests adjustments

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* fix: dependencies cleanup

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* test: adjust after rebase

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

---------

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
)

* chore(ppl-lint): re-trigger CI (flaky cypress ciGroup23Explore)

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* feat(ppl-lint): command-typo quick-fix + unknown-field rule

Adds the quick-fix subsystem with two fix producers, exercising the
lightbulb on both marker channels end-to-end:

1. Command-typo suggestion (syntax channel) — replaces ANTLR's noisy
   "mismatched input ... expecting {N keywords}" with "Did you mean
   'where'?" plus a one-click rewrite. Fires on both the compiled-worker
   path (ppl_error_listener) and the runtime ParserInterpreter path
   (new PPLCommandErrorListener).

2. field-validation lint rule (lint channel) — flags unknown field
   references and the Splunk-style `grok field=body` shape error, each
   with a quick-fix ("Replace with '<field>'" / "Remove field=").

Quick-fix infra: fix_registry side tables (lint + syntax channels,
keyed by the marker fields Monaco's MarkerService preserves) and a
code_action_provider that routes by marker source. markerFixKey moves
to fix_registry (canonical owner); hover_registry re-exports it.

Field context: minimal fields-only plumbing — LintFieldsCache,
3-arg buildPPLLintContext, and a loadFields effect in both hosts
(query_editor + explore use_query_panel_editor) that walks
indexPattern.fields into a Set. No server route, no version coupling.
field-validation self-suppresses until fields load. The plumbing makes
the sibling needsContext rules ~1 catalog line each; omitting them here
is a scoping choice.

Catalog/ui_settings/doc_links parity kept in lock-step (field-validation
added to all three). GeneralErrorListener widened backward-compatibly
(trailing optional RecognitionException + optional code/fix) so the SQL
/DQL/autocomplete callers are unaffected.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* ci: retrigger after transient Cypress download timeout

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): don't flag the source/index keyword as an unknown field

Live verification against a sub-3.6 cluster (OpenSearch 2.19) surfaced a
false positive: on the compiled-simplified grammar, `source=idx` /
`index=idx` parses the leading `source`/`index` keyword into a
fieldExpression (the runtime >=3.6 grammar instead parses it as a
fromClause, which field-validation already excludes). Because Group D
wires `fields` into the compiled-worker lint context, field-validation
now runs on that surface and emitted a spurious `Unknown field "source"`
on essentially every source-first query against a sub-3.6 cluster — the
dominant query shape in the editor's compiled-fallback path.

Skip the `source`/`index` fromClause keyword in the existence pass. The
shape pass already defers on the compiled surface, and >=3.6 clusters are
unaffected (the runtime grammar excludes the fromClause). Real unknown
fields on source-first queries are still flagged. Adds 4 regression cases.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): validate eval RHS + guard cast target type

The field-validation existence pass excluded the entire `evalClause` subtree
via ancestor-matching, so a typo in an eval value expression
(`eval x = nonexistent + 1`) was never flagged even though the eval target is
already protected by `createdFields`. Drop `evalClause` (and the dead
`renameClasue`/`renameClause` entries) from the excluded-ancestor set so the RHS
is walked like a `where` clause; the created-field name slot stays safe via
`createdFields`.

Separately, `collectCreatedFields` added the node after any `AS` terminal to the
created-field set, so `cast(field AS int)` registered the target type name as a
field — silently accepting a later reference to it. Skip the `AS` slot when the
following node is a `convertedDataType`.

Also convert the touched `stack.pop()!` non-null assertions to the guard form.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): scope alternate-source field creation to its own pipeline

`buildPipelineShape` collected created fields from every command stage,
including stages nested inside an alternate-source subtree
(`append [search ...]`, subsearch, lookup, appendcol, union). A field created
by an eval inside `append [...]` therefore leaked into the outer pipeline's
known-field set, silently accepting a downstream reference to it.

Prune alt-source stages when collecting created fields, reusing the same
`collectAlternateSourceSubtrees` set the reference pass already prunes against.
Extract the ancestor-walk into a shared `isInsideAltSource` helper so
`buildPipelineShape` and `head_without_sort` prune identically instead of each
inlining the same closure.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): don't suggest a command for sub-threshold-length tokens

`suggestCommand` used an edit threshold of 1 for short tokens, so a single
stray character (`source=logs | a`) was distance 1 from any 2-char command
(`ad`, `ml`) and got "corrected". The structured suggestion then replaced
ANTLR's real diagnostic and attached a misleading quick-fix while the user was
mid-typing a fresh command.

Add a length floor: a token must be strictly longer than the edit threshold to
be considered a typo — rewriting 100% of a token to reach a command is a guess,
not a correction.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): honor configured severity in field-slot shape pass

The existence pass emitted at `config.severity`, but the field-slot shape pass
hardcoded `severity: 'error'`. A user who set field-validation to `warning`
still saw red errors from the shape pass. A rule has one catalog entry and one
user-facing severity toggle, so the shape pass must follow it; use
`config.severity`.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): only skip source/index keyword on the compiled surface

The existence pass unconditionally skipped any field reference whose text was
`source`/`index`, so a real field literally named `source` or `index` was never
validated on any surface. The skip is a compiled-simplified-grammar workaround:
there `source=idx` misparses the keyword into a fieldExpression. On the runtime
bundle `source=idx` is an excluded fromClause, so a fieldExpression named
`source`/`index` is a genuine reference.

Gate the skip on `grammarSurface !== 'runtime-bundle'`, which keeps the
workaround on the compiled and test/fallback paths (no surface set) while
restoring real validation of those field names on the modern surface.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): guard syntax highlighting against stale async results

`processLintHighlighting` already drops a slower, earlier pass whose response
resolves after a newer one (generation counter + content/dispose checks).
`processSyntaxHighlighting` had no such guard: it awaited the validation result
and wrote markers/fixes unconditionally. Multiple triggers (dataset change,
loadFields resolve, content change) call revalidatePPLModel, so two in-flight
validations can race and the stale one resolving last clobbers newer markers —
leaving a stale command-typo fix range pointing into outdated text.

Add a dedicated `syntaxGenerations` guard mirroring the lint path, with matching
cleanup on model dispose and on provider teardown.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): robust join-alias collection across grammar surfaces

`collectJoinAliases` used `findAllChildrenByRule` (direct children only) to find
the `qualifiedName` under each `sideAlias`. If a grammar surface nests that
`qualifiedName` below an intermediate rule, the alias set comes back empty and
every join-alias reference (`| where l.response = 200`) is false-flagged. The
join-alias tests only run on the compiled surface, so this risk is untested on
the runtime surface today.

Switch to `findAllDescendantsByRule`. A `sideAlias` wraps exactly one alias
identifier, so descending cannot over-collect; the change is strictly more
robust across surfaces.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* refactor(ppl-lint): unify edit-distance on Damerau-Levenshtein

The command suggester used Damerau-Levenshtein (transpositions cost 1) while the
field suggester used plain Levenshtein (transpositions cost 2, compensated by a
wider threshold) — two near-identical sweeps that differed only by which typo
class they ranked well. Extract a shared `edit_distance` module exposing
`damerauLevenshtein` and a `nearestWithinThreshold` helper, and route both
`suggestField` and `suggestCommand` through it. Delete the plain `levenshtein`
implementation; both callers now rank transposition typos closer at no extra
cost. `command_suggestion` re-exports `damerauLevenshtein` so existing importers
are unaffected. Behavior is preserved (verified by the existing suggester tests,
including the distance-0 case-preference case).

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): collision tripwire + hot-path tidy + shared field extraction

Three non-behavioral cleanups bundled:

- Add a dev-only `console.warn` in the lint marker-capture loop when a
  markerFixKey would be overwritten with a different fix. Today separate fix
  tables and suppressContained prevent collisions, so this is a latent tripwire;
  the dead branch is stripped from production bundles.
- Replace the per-keystroke `new Set([...fields, ...createdFields])` merge in the
  field-existence pass with a two-set membership test (`isKnown`); the cold
  suggestion path materializes the union inline.
- Extract `extractFieldNames` into lint_context_builder and route both the data
  query_editor and the explore use_query_panel_editor loadFields effects through
  it, replacing two copies of the same loop. The data copy gains the
  `!indexPattern` guard the explore copy already had.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): lint best-effort on the runtime surface even when parsing errors

`buildRuntimeTree` discarded the entire parse tree whenever the runtime
`ParserInterpreter` reported any syntax error, so `lintRuntimePPLQuery` returned
no diagnostics for the whole query. This silently disabled all linting for
queries the deserialized runtime ATN can't fully parse even though they are
semantically valid to the engine (e.g. `eval x = <field> + 1`), and for any
otherwise-valid query with a trailing unparseable command.

ANTLR's error recovery still produces a usable partial tree, and the lint rules
already walk it best-effort. The compiled fallback path (`PPLLanguageAnalyzer.lint`)
never discards a tree, so the runtime path was the outlier. Keep the recovered
tree; only a thrown exception (no tree at all) now suppresses linting.

Browser-verified against a live 3.8 runtime grammar bundle: `eval x = nonexistent
+ 1` now flags the unknown RHS field where it previously produced nothing.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): register extraction-command created fields

The field-validation existence pass unions index fields with fields
created upstream, but collectCreatedFields never registered the fields
that grok/parse/rex/patterns/spath produce. Any downstream reference to
an extracted field was therefore false-flagged as an unknown field once
a real index field set was present.

Add a dependency-free pattern_fields module that extracts created names
from a pattern string (grok %{SYNTAX:name}; Java (?<name>) groups filtered
by the engine's charset rules — no underscore for parse/rex), and three
branches in collectCreatedFields:
  - grok/parse/rex: names from the pattern string literal
  - patterns: NEW_FIELD name + default patterns_field + companion tokens
  - spath: OUTPUT name or path-derived field (INPUT left validated)

Because buildPipelineShape here scopes collectCreatedFields to
non-alternate-source stages, a field extracted inside an `append
[search ...]` subquery does NOT leak into the outer known-field set — an
outer reference to it is correctly flagged (regression test added).

Verified live against the Calcite 2.19 and runtime 3.6 engines. The two
disagree on patterns output naming (2.19 honors NEW_FIELD and emits a
tokens column; 3.6 ignores NEW_FIELD and always emits patterns_field), so
the patterns branch registers the union to stay correct on both.

field_validation.ts is unchanged. No grammar changes.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): don't register a join table alias as a created field

`collectCreatedFields` treated any node after an `AS` terminal (except a
cast's `convertedDataType`) as a created field. On a top-level
`join departments AS d`, the `AS` sits under `tableSourceClause` and binds
`d` as a *table* alias, not a column on the outer source — so `d` leaked
into the pipeline's known-field set and silently suppressed a real
"Unknown field" warning on a downstream reference to a field named `d`.
(The `lookup ... AS d` shape was already safe: lookupCommand is pruned by
collectAlternateSourceSubtrees, so collectCreatedFields never runs on it.)

Skip an `AS` whose immediate container is a table/source-alias context,
reusing the same vocabulary field_validation's existence pass already
excludes (tableSourceClause / tableSource / tableQualifiedName /
sourceReference / sideAlias). Legitimate column-minting `AS` (stats
`... AS mean`, rename target, eval LHS) is unaffected. Adds a regression
test; verified the test fails without the fix.

Also two low-risk hardenings surfaced in review:
- offendingFollowsPipe: bound tokenIndex by stream.size so a recovery-
  synthesized out-of-range index can't drive an out-of-bounds lookback.
- edit_distance: document the three-row rolling rotation invariant.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): apply quick-fix even after the model version changes

The lint/command-typo quick-fix lightbulb did nothing when clicked. The
code-action provider stamped each workspace edit with the model's
versionId captured at the moment the action was computed. Monaco's
bulk-edit service rejects an edit whose versionId no longer matches the
model ("bad state - model changed in the meantime") and the standalone
editor's notification service swallows the error — so the button was a
silent no-op.

In the live editor the model version advances between computing the
action and the user clicking it: the debounced re-lint, re-tokenization,
and autocomplete all bump it. So the stale versionId virtually always
mismatched by click time. It never reproduced in the jest unit tests
because nothing there churns the version.

Omit versionId (pass undefined), which skips the guard. The fix range is
absolute, so applying without the version check is safe. Verified in a
browser against the built bundle: emulating Monaco's exact bulk-edit
guard, a pinned-version edit is rejected after version churn while the
undefined-version edit applies. Adds a regression test asserting the
provider never pins a versionId.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): load Monaco codeAction contribution so quick-fixes apply

The lint/command-typo quick-fix lightbulb rendered nothing and clicking it
was a silent no-op. osd-monaco's `monaco.ts` imports individual Monaco editor
contributions (suggestController, hoverContribution, parameterHints,
formatActions, comment) but never the codeAction one. So
`monaco.languages.registerCodeActionProvider` stored the PPL provider (the fix
even showed up in the side-table registry, and hover worked) while the module
that renders the lightbulb widget and registers the `editor.action.quickFix`
command was never loaded — there was no UI to invoke the provider.

Import `contrib/codeAction/browser/codeActionContributions` (the same module
the canonical `editor.all` bundle loads; it registers CodeActionController,
LightBulbWidget, and QuickFixAction). Browser-verified against the built
bundle: pre-fix the editor threw "command 'editor.action.quickFix' not found"
with no widget; after the fix the lightbulb renders and clicking "Replace
with 'balance'" rewrites `balnce` -> `balance` in place.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): generalize field-slot message and default field-validation to error

Two related field-validation adjustments:

- The field-slot shape message hardcoded "PPL does not use Splunk-style
  'field=' syntax", but the pass fires on ANY non-bare-field shape — a bare
  comparison (`grok status > 200`), a literal, or arithmetic — not only
  `field=`. The Splunk framing misdescribes those cases. Drop it; the message
  is now just "<cmd> expects a field name here, not an expression." A test
  asserts the message no longer mentions Splunk.

- Default field-validation severity warning -> error in both the catalog and
  the query_enhancements per-rule defaults (kept in lock-step). An unknown
  field or a Splunk-style field slot is not a stylistic heads-up: the query
  will fail at the engine, so error is the right default. Still user-toggleable
  via the per-rule uiSetting; the pass continues to honor config.severity.

Browser-verified on the live runtime-grammar surface: `grok field=url` and
`grok status > 200` both surface the generic message at severity Error, and
`where balnce > 1` now reports Error with the "Did you mean balance?" fix.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* docs(ppl-lint): explain shouldUseRuntimeGrammar's optimistic version gate

`shouldUseRuntimeGrammar` returns true for an unknown version while
`shouldFetchFromBackend` returns false — which reads like a bug but is
deliberate. The former is a synchronous render-time gate that cannot resolve
the version (local needs an async /api/status call, remote an async
saved-object read), so it optimistically prefers runtime and lets the async
warmUp -> resolveVersion -> shouldFetchFromBackend chain make the real
decision. If the grammar can't load, the runtime lint/validate paths return
null and the editor falls back to the compiled grammar. Add a comment so this
isn't "fixed" to return false on unknown version, which would break the local
cluster whose version is only knowable asynchronously.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* feat(ppl-lint): make the command-typo suggestion toggleable via uiSetting

The command-typo suggestion ("Unknown command 'wherre'. Did you mean 'where'?"
+ quick-fix) had no user control, unlike the lint rules. It runs on the syntax
channel (it rewrites ANTLR's raw parse error), not as a tree-walking lint rule,
so it isn't in the lint catalog. Add a `command-suggestion` entry to the
existing "PPL lint rules" uiSetting so it sits alongside the rules, plumbed
through the syntax path rather than the catalog.

- ui_settings: add `{ id: 'command-suggestion', enabled: true }` to the
  defaults and make `severity` optional in the schema (this toggle carries no
  severity — it inherits the syntax error's).
- lint_overrides: `isCommandSuggestionEnabled(uiSettings)` reads the flag
  separately from the catalog-iterating override builder. Defaults to enabled;
  only an explicit `enabled: false` turns it off.
- lint_context_builder: carry `commandSuggestionEnabled` on the lint context.
- language.ts (syntax marker builder): when disabled, revert an UNKNOWN_COMMAND
  error to ANTLR's raw message and drop the quick-fix. To make "off" the true
  original behavior, the error listeners now preserve ANTLR's `rawMessage`
  alongside the friendly rewrite (both the compiled PPLSyntaxErrorListener and
  the runtime PPLCommandErrorListener), threaded through PPLValidationResult.

Gating on the client (where both the compiled-worker and runtime validation
paths converge) avoids plumbing the flag into the Web Worker. Unit tests cover
the setting schema/defaults, the reader, the context wiring, and the syntax
marker gate; browser-verified on the live editor: enabled -> "Did you mean
'where'?" + fix; disabled -> "mismatched input 'wherre'..." with no fix.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): retrigger CI

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): gate command suggestion on global lint flag and key field cache on data source

Address two review findings from Eric on PR opensearch-project#12298:

1. The command-typo suggestion enhancement (friendly message rewrite + quick-fix
   lightbulb) was not gated on the global `isPPLLintEnabled()` flag. When lint
   was disabled via `queryEnhancements.ppl.lint.enabled`, the suggestion still
   fired because the per-context toggle defaulted to true when no context was
   pushed. Now the syntax path checks isPPLLintEnabled() first; when off, users
   see the raw ANTLR error with no enhancement.

2. The field-validation cache matched only on dataset id. If two different data
   sources happened to share a dataset id, stale fields could be reused. Now the
   cache stamps and checks `dataSourceId` alongside `datasetId` in both the data
   plugin query_editor and the explore use_query_panel_editor hooks.

Signed-off-by: Hanyu Wei <hanyu@amazon.com>
Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): retrigger CI

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* feat(ppl-lint): fire field-validation shape pass on the compiled surface

field-validation's field-slot shape pass (grok/parse/patterns field=body)
was runtime-only: it hard-returned [] on the compiled-simplified grammar,
where `field=body` error-recovers and can't be read off the parse tree. The
existence pass already fired there, but the shape pass did not, so sub-3.6
clusters got at most a raw syntax squiggle instead of an actionable finding.

Add a narrow, comment/quote-aware text-side scanner
(findCompiledFieldSlotShapeMatches) that recognizes exactly the one
backend-accepted `grok|parse|patterns field=<bareField>` typo from the raw
query, and route the compiled surface to it via a new sourceText field on
LintRunContext (set by PPLLanguageAnalyzer.lint). The compiled emit honors
config.severity (catalog default error) so the rule keeps a single severity
toggle across both grammar surfaces.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): reformat PPL files for prettier 3.9.4

The main merge (opensearch-project#12340) upgraded prettier 2.1.1 -> 3.9.4 and eslint 10.6.0,
but the branch-new PPL files pre-date that reformat, so `yarn lint` failed on
16 prettier/prettier errors in six of them. Apply the prettier-3 formatting
(strip redundant `(x as unknown)` cast parens, wrap mixed `??`, nested-ternary
indentation, multiline type-cast layout). Formatting only, no behavior change.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): tighten pattern-field regex and validate override severity

Backport two correctness fixes from poc-ppl-linter-v3 (1d1fd25).

1. extractCreatedFieldNames used a greedy `(?<([^>]*)>` opener that
   consumed across a preceding lookbehind and never matched the real
   named group, so a field a parse/rex/grok pattern creates (e.g.
   `(?<=user_)(?<username>\w+)`) was dropped from field-validation's
   allowlist and then falsely flagged as an unknown field. Tighten the
   name charset to `[A-Za-z][A-Za-z0-9]*` so the regex cannot start on a
   `(?<=` / `(?<!` opener and never skips a real group.

2. buildOverridesFromSettings applied any stored severity string. An
   unknown value (reachable via the raw uiSettings API) makes
   `SEV_RANK[...]` undefined, so the MIN_SEVERITY floor comparison is
   false and the junk value slipped past the clamp that protects
   error-level rules. Ignore severities that are not real levels.

Adds regression coverage for both (each new test fails on the pre-fix
code and passes after).

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): normalize backtick-quoted created field names

field-validation false-flagged backtick-quoted created/derived fields as
"Unknown field": references were normalized per dotted segment (unquoteIdent)
but the created-field registration stored the raw getText() including
backticks, so a valid query like

    source=t | eval `total` = age * 2 | where `total` > 100

flagged `total`. Five identifier slots had this asymmetry: stats/rename/etc.
AS aliases, eval LHS, spath OUTPUT, the spath path fallback, and join side
aliases (`left=`l``).

Route both sides through a single shared normalizeFieldName helper (exported
from pipeline_shape) so the created-field and reference sides can never drift.
The helper strips one enclosing quote pair per dotted segment; single/double
quotes are stripped too (created names only — e.g. `rename age as 'years'`),
which is one-directional since references can only be backtick-quoted.

Also correct stale docs: the field-validation docstring and a test mock said
severity `warning`, but the catalog default was deliberately set to `error`
in an earlier commit. No behavior change — catalog and uiSettings defaults are
untouched; the rule stays user-downgradable via its per-rule uiSetting.

Adds regression coverage for both reported repros plus rename/stats-alias,
join-alias, and spath OUTPUT backtick cases, a mixed-quoting case, a negative
control, and suggestion hygiene.

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* fix(ppl-lint): sync doc links with structural rules

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

* chore(ppl-lint): retrigger CI after rebase

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>

---------

Signed-off-by: Hanyu Wei <weihanyu@amazon.com>
Signed-off-by: Hanyu Wei <hanyu@amazon.com>
Co-authored-by: Hanyu Wei <weihanyu@amazon.com>
…rch (opensearch-project#12408)

Make getTimeFilterWhereClause engine-aware: emit bare string literals for
OpenSearch (which fold to native Lucene range queries) and only wrap in
TIMESTAMP('...') for legacy Elasticsearch/Open Distro engines that reject
bare strings.

On OpenSearch, `field >= TIMESTAMP('...')` cannot be folded to a native
range query because the RHS is a function expression, so it is pushed down
as a per-value `opensearch_query_expression` script filter. Each unique
timestamp compiles a new script and quickly exhausts the cluster-wide
`script.context.filter.max_compilations_rate` limit (default 75/5m),
producing `CircuitBreakingException` errors in classic Discover. Emitting a
bare string lets the optimizer produce a native range query with zero script
compilations, while Elasticsearch keeps the TIMESTAMP() wrapper it requires.

Signed-off-by: Suchit Sahoo <suchsah@amazon.com>
Signed-off-by: Suchit Sahoo <suchsah@amazon.com>
…arch-project#12410)

* [Explore] Warn when saving a complex query as a visualization

Adds an `explore.queryProfiling.enabled` feature flag (default off). When it is
enabled, the Explore save windows -- the top-nav Save modal, the Add to dashboard
modal, and the in-context Save-as-visualization modal -- show a warning banner
telling the user the query is complex: it can use significant cluster resources and
re-runs on every dashboard load and refresh. The banner is informational and the
Save / Add action is unchanged.

The banner reuses each modal's existing EuiCallOut pattern and the shared
SavedObjectSaveModal `options` slot, so the save flow itself is untouched.

The per-query "complex" signal will come from query profiling; until that is wired
the banner is shown whenever the flag is enabled (see the TODOs at the call sites).

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* Add changelog fragment for opensearch-project#12410

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Gate the complex-query warning on query profiling

Wires the complex-query warning banner to the real per-query signal from query
profiling, replacing the feature-flag placeholder.

- When `explore.queryProfiling.enabled` is on, Explore sends `profile: true` on the
  PPL query (query_actions.ts -> data plugin Query.profile -> query_enhancements facet.ts).
- The PPL search strategy reads the backend's `profile.thread_pool` from the response
  body and surfaces `isComplex` (true for the `sql-complex-worker` pool) on the data
  frame meta.
- executeQueryBase captures `isComplex` into the results slice; the three save windows
  gate the banner on the stored value for the query being saved (via useIsQueryComplex,
  and the store for the non-component top-nav Save handler).

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Allow the profile flag in the query-enhancements search route schema

The search request body validated `query` strictly, so the `profile` flag added for
query profiling was rejected ("definition for this key is missing") on every query.
Allow it as an optional boolean.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Show the complex-query warning in the in-context visualization editor

The in-context editor (create/edit a visualization from within a dashboard) runs on its
own query-builder state with no Redux Provider, so it reads the complex signal from its
own result observable rather than the Explore results slice:

- Capture `isComplex` from the data frame meta into the editor's query result
  (query_builder/utils.ts), mirroring executeQueryBase.
- SaveVisButton reads `resultState.isComplex` via useQueryBuilderState and shows the
  banner in its save modal.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Guard complex-query detection against unpopulated query state

The save-window complex-query warning reads the Redux store and query
slice to decide whether to show the banner. When the store or query
state is not yet populated, these reads threw and broke the save
button (surfaced by the existing add_to_dashboard_button and
top_nav_save unit tests). The banner is a non-critical enhancement, so
guard both read sites to degrade to 'no banner' instead of throwing.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Reword complex-query warning to drop 'cluster'

Reword the save-window warning banner from 'significant cluster
resources' to 'resource-intensive' so the message reads clearly for
users regardless of deployment terminology.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Add runtime advanced setting to toggle query profiling

Add an 'Enable query profiling' advanced setting (explore:enableQueryProfiling,
default off, category explore) so admins can turn the complex-query warning
on/off at runtime from /app/settings without a config change. The setting is
registered by the Explore plugin, so it only appears when Explore is enabled.

Profiling now requires BOTH the deployment-level config gate
(explore.queryProfiling.enabled) AND the advanced setting: the outgoing
profile:true flag is sent only when both are on. The setting is read live at
query execution time so the toggle takes effect on the next query. When the
config gate is off the setting has no effect, keeping the feature off by
default.

Adds unit tests for the setting registration and the combined gate.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Remove the query profiling advanced setting; keep the config flag

Drop the explore:enableQueryProfiling advanced setting and its runtime
gate, reverting to a single deployment-level switch: the
explore.queryProfiling.enabled config flag. Operators who want to drive
it from the UI can use the native uiSettings.overrides mechanism.

Also removes the now-redundant comment on Query.profile.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Limit query profiling to PPL queries

createSearchSourceWithQuery is shared across languages, so gating the
profile flag on the config flag alone also sent it on SQL/PROMQL
queries. Only PPL runs on the complex worker pool the profile response
reports on, and the extra field is meaningless (and can affect engine
selection on some backends) for other languages. Gate on
preparedQuery.language === 'PPL' as well as the flag.

Addresses review feedback on opensearch-project#12410.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

* [Explore] Nest query profiling result under a profile object

Group the profiling signal under a `profile` object (QueryProfile) on
the data frame meta and the search result, instead of exposing
`isComplex` as a top-level attribute, so future profiling fields stay
nested together. Readers now go through `profile?.isComplex`.

Addresses review feedback on opensearch-project#12410.

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>

---------

Signed-off-by: Jialiang Liang <ryanleeang@gmail.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
opensearch-project#12421)

* Change the allowed title length to 64 to comply with the collection title length

Signed-off-by: Ella Zhu <zhyuanqi@amazon.com>

* fix tests

Signed-off-by: Ella Zhu <zhyuanqi@amazon.com>

---------

Signed-off-by: Ella Zhu <zhyuanqi@amazon.com>
…1.7.6, diff 8.0.4 (opensearch-project#12406)

* chore(deps): puppeteer 24.43.1, ws 8.21.1

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): mocha 11.7.6

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): body-parser 2.3.0

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* chore(deps): diff 8.0.4

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

* fix: ensures id never shorter than 9 chars as test expects

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>

---------

Signed-off-by: Tomasz Kania <tomasz.kania@pl.ibm.com>
- Bump @elastic/charts 31.1.0 -> 71.8.1 (root package.json and
  osd-ui-shared-deps). This also pulls uuid ^14, removing the
  vulnerable uuid 3.x and resolving CVE-2026-41907.
- postinstall.js: patch charts dist/theme.scss for constructs that
  OUI 1.22.1 / Dart Sass reject: euiFocusRing(null, 1) (OUI's mixin
  takes a single arg) and legacy $euiSizeXS division.
- Discover histogram: deep-clone the charts default theme before
  applying overrides, since the theme object is frozen in charts >=71
  (fixes 'Cannot assign to read only property axisTitle' crash), and
  set timeAxisLayerCount=0 to keep the single-row time axis so the
  existing tickFormat drives x-axis labels.

Signed-off-by: Justin Kim <jungkm@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.