Skip to content

[ES|QL Controls] Refresh "Values from a query" options on dashboard reload#225101

Merged
Zacqary merged 55 commits intoelastic:mainfrom
Zacqary:222198-esql-control-rt
Jun 30, 2025
Merged

[ES|QL Controls] Refresh "Values from a query" options on dashboard reload#225101
Zacqary merged 55 commits intoelastic:mainfrom
Zacqary:222198-esql-control-rt

Conversation

@Zacqary
Copy link
Contributor

@Zacqary Zacqary commented Jun 24, 2025

Summary

Closes #222198

For "values from a query" ES|QL controls, attempts to execute the query again on dashboard page load, refresh, timerange change, etc. to get an up-to-date list of values.

If the query execution fails, values cached at the previous edit time will be used.

Checklist

@Zacqary Zacqary added Feature:Dashboard Dashboard related features release_note:fix Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas t// loe:medium Medium Level of Effort impact:critical This issue should be addressed immediately due to a critical level of impact on the product. backport:all-open Backport to all branches that could still receive a release labels Jun 24, 2025
}
};

esqlQueryToOptions.isSuccess = (result: unknown): result is ESQLControlOptionsSuccess =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think glomming a type guard for the result onto the function itself is an elegant way to save space and imports but if this is too galaxy brain javascript to be a sustainable pattern, I'm open to changing this.

@Zacqary Zacqary marked this pull request as ready for review June 24, 2025 22:27
@Zacqary Zacqary requested review from a team as code owners June 24, 2025 22:27
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-presentation (Team:Presentation)

ESQLVariableType,
} from '@kbn/esql-types';
import { PublishingSubject, StateComparators } from '@kbn/presentation-publishing';
import { esqlQueryToOptions } from '@kbn/presentation-controls';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this placed in a package? What are the future plans for this package and method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make this method available to the esql plugin and controls plugin without creating any new cross-dependencies, because in my experience that eventually leads to circular dependency hell. I wasn't able to find an existing kbn package that seemed to fit.

If we're going to work on combining the UI components for classic and ES|QL controls, I expect we're going to run into more cases like this.

Copy link
Contributor

@nreese nreese Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. That makes sense.

Why does it need its own package and is that it important that it it has presentation-controls namespace? Would it be better to place in an existing esql package like esql-utils? That way, all esql logic is located in a single location.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can move it to esql-utils and hold off on creating a new package for controls until we've got a larger use case.

Copy link
Contributor

@nreese nreese Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure we need to move it. I only want to have the discussion and understand the why. If there are no plans that would require a separate package and no design reasons, then we can have the conversation about moving it into an existing package.

@stratoula
Copy link
Contributor

I think this will create conflicts with #225054 but it should be easy to solve, let me know if you need any help

Copy link
Contributor

@stratoula stratoula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didnt go through the code but I would like to raise a concern about this feature mostly due to how ES|QL works and returns results

Let'say that the user types a query like this:

FROM logs* | STATS BY agent.name | LIMIT 5

This returns 5 values (one is null and we dont allow it)
image

Now every time you refresh your dashboard this list changes

and can change so much that the selected value is not part of the list anymore

image

which can be weird. This happens due to the randomness of the data retrieval especially for datasets with sparse data.

A user can improve that with sorting etc but it something I wanted to raise with you before we move on with this functionality cc @ghudgins

Zacqary and others added 2 commits June 25, 2025 10:56
# Conflicts:
#	src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.tsx
@Zacqary Zacqary enabled auto-merge (squash) June 27, 2025 18:29
availableOptions$.next(result.values);
}
}
const fetchSubscription = controlFetch$.subscribe(updateAvailableOptions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a race condition. If updateAvailableOptions does not return before controlFetch$ fires again and updateAvailableOptions from the second emit returns first, then updateAvailableOptions from the first emit will overwrite the options. to solve this, you should use a switchMap

  const fetchSubscription = controlFetch$.pipe(
  filter(() => controlType$.getValue() === EsqlControlType.VALUES_FROM_QUERY)
  switchMap(async (fetchContext) => {
    return await getESQLSingleColumnValues({
      query: esqlQuery$.getValue(),
      search: dataService.search.search,
      timeRange: fetchContext.timeRange,
    });
  }),
).subscribe(results => {
  if (getESQLSingleColumnValues.isSuccess(results)) {
      availableOptions$.next(result.values);
    }
});
export function initializeESQLControlSelections(
initialState: ESQLControlState,
controlFetch$: ReturnType<ControlGroupApi['controlFetch$']>,
timeRange$?: PublishingSubject<TimeRange | undefined>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to pass in timeRange$, its provided by controlFetch$

@Zacqary
Copy link
Contributor Author

Zacqary commented Jun 27, 2025

@stratoula Had a conversation with @ThomThomson and we've decided just to apply these changes to the controls plugin for now since we need to get this PR merged urgently. This duplicates some of the functionality the editor flyout already uses, but we'll resolve that in a follow-up.

return { values };
}

return { columns, errors: [] };
Copy link
Contributor

@nreese nreese Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand why the function would return columns when there are more then one? Would this be an error case? What consumer would use this response? Would it be better to just throw an error if multiple columns are returned?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flyout UI needed this because it needs to populate a dropdown list of possible columns in the error state. I can remove it for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm anticipating we'll need this again in a followup PR so I'm going to keep the values/errors key value schema in the return type

Copy link
Contributor

@nreese nreese left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kibana-presentation changes LGTM after fixing last few comments in test. Thanks for cleaning everything up
code review only

search: searchMock,
})) as GetESQLSingleColumnValuesSuccess;
expect(getESQLSingleColumnValues.isSuccess(result)).toBe(true);
expect('columns' in result).toBe(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

columns is no longer in response so this expect is not needed.

}
`);
});
it('returns columns and empty error on successful query that returns multiple columns', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about renaming to 'returns error when query returns multiple columns'?

@Zacqary Zacqary merged commit 215a4bf into elastic:main Jun 30, 2025
10 checks passed
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.17, 8.18, 8.19, 9.0, 9.1

https://github.com/elastic/kibana/actions/runs/15979438288

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
controls 357 384 +27

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
controls 473.1KB 477.7KB +4.6KB

History

kibanamachine added a commit to kibanamachine/kibana that referenced this pull request Jun 30, 2025
…eload (elastic#225101)

## Summary

Closes elastic#222198

For "values from a query" ES|QL controls, attempts to execute the query
again on dashboard page load, refresh, timerange change, etc. to get an
up-to-date list of values.

If the query execution fails, values cached at the previous edit time
will be used.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
(cherry picked from commit 215a4bf)
@kibanamachine
Copy link
Contributor

💔 Some backports could not be created

Status Branch Result
8.17 Backport failed because of merge conflicts
8.18 Backport failed because of merge conflicts
8.19 Backport failed because of merge conflicts
9.0 Backport failed because of merge conflicts
9.1

Note: Successful backport PRs will be merged automatically after passing CI.

Manual backport

To create the backport manually run:

node scripts/backport --pr 225101

Questions ?

Please refer to the Backport tool documentation

@Zacqary Zacqary added backport:version Backport to applied version labels v9.1.0 v8.19.0 and removed backport:all-open Backport to all branches that could still receive a release labels Jun 30, 2025
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.19, 9.1

https://github.com/elastic/kibana/actions/runs/15980325200

@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.19, 9.1

https://github.com/elastic/kibana/actions/runs/15980325283

@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.19, 9.1

https://github.com/elastic/kibana/actions/runs/15980325244

@Zacqary
Copy link
Contributor Author

Zacqary commented Jun 30, 2025

💚 All backports created successfully

Status Branch Result
8.19

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

Zacqary added a commit to Zacqary/kibana that referenced this pull request Jun 30, 2025
…eload (elastic#225101)

## Summary

Closes elastic#222198

For "values from a query" ES|QL controls, attempts to execute the query
again on dashboard page load, refresh, timerange change, etc. to get an
up-to-date list of values.

If the query execution fails, values cached at the previous edit time
will be used.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
(cherry picked from commit 215a4bf)

# Conflicts:
#	src/platform/plugins/shared/controls/tsconfig.json
kibanamachine added a commit that referenced this pull request Jun 30, 2025
…oard reload (#225101) (#225891)

# Backport

This will backport the following commits from `main` to `9.1`:
- [[ES|QL Controls] Refresh "Values from a query" options on dashboard
reload (#225101)](#225101)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Zac
Xeper","email":"Zacqary@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-06-30T17:20:21Z","message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Dashboard","release_note:fix","Team:Presentation","loe:medium","impact:critical","backport:all-open","v9.2.0"],"title":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard
reload","number":225101,"url":"https://github.com/elastic/kibana/pull/225101","mergeCommit":{"message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/225101","number":225101,"mergeCommit":{"message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae"}}]}]
BACKPORT-->

Co-authored-by: Zac Xeper <Zacqary@users.noreply.github.com>
Zacqary added a commit that referenced this pull request Jul 1, 2025
…board reload (#225101) (#225903)

# Backport

This will backport the following commits from `main` to `8.19`:
- [[ES|QL Controls] Refresh "Values from a query" options on dashboard
reload (#225101)](#225101)

<!--- Backport version: 10.0.1 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Zac
Xeper","email":"Zacqary@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-06-30T17:20:21Z","message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Dashboard","release_note:fix","Team:Presentation","loe:medium","impact:critical","backport:version","v9.1.0","v8.19.0","v9.2.0"],"title":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard
reload","number":225101,"url":"https://github.com/elastic/kibana/pull/225101","mergeCommit":{"message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"9.1","label":"v9.1.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/225891","number":225891,"state":"OPEN"},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/225101","number":225101,"mergeCommit":{"message":"[ES|QL
Controls] Refresh \"Values from a query\" options on dashboard reload
(#225101)\n\n## Summary\n\nCloses #222198 \n\nFor \"values from a
query\" ES|QL controls, attempts to execute the query\nagain on
dashboard page load, refresh, timerange change, etc. to get
an\nup-to-date list of values.\n\nIf the query execution fails, values
cached at the previous edit time\nwill be used.\n\n\n### Checklist\n\n-
[x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"215a4bf136c201bdcb0759f137486573309526ae"}}]}]
BACKPORT-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:version Backport to applied version labels Feature:Dashboard Dashboard related features impact:critical This issue should be addressed immediately due to a critical level of impact on the product. loe:medium Medium Level of Effort release_note:fix Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas t// v8.19.0 v9.1.0 v9.2.0

6 participants