[Infrastructure UI] Host filtering controls#145935
[Infrastructure UI] Host filtering controls#145935jennypavlova merged 17 commits intoelastic:mainfrom
Conversation
|
Pinging @elastic/infra-monitoring-ui (Team:Infra Monitoring UI) |
…s-with-url-state [Infrastructure UI] Host filtering controls with url state
| const setControlPanels = useCallback( | ||
| (panels: ControlPanels) => { | ||
| setUrlState(panels); | ||
| }, | ||
| [setUrlState] | ||
| ); |
There was a problem hiding this comment.
suggestion: in my understanding (correct me if wrong, please), the useUrlState already returns a memorized handler setUrlState. This declaration is unnecessary since the function only forwards the argument to the updated handler.
You could rename it directly with a new variable and keep the same function reference:
const setControlPanels = setUrlStateThere was a problem hiding this comment.
Good point! I don't need the useCallback anymore 🙂 I set it directly in the return same as the urlState so it will be even simpler:
return {
controlPanel: urlState,
setControlPanels: setUrlState,
}
|
|
||
| return ( | ||
| <LazyControlsRenderer | ||
| getCreationOptions={async ({ addDataControlFromField }) => { |
There was a problem hiding this comment.
@elastic/kibana-presentation I saw that the input parameter was replaced with getCreationOptions in this PR, really nice progress there 🙌
I tried to use addDataControlFromField to add the panels like in your example but in my case, I want to prefill the control group selections from a URL parameter (Currently I am persisting the whole panels object in the URL state to achieve that) Do you know if I can archive something similar with the latest Controls API changes or it's not currently available?
|
|
||
| return ( | ||
| <LazyControlsRenderer | ||
| getCreationOptions={async ({ addDataControlFromField }) => { |
There was a problem hiding this comment.
nit: since this function does not wait for any async operation, you can safely remove the async and keep your function synchronous.
Also, you don't need to restructure the args if not necessary, and to improve the readability of the return statement you could abstract the object into a factory function out of the return statement, something like this:
const makeCreationOption = ({dataViewId, timeRange, filters, query}): Partial<ControlGroupInput> => ({
id: dataViewId,
timeRange,
viewMode: ViewMode.VIEW,
filters,
query,
chainingSystem: 'HIERARCHICAL',
controlStyle: 'oneLine',
defaultControlWidth: 'small',
panels: controlPanel,
});
...
const handleOptionCreation = () => makeCreationOption({dataViewId, timeRange, filters, query})
return (
<LazyControlsRenderer
getCreationOptions={handleOptionCreation}
onEmbeddableLoad={...}
...There was a problem hiding this comment.
The function (getCreationOptions) is defined to return a promise, that's why it has async. The methods that we need to wait are not used in this case but the returned type is still a promise.
| } | ||
| return buildEsQuery(metricsDataView, state.query, state.filters); | ||
| }, [metricsDataView, state.filters, state.query]); | ||
| if (panelFilters && panelFilters.length > 0) { |
There was a problem hiding this comment.
nit: if (panelFilters?.length > 0)
There was a problem hiding this comment.
In this case, panelFilters can be null - So if it's null the filters are not in the URL, it can be an empty array if there are no filters and an array with filter objects: so the type is Filter[] | null and type check is not passing if I change it to panelFilters?.length.
So to make it clear I used Array.isArray(panelFilters) && panelFilters.length > 0.
| export const useControlPanels = (dataViewId: string) => { | ||
| const [urlState, setUrlState] = useUrlState<ControlPanels>({ | ||
| defaultState: getDefaultPanels(dataViewId), | ||
| decodeUrlState, | ||
| encodeUrlState, | ||
| urlStateKey: HOST_FILTERS_URL_STATE_KEY, | ||
| }); | ||
|
|
||
| return { | ||
| controlPanel: urlState, | ||
| setControlPanels: setUrlState, | ||
| }; | ||
| }; |
There was a problem hiding this comment.
question: just a detail, for stateful hooks like useState or useReducer the React convention is to return the result as a Array<Value, UpdaterHandler>. Following this convention, you could basically reduce this custom hook to a configurator custom hook in the form of
export const useControlPanels = (dataViewId: string) => {
return useUrlState<ControlPanels>({
defaultState: getDefaultPanels(dataViewId),
decodeUrlState,
encodeUrlState,
urlStateKey: HOST_FILTERS_URL_STATE_KEY,
});
};and then use it as
const [ controlPanel, setControlPanels ] = useControlPanels(dataViewId);Non-blocking at all, just curious if there is any reason for following this approach :)
There was a problem hiding this comment.
Good point, I changed this 👍
tonyghiani
left a comment
There was a problem hiding this comment.
LGTM 👏 Just left a couple of suggestions for readability improvements, but overall it looks functional 🚀
💚 Build Succeeded
Metrics [docs]Module Count
Async chunks
Page load bundle
Unknown metric groupsESLint disabled in files
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
Closes #140445
Summary
This PR adds 2 filters (Operating System and Cloud Provider) using Kibana Controls API to the Host view.
Testing
🎉 UPDATE the control panels are prefilled from the URL
The Workaround:
Together with @ThomThomson we found a way to prefill the control group selections from the URL state by adding the panels' objects to the URL state (using a separate key to avoid the infinite loop issue) and keeping the output filters (used for updating the table) separately.
Discovered issues with persisting the new filters to the URL state
In order to avoid that we can persist them in a different parameter (instead of adding them to the existing
_awe can add a new one for example namedcontrolFilters. This will work with filtering the table results.BUT If we go with the solution to persist them in another
urlStateKeywe also need to prefill those selections from the url state to the control filters (Operating System and Cloud Provide).Currently, the controls API supports setting
selectedOptionsas a string array.Workaraound Ideas
Option 1: I tried first on a separate branch
selectedOptionsinside the control group inputpanel(based on the field name for example)Option 2 (Suggestion from Devon )
❌ The issue with both 1 & 2
selectedOptionswe can prefill only strings soExistandNegatewon't be supported