diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index df8a077e844f6..aca3a1a0c3c99 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -119,7 +119,7 @@ pageLoadAssetSize:
   observabilityAiAssistantManagement: 19279
   observabilityLogsExplorer: 46650
   observabilityOnboarding: 19573
-  observabilityShared: 80000
+  observabilityShared: 111036
   osquery: 107090
   painlessLab: 179748
   presentationPanel: 55463
diff --git a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts b/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts
index 433ca877b0f62..477d765ef7a7f 100644
--- a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts
+++ b/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts
@@ -54,7 +54,9 @@ export function useAbortableAsync<T>(
           })
           .catch((err) => {
             setValue(undefined);
-            setError(err);
+            if (!controller.signal.aborted) {
+              setError(err);
+            }
           })
           .finally(() => setLoading(false));
       } else {
diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts
index d0694ef7f207f..3199cbf70c0be 100644
--- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts
+++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts
@@ -15,8 +15,8 @@ import {
   ALERT_STATUS_RECOVERED,
   ALERT_STATUS_UNTRACKED,
 } from '@kbn/rule-data-utils';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { ContentTabIds } from '../types';
-import { useUrlState } from '../../../hooks/use_url_state';
 import { ASSET_DETAILS_URL_STATE_KEY } from '../constants';
 import { ALERT_STATUS_ALL } from '../../shared/alerts/constants';
 
diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_inventory_views.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_inventory_views.ts
index 38f3b19604102..d334baa0e5fdf 100644
--- a/x-pack/plugins/observability_solution/infra/public/hooks/use_inventory_views.ts
+++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_inventory_views.ts
@@ -9,7 +9,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { useUiTracker } from '@kbn/observability-shared-plugin/public';
+import { useUiTracker, useUrlState } from '@kbn/observability-shared-plugin/public';
 import {
   MutationContext,
   SavedViewResult,
@@ -23,7 +23,6 @@ import {
 } from '../../common/http_api/latest';
 import type { InventoryView } from '../../common/inventory_views';
 import { useKibanaContextForPlugin } from './use_kibana';
-import { useUrlState } from './use_url_state';
 import { useSavedViewsNotifier } from './use_saved_views_notifier';
 import { useSourceContext } from '../containers/metrics_source';
 
diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_explorer_views.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_explorer_views.ts
index 6d652af02a136..ddf27da96e1a7 100644
--- a/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_explorer_views.ts
+++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_metrics_explorer_views.ts
@@ -9,7 +9,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { useUiTracker } from '@kbn/observability-shared-plugin/public';
+import { useUiTracker, useUrlState } from '@kbn/observability-shared-plugin/public';
 
 import {
   MutationContext,
@@ -23,7 +23,6 @@ import {
   UpdateMetricsExplorerViewAttributesRequestPayload,
 } from '../../common/http_api/latest';
 import { MetricsExplorerView } from '../../common/metrics_explorer_views';
-import { useUrlState } from './use_url_state';
 import { useSavedViewsNotifier } from './use_saved_views_notifier';
 import { useSourceContext } from '../containers/metrics_source';
 import { useKibanaContextForPlugin } from './use_kibana';
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results_url_state.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results_url_state.tsx
index 169000aa3801f..f219757da8514 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results_url_state.tsx
+++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results_url_state.tsx
@@ -9,7 +9,7 @@ import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import { pipe } from 'fp-ts/lib/pipeable';
 import * as rt from 'io-ts';
-import { useUrlState } from '../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import {
   useKibanaTimefilterTime,
   useSyncKibanaTimeFilterTime,
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
index 1130c8dca9be2..f669d82f76f0f 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
+++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
@@ -12,8 +12,8 @@ import moment from 'moment';
 import * as rt from 'io-ts';
 import type { TimeRange as KibanaTimeRange } from '@kbn/es-query';
 import { decodeOrThrow } from '@kbn/io-ts-utils';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { TimeRange } from '../../../../common/time/time_range';
-import { useUrlState } from '../../../hooks/use_url_state';
 import {
   useKibanaTimefilterTime,
   useSyncKibanaTimeFilterTime,
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page.tsx
index 33ff9300c4d94..706fb7811fa78 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page.tsx
+++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/stream/page.tsx
@@ -6,7 +6,7 @@
  */
 
 import { EuiErrorBoundary } from '@elastic/eui';
-import { useTrackPageview } from '@kbn/observability-shared-plugin/public';
+import { useKibanaQuerySettings, useTrackPageview } from '@kbn/observability-shared-plugin/public';
 import React from 'react';
 import { useLogViewContext } from '@kbn/logs-shared-plugin/public';
 import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
@@ -14,7 +14,6 @@ import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs';
 import { LogStreamPageStateProvider } from '../../../observability_logs/log_stream_page/state';
 import { streamTitle } from '../../../translations';
 import { useKbnUrlStateStorageFromRouterContext } from '../../../containers/kbn_url_state_context';
-import { useKibanaQuerySettings } from '../../../hooks/use_kibana_query_settings';
 import { ConnectedStreamPageContent } from './page_content';
 
 export const StreamPage = () => {
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/control_panels_config.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/control_panels_config.ts
new file mode 100644
index 0000000000000..75e2469974768
--- /dev/null
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/control_panels_config.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { ControlPanels } from '@kbn/observability-shared-plugin/public';
+
+export const availableControlsPanels = {
+  HOST_OS_NAME: 'host.os.name',
+  CLOUD_PROVIDER: 'cloud.provider',
+  SERVICE_NAME: 'service.name',
+};
+
+export const controlPanelConfigs: ControlPanels = {
+  [availableControlsPanels.HOST_OS_NAME]: {
+    order: 0,
+    width: 'medium',
+    grow: false,
+    type: 'optionsListControl',
+    fieldName: availableControlsPanels.HOST_OS_NAME,
+    title: 'Operating System',
+  },
+  [availableControlsPanels.CLOUD_PROVIDER]: {
+    order: 1,
+    width: 'medium',
+    grow: false,
+    type: 'optionsListControl',
+    fieldName: availableControlsPanels.CLOUD_PROVIDER,
+    title: 'Cloud Provider',
+  },
+  [availableControlsPanels.SERVICE_NAME]: {
+    order: 2,
+    width: 'medium',
+    grow: false,
+    type: 'optionsListControl',
+    fieldName: availableControlsPanels.SERVICE_NAME,
+    title: 'Service Name',
+  },
+};
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_content.tsx
index 2ee6aa762e77c..847d0e05183a7 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_content.tsx
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_content.tsx
@@ -5,18 +5,19 @@
  * 2.0.
  */
 
-import React, { useCallback, useEffect, useRef } from 'react';
 import {
   ControlGroupRenderer,
   ControlGroupRendererApi,
-  DataControlApi,
   ControlGroupRuntimeState,
+  DataControlApi,
 } from '@kbn/controls-plugin/public';
-import type { Filter, Query, TimeRange } from '@kbn/es-query';
 import { DataView } from '@kbn/data-views-plugin/public';
-import { Subscription } from 'rxjs';
+import type { Filter, Query, TimeRange } from '@kbn/es-query';
 import { euiStyled } from '@kbn/kibana-react-plugin/common';
-import { useControlPanels } from '../../hooks/use_control_panels_url_state';
+import { useControlPanels } from '@kbn/observability-shared-plugin/public';
+import React, { useCallback, useEffect, useRef } from 'react';
+import { Subscription } from 'rxjs';
+import { controlPanelConfigs } from './control_panels_config';
 import { ControlTitle } from './controls_title';
 
 interface Props {
@@ -34,7 +35,7 @@ export const ControlsContent: React.FC<Props> = ({
   timeRange,
   onFiltersChange,
 }) => {
-  const [controlPanels, setControlPanels] = useControlPanels(dataView);
+  const [controlPanels, setControlPanels] = useControlPanels(controlPanelConfigs, dataView);
   const subscriptions = useRef<Subscription>(new Subscription());
 
   const getInitialInput = useCallback(
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_title.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_title.tsx
index 7202985dbb6bb..b5b45e0d3979a 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_title.tsx
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/search_bar/controls_title.tsx
@@ -8,8 +8,8 @@
 import React from 'react';
 import { EuiFormLabel, EuiText, EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
 import { FormattedMessage } from '@kbn/i18n-react';
-import { availableControlsPanels } from '../../hooks/use_control_panels_url_state';
 import { Popover } from '../common/popover';
+import { availableControlsPanels } from './control_panels_config';
 
 const helpMessages = {
   [availableControlsPanels.SERVICE_NAME]: (
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table_url_state.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table_url_state.ts
index c3a5117c18efe..3c2569da620c7 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table_url_state.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table_url_state.ts
@@ -12,7 +12,7 @@ import { constant, identity } from 'fp-ts/lib/function';
 import useLocalStorage from 'react-use/lib/useLocalStorage';
 import deepEqual from 'fast-deep-equal';
 import { useReducer } from 'react';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { DEFAULT_PAGE_SIZE, LOCAL_STORAGE_PAGE_SIZE_KEY } from '../constants';
 
 export const GET_DEFAULT_TABLE_PROPERTIES: TableProperties = {
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_logs_search_url_state.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_logs_search_url_state.ts
index d40004e325a60..e2caa050132d3 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_logs_search_url_state.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_logs_search_url_state.ts
@@ -9,7 +9,7 @@ import * as rt from 'io-ts';
 import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 
 const DEFAULT_QUERY = {
   language: 'kuery',
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_tab_id.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_tab_id.ts
index ec5d897751481..4e9215158c696 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_tab_id.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_tab_id.ts
@@ -9,7 +9,7 @@ import * as rt from 'io-ts';
 import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 
 const TAB_ID_URL_STATE_KEY = 'tabId';
 
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts
index 8912ec480e3b7..8a7302da1a223 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts
@@ -10,9 +10,9 @@ import { buildEsQuery, Filter, fromKueryExpression, TimeRange, type Query } from
 import { Subscription, map, tap } from 'rxjs';
 import deepEqual from 'fast-deep-equal';
 import useEffectOnce from 'react-use/lib/useEffectOnce';
+import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public';
 import { useSearchSessionContext } from '../../../../hooks/use_search_session';
 import { parseDateRange } from '../../../../utils/datemath';
-import { useKibanaQuerySettings } from '../../../../hooks/use_kibana_query_settings';
 import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
 import { telemetryTimeRangeFormatter } from '../../../../../common/formatters/telemetry_time_range';
 import { useMetricsDataViewContext } from '../../../../containers/metrics_source';
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search_url_state.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search_url_state.ts
index 4c96fd93524be..c7bcf09271a3e 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search_url_state.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search_url_state.ts
@@ -14,7 +14,7 @@ import { constant, identity } from 'fp-ts/lib/function';
 import { enumeration } from '@kbn/securitysolution-io-ts-types';
 import { FilterStateStore } from '@kbn/es-query';
 import useLocalStorage from 'react-use/lib/useLocalStorage';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import {
   useKibanaTimefilterTime,
   useSyncKibanaTimeFilterTime,
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts
index bbce5a9f90579..8878dead99d05 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts
@@ -9,7 +9,7 @@ import * as rt from 'io-ts';
 import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 
 export const GET_DEFAULT_PROPERTIES: AssetDetailsFlyoutProperties = {
   detailsItemId: null,
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts
index 94ad32c4e3097..7372fbcfdd737 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts
@@ -12,12 +12,12 @@ import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import createContainter from 'constate';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import {
   type InventoryFiltersState,
   inventoryFiltersStateRT,
 } from '../../../../../common/inventory_views';
 import { useAlertPrefillContext } from '../../../../alerting/use_alert_prefill';
-import { useUrlState } from '../../../../hooks/use_url_state';
 import { useMetricsDataViewContext } from '../../../../containers/metrics_source';
 import { convertKueryToElasticSearchQuery } from '../../../../utils/kuery';
 
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts
index 38dd4f0bf3617..41b91bce9c4ee 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts
@@ -11,6 +11,7 @@ import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import createContainer from 'constate';
 import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { InventoryViewOptions } from '../../../../../common/inventory_views/types';
 import {
   type InventoryLegendOptions,
@@ -24,7 +25,6 @@ import type {
   SnapshotGroupBy,
   SnapshotCustomMetricInput,
 } from '../../../../../common/http_api/snapshot_api';
-import { useUrlState } from '../../../../hooks/use_url_state';
 
 export const DEFAULT_LEGEND: WaffleLegendOptions = {
   palette: 'cool',
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts
index 670f8645fc485..a7aadb731a750 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts
@@ -12,7 +12,7 @@ import { fold } from 'fp-ts/lib/Either';
 import DateMath from '@kbn/datemath';
 import { constant, identity } from 'fp-ts/lib/function';
 import createContainer from 'constate';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { useKibanaTimefilterTime } from '../../../../hooks/use_kibana_timefilter_time';
 export const DEFAULT_WAFFLE_TIME_STATE: WaffleTimeState = {
   currentTime: Date.now(),
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts
index 7c61778dce74e..b36a1a1cd1c5d 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts
+++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts
@@ -13,8 +13,8 @@ import * as rt from 'io-ts';
 import { pipe } from 'fp-ts/lib/pipeable';
 import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
 import { replaceStateKeyInQueryString } from '../../../../../common/url_state_storage_service';
-import { useUrlState } from '../../../../hooks/use_url_state';
 
 const parseRange = (range: MetricsTimeInput) => {
   const parsedFrom = dateMath.parse(range.from.toString());
diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts
index 507d9d492c0f7..3a9684a38254a 100644
--- a/x-pack/plugins/observability_solution/inventory/common/entities.ts
+++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts
@@ -80,29 +80,6 @@ export const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({
   dataset: ENTITY_LATEST,
 });
 
-const entityArrayRt = t.array(t.string);
-export const entityTypesRt = new t.Type<string[], string, unknown>(
-  'entityTypesRt',
-  entityArrayRt.is,
-  (input, context) => {
-    if (typeof input === 'string') {
-      const arr = input.split(',');
-      const validation = entityArrayRt.decode(arr);
-      if (isRight(validation)) {
-        return t.success(validation.right);
-      }
-    } else if (Array.isArray(input)) {
-      const validation = entityArrayRt.decode(input);
-      if (isRight(validation)) {
-        return t.success(validation.right);
-      }
-    }
-
-    return t.failure(input, context);
-  },
-  (arr) => arr.join()
-);
-
 export interface Entity {
   [ENTITY_LAST_SEEN]: string;
   [ENTITY_ID]: string;
@@ -117,7 +94,7 @@ export interface Entity {
 export type EntityGroup = {
   count: number;
 } & {
-  [key: string]: any;
+  [key: string]: string;
 };
 
 export type InventoryEntityLatest = z.infer<typeof entityLatestSchema> & {
diff --git a/x-pack/plugins/observability_solution/inventory/common/entitites.test.ts b/x-pack/plugins/observability_solution/inventory/common/entitites.test.ts
deleted file mode 100644
index c923bda530746..0000000000000
--- a/x-pack/plugins/observability_solution/inventory/common/entitites.test.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-import { isLeft, isRight } from 'fp-ts/lib/Either';
-import { entityTypesRt } from './entities';
-
-const validate = (input: unknown) => entityTypesRt.decode(input);
-
-describe('entityTypesRt codec', () => {
-  it('should validate a valid string of entity types', () => {
-    const input = 'service,host,container';
-    const result = validate(input);
-    expect(isRight(result)).toBe(true);
-    if (isRight(result)) {
-      expect(result.right).toEqual(['service', 'host', 'container']);
-    }
-  });
-
-  it('should validate a valid array of entity types', () => {
-    const input = ['service', 'host', 'container'];
-    const result = validate(input);
-    expect(isRight(result)).toBe(true);
-    if (isRight(result)) {
-      expect(result.right).toEqual(['service', 'host', 'container']);
-    }
-  });
-
-  it('should fail validation when input is not a string or array', () => {
-    const input = 123;
-    const result = validate(input);
-    expect(isLeft(result)).toBe(true);
-  });
-
-  it('should validate an empty array as valid', () => {
-    const input: unknown[] = [];
-    const result = validate(input);
-    expect(isRight(result)).toBe(true);
-    if (isRight(result)) {
-      expect(result.right).toEqual([]);
-    }
-  });
-
-  it('should serialize a valid array back to a string', () => {
-    const input = ['service', 'host'];
-    const serialized = entityTypesRt.encode(input);
-    expect(serialized).toBe('service,host');
-  });
-
-  it('should serialize an empty array back to an empty string', () => {
-    const input: string[] = [];
-    const serialized = entityTypesRt.encode(input);
-    expect(serialized).toBe('');
-  });
-});
diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts
index d24953c38eb13..9c9011609740b 100644
--- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts
+++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts
@@ -165,16 +165,17 @@ describe('Home page', () => {
         cy.intercept('GET', '/internal/entities/managed/enablement', {
           fixture: 'eem_enabled.json',
         }).as('getEEMStatus');
+        cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as(
+          'entityTypeControlGroupOptions'
+        );
         cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities');
         cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups');
         cy.visitKibana('/app/inventory');
         cy.wait('@getEEMStatus');
-        cy.getByTestSubj('entityTypesFilterComboBox')
-          .click()
-          .getByTestSubj('entityTypesFilterserviceOption')
-          .click();
+        cy.getByTestSubj('optionsList-control-entity.type').click();
+        cy.wait('@entityTypeControlGroupOptions');
+        cy.getByTestSubj('optionsList-control-selection-service').click();
         cy.wait('@getGroups');
-        cy.contains('service');
         cy.getByTestSubj('inventoryGroupTitle_entity.type_service').click();
         cy.wait('@getEntities');
         cy.get('server1').should('not.exist');
@@ -188,16 +189,17 @@ describe('Home page', () => {
         cy.intercept('GET', '/internal/entities/managed/enablement', {
           fixture: 'eem_enabled.json',
         }).as('getEEMStatus');
+        cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as(
+          'entityTypeControlGroupOptions'
+        );
         cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities');
         cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups');
         cy.visitKibana('/app/inventory');
         cy.wait('@getEEMStatus');
-        cy.getByTestSubj('entityTypesFilterComboBox')
-          .click()
-          .getByTestSubj('entityTypesFilterhostOption')
-          .click();
+        cy.getByTestSubj('optionsList-control-entity.type').click();
+        cy.wait('@entityTypeControlGroupOptions');
+        cy.getByTestSubj('optionsList-control-selection-host').click();
         cy.wait('@getGroups');
-        cy.contains('host');
         cy.getByTestSubj('inventoryGroupTitle_entity.type_host').click();
         cy.wait('@getEntities');
         cy.contains('server1');
@@ -211,16 +213,17 @@ describe('Home page', () => {
         cy.intercept('GET', '/internal/entities/managed/enablement', {
           fixture: 'eem_enabled.json',
         }).as('getEEMStatus');
+        cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as(
+          'entityTypeControlGroupOptions'
+        );
         cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities');
         cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups');
         cy.visitKibana('/app/inventory');
         cy.wait('@getEEMStatus');
-        cy.getByTestSubj('entityTypesFilterComboBox')
-          .click()
-          .getByTestSubj('entityTypesFiltercontainerOption')
-          .click();
+        cy.getByTestSubj('optionsList-control-entity.type').click();
+        cy.wait('@entityTypeControlGroupOptions');
+        cy.getByTestSubj('optionsList-control-selection-container').click();
         cy.wait('@getGroups');
-        cy.contains('container');
         cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click();
         cy.wait('@getEntities');
         cy.contains('server1').should('not.exist');
diff --git a/x-pack/plugins/observability_solution/inventory/kibana.jsonc b/x-pack/plugins/observability_solution/inventory/kibana.jsonc
index e7cc398c9c655..e6e7c5f2fa2f8 100644
--- a/x-pack/plugins/observability_solution/inventory/kibana.jsonc
+++ b/x-pack/plugins/observability_solution/inventory/kibana.jsonc
@@ -21,7 +21,7 @@
       "ruleRegistry",
       "share"
     ],
-    "requiredBundles": ["kibanaReact"],
+    "requiredBundles": ["kibanaReact","controls"],
     "optionalPlugins": ["spaces", "cloud"],
     "extraPublicDirs": []
   }
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/app_root/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/app_root/index.tsx
index 6bec4335c7193..52f46268da2ef 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/app_root/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/app_root/index.tsx
@@ -12,12 +12,12 @@ import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
 import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config';
 import React from 'react';
 import { InventoryContextProvider } from '../../context/inventory_context_provider';
-import { InventorySearchBarContextProvider } from '../../context/inventory_search_bar_context_provider';
+import { KibanaEnvironment } from '../../hooks/use_kibana';
+import { UnifiedSearchProvider } from '../../hooks/use_unified_search_context';
 import { inventoryRouter } from '../../routes/config';
 import { InventoryServices } from '../../services/types';
 import { InventoryStartDependencies } from '../../types';
 import { HeaderActionMenuItems } from './header_action_menu';
-import { KibanaEnvironment } from '../../hooks/use_kibana';
 
 export function AppRoot({
   coreStart,
@@ -43,12 +43,12 @@ export function AppRoot({
   return (
     <InventoryContextProvider context={context}>
       <RedirectAppLinks coreStart={coreStart}>
-        <InventorySearchBarContextProvider>
-          <RouterProvider history={history} router={inventoryRouter}>
+        <RouterProvider history={history} router={inventoryRouter as any}>
+          <UnifiedSearchProvider>
             <RouteRenderer />
             <InventoryHeaderActionMenu appMountParameters={appMountParameters} />
-          </RouterProvider>
-        </InventorySearchBarContextProvider>
+          </UnifiedSearchProvider>
+        </RouterProvider>
       </RedirectAppLinks>
     </InventoryContextProvider>
   );
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx
index 6018b66d37991..f3c518ef49b16 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx
@@ -5,11 +5,11 @@
  * 2.0.
  */
 
+import { copyToClipboard } from '@elastic/eui';
+import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
+import { fireEvent, render, screen } from '@testing-library/react';
 import React from 'react';
-import { render, fireEvent, screen } from '@testing-library/react';
 import { BadgeFilterWithPopover } from '.';
-import { EuiThemeProvider, copyToClipboard } from '@elastic/eui';
-import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
 
 jest.mock('@elastic/eui', () => ({
   ...jest.requireActual('@elastic/eui'),
@@ -17,10 +17,8 @@ jest.mock('@elastic/eui', () => ({
 }));
 
 describe('BadgeFilterWithPopover', () => {
-  const mockOnFilter = jest.fn();
   const field = ENTITY_TYPE;
   const value = 'host';
-  const label = 'Host';
   const popoverContentDataTestId = 'inventoryBadgeFilterWithPopoverContent';
   const popoverContentTitleTestId = 'inventoryBadgeFilterWithPopoverTitle';
 
@@ -28,32 +26,16 @@ describe('BadgeFilterWithPopover', () => {
     jest.clearAllMocks();
   });
 
-  it('renders the badge with the correct label', () => {
-    render(
-      <BadgeFilterWithPopover field={field} value={value} onFilter={mockOnFilter} label={label} />,
-      { wrapper: EuiThemeProvider }
-    );
-    expect(screen.queryByText(label)).toBeInTheDocument();
-    expect(screen.getByText(label).textContent).toBe(label);
-  });
-
   it('opens the popover when the badge is clicked', () => {
-    render(<BadgeFilterWithPopover field={field} value={value} onFilter={mockOnFilter} />);
+    render(<BadgeFilterWithPopover field={field} value={value} />);
     expect(screen.queryByTestId(popoverContentDataTestId)).not.toBeInTheDocument();
     fireEvent.click(screen.getByText(value));
     expect(screen.queryByTestId(popoverContentDataTestId)).toBeInTheDocument();
     expect(screen.queryByTestId(popoverContentTitleTestId)?.textContent).toBe(`${field}:${value}`);
   });
 
-  it('calls onFilter when the "Filter for" button is clicked', () => {
-    render(<BadgeFilterWithPopover field={field} value={value} onFilter={mockOnFilter} />);
-    fireEvent.click(screen.getByText(value));
-    fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverFilterForButton'));
-    expect(mockOnFilter).toHaveBeenCalled();
-  });
-
   it('copies value to clipboard when the "Copy value" button is clicked', () => {
-    render(<BadgeFilterWithPopover field={field} value={value} onFilter={mockOnFilter} />);
+    render(<BadgeFilterWithPopover field={field} value={value} />);
     fireEvent.click(screen.getByText(value));
     fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverCopyValueButton'));
     expect(copyToClipboard).toHaveBeenCalledWith(value);
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx
index d1e952e189d6e..83e0bb02e6d8d 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx
@@ -8,28 +8,29 @@
 import {
   EuiBadge,
   EuiButtonEmpty,
-  EuiFlexGrid,
   EuiFlexGroup,
   EuiFlexItem,
   EuiPopover,
   EuiPopoverFooter,
+  EuiPopoverTitle,
   copyToClipboard,
   useEuiTheme,
 } from '@elastic/eui';
 import { css } from '@emotion/react';
 import { i18n } from '@kbn/i18n';
+import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
 import React, { useState } from 'react';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
 
 interface Props {
   field: string;
   value: string;
-  label?: string;
-  onFilter: () => void;
 }
 
-export function BadgeFilterWithPopover({ field, value, onFilter, label }: Props) {
+export function BadgeFilterWithPopover({ field, value }: Props) {
   const [isOpen, setIsOpen] = useState(false);
   const theme = useEuiTheme();
+  const { addFilter } = useUnifiedSearchContext();
 
   return (
     <EuiPopover
@@ -43,60 +44,76 @@ export function BadgeFilterWithPopover({ field, value, onFilter, label }: Props)
             { defaultMessage: 'Open popover' }
           )}
         >
-          {label || value}
+          {value}
         </EuiBadge>
       }
       isOpen={isOpen}
       closePopover={() => setIsOpen(false)}
+      panelPaddingSize="s"
     >
-      <span data-test-subj="inventoryBadgeFilterWithPopoverTitle">
-        <EuiFlexGroup
-          data-test-subj="inventoryBadgeFilterWithPopoverContent"
-          responsive={false}
-          gutterSize="xs"
-          css={css`
-            font-family: ${theme.euiTheme.font.familyCode};
-          `}
-        >
-          <EuiFlexItem grow={false}>
-            <span
-              css={css`
-                font-weight: bold;
-              `}
-            >
-              {field}:
-            </span>
-          </EuiFlexItem>
-          <EuiFlexItem grow={false}>
-            <span className="eui-textBreakWord">{value}</span>
-          </EuiFlexItem>
-        </EuiFlexGroup>
-      </span>
+      <EuiPopoverTitle>
+        <span data-test-subj="inventoryBadgeFilterWithPopoverTitle">
+          <EuiFlexGroup
+            data-test-subj="inventoryBadgeFilterWithPopoverContent"
+            responsive={false}
+            gutterSize="xs"
+            css={css`
+              font-family: ${theme.euiTheme.font.familyCode};
+            `}
+          >
+            <EuiFlexItem grow={false}>
+              <span
+                css={css`
+                  font-weight: bold;
+                `}
+              >
+                {field}:
+              </span>
+            </EuiFlexItem>
+            <EuiFlexItem grow={false}>
+              <span className="eui-textBreakWord">{value}</span>
+            </EuiFlexItem>
+          </EuiFlexGroup>
+        </span>
+      </EuiPopoverTitle>
+      <EuiFlexGroup responsive={false}>
+        <EuiFlexItem>
+          <EuiButtonEmpty
+            data-test-subj="inventoryBadgeFilterWithPopoverFilterForButton"
+            iconType="plusInCircle"
+            onClick={() => {
+              addFilter({ fieldName: ENTITY_TYPE, operation: '+', value });
+            }}
+          >
+            {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', {
+              defaultMessage: 'Filter for',
+            })}
+          </EuiButtonEmpty>
+        </EuiFlexItem>
+        <EuiFlexItem>
+          <EuiButtonEmpty
+            data-test-subj="inventoryBadgeFilterWithPopoverFilterForButton"
+            iconType="minusInCircle"
+            onClick={() => {
+              addFilter({ fieldName: ENTITY_TYPE, operation: '-', value });
+            }}
+          >
+            {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', {
+              defaultMessage: 'Filter out',
+            })}
+          </EuiButtonEmpty>
+        </EuiFlexItem>
+      </EuiFlexGroup>
       <EuiPopoverFooter>
-        <EuiFlexGrid responsive={false} columns={2}>
-          <EuiFlexItem>
-            <EuiButtonEmpty
-              data-test-subj="inventoryBadgeFilterWithPopoverFilterForButton"
-              iconType="plusInCircle"
-              onClick={onFilter}
-            >
-              {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', {
-                defaultMessage: 'Filter for',
-              })}
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-          <EuiFlexItem>
-            <EuiButtonEmpty
-              data-test-subj="inventoryBadgeFilterWithPopoverCopyValueButton"
-              iconType="copyClipboard"
-              onClick={() => copyToClipboard(value)}
-            >
-              {i18n.translate('xpack.inventory.badgeFilterWithPopover.copyValueButtonEmptyLabel', {
-                defaultMessage: 'Copy value',
-              })}
-            </EuiButtonEmpty>
-          </EuiFlexItem>
-        </EuiFlexGrid>
+        <EuiButtonEmpty
+          data-test-subj="inventoryBadgeFilterWithPopoverCopyValueButton"
+          iconType="copyClipboard"
+          onClick={() => copyToClipboard(value)}
+        >
+          {i18n.translate('xpack.inventory.badgeFilterWithPopover.copyValueButtonEmptyLabel', {
+            defaultMessage: 'Copy value',
+          })}
+        </EuiButtonEmpty>
       </EuiPopoverFooter>
     </EuiPopover>
   );
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx
index 047c2e73d0d3e..a3f2834934cd8 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx
@@ -77,7 +77,6 @@ export const Grid: Story<EntityGridStoriesArgs> = (args) => {
           onChangePage={setPageIndex}
           onChangeSort={setSort}
           pageIndex={pageIndex}
-          onFilterByType={(selectedEntityType) => updateArgs({ entityType: selectedEntityType })}
         />
       </EuiFlexItem>
     </EuiFlexGroup>
@@ -100,7 +99,6 @@ export const EmptyGrid: Story<EntityGridStoriesArgs> = (args) => {
       onChangePage={setPageIndex}
       onChangeSort={setSort}
       pageIndex={pageIndex}
-      onFilterByType={() => {}}
     />
   );
 };
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx
index 7819e944c486d..7ca29f7820332 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx
@@ -40,7 +40,6 @@ interface Props {
   pageIndex: number;
   onChangeSort: (sorting: EuiDataGridSorting['columns'][0]) => void;
   onChangePage: (nextPage: number) => void;
-  onFilterByType: (entityType: string) => void;
 }
 
 const PAGE_SIZE = 20;
@@ -53,7 +52,6 @@ export function EntitiesGrid({
   pageIndex,
   onChangePage,
   onChangeSort,
-  onFilterByType,
 }: Props) {
   const { getDiscoverRedirectUrl } = useDiscoverRedirect();
 
@@ -98,14 +96,7 @@ export function EntitiesGrid({
           return entity?.alertsCount ? <AlertsBadge entity={entity} /> : null;
 
         case ENTITY_TYPE:
-          return (
-            <BadgeFilterWithPopover
-              field={ENTITY_TYPE}
-              value={entityType}
-              label={entityType}
-              onFilter={() => onFilterByType(entityType)}
-            />
-          );
+          return <BadgeFilterWithPopover field={ENTITY_TYPE} value={entityType} />;
         case ENTITY_LAST_SEEN:
           return (
             <FormattedMessage
@@ -147,7 +138,7 @@ export function EntitiesGrid({
           return entity[columnId as EntityColumnIds] || '';
       }
     },
-    [entities, getDiscoverRedirectUrl, onFilterByType]
+    [entities, getDiscoverRedirectUrl]
   );
 
   if (loading) {
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx
index d005a001999d5..911e997401023 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx
@@ -4,13 +4,10 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-import React from 'react';
 import { EuiDataGridSorting } from '@elastic/eui';
-import useEffectOnce from 'react-use/lib/useEffectOnce';
 import { decodeOrThrow } from '@kbn/io-ts-utils';
-import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider';
-import { useKibana } from '../../hooks/use_kibana';
-import { EntitiesGrid } from '../entities_grid';
+import React from 'react';
+import useEffectOnce from 'react-use/lib/useEffectOnce';
 import {
   entityPaginationRt,
   type EntityColumnIds,
@@ -19,35 +16,37 @@ import {
 import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async';
 import { useInventoryParams } from '../../hooks/use_inventory_params';
 import { useInventoryRouter } from '../../hooks/use_inventory_router';
+import { useKibana } from '../../hooks/use_kibana';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
+import { EntitiesGrid } from '../entities_grid';
 
 interface Props {
-  field: string;
+  groupValue: string;
 }
 
 const paginationDecoder = decodeOrThrow(entityPaginationRt);
 
-export function GroupedEntitiesGrid({ field }: Props) {
+export function GroupedEntitiesGrid({ groupValue }: Props) {
   const { query } = useInventoryParams('/');
-  const { sortField, sortDirection, kuery, pagination: paginationQuery } = query;
+  const { sortField, sortDirection, pagination: paginationQuery } = query;
   const inventoryRoute = useInventoryRouter();
   let pagination: EntityPagination | undefined = {};
+  const { stringifiedEsQuery } = useUnifiedSearchContext();
   try {
     pagination = paginationDecoder(paginationQuery);
   } catch (error) {
     inventoryRoute.push('/', {
       path: {},
       query: {
-        sortField,
-        sortDirection,
-        kuery,
+        ...query,
         pagination: undefined,
       },
     });
     window.location.reload();
   }
-  const pageIndex = pagination?.[field] ?? 0;
+  const pageIndex = pagination?.[groupValue] ?? 0;
 
-  const { refreshSubject$ } = useInventorySearchBarContext();
+  const { refreshSubject$, isControlPanelsInitiated } = useUnifiedSearchContext();
   const {
     services: { inventoryAPIClient },
   } = useKibana();
@@ -58,19 +57,28 @@ export function GroupedEntitiesGrid({ field }: Props) {
     refresh,
   } = useInventoryAbortableAsync(
     ({ signal }) => {
-      return inventoryAPIClient.fetch('GET /internal/inventory/entities', {
-        params: {
-          query: {
-            sortDirection,
-            sortField,
-            entityTypes: field?.length ? JSON.stringify([field]) : undefined,
-            kuery,
+      if (isControlPanelsInitiated) {
+        return inventoryAPIClient.fetch('GET /internal/inventory/entities', {
+          params: {
+            query: {
+              sortDirection,
+              sortField,
+              esQuery: stringifiedEsQuery,
+              entityTypes: groupValue?.length ? JSON.stringify([groupValue]) : undefined,
+            },
           },
-        },
-        signal,
-      });
+          signal,
+        });
+      }
     },
-    [field, inventoryAPIClient, kuery, sortDirection, sortField]
+    [
+      groupValue,
+      inventoryAPIClient,
+      sortDirection,
+      sortField,
+      isControlPanelsInitiated,
+      stringifiedEsQuery,
+    ]
   );
 
   useEffectOnce(() => {
@@ -86,7 +94,7 @@ export function GroupedEntitiesGrid({ field }: Props) {
         ...query,
         pagination: entityPaginationRt.encode({
           ...pagination,
-          [field]: nextPage,
+          [groupValue]: nextPage,
         }),
       },
     });
@@ -103,18 +111,6 @@ export function GroupedEntitiesGrid({ field }: Props) {
     });
   }
 
-  function handleTypeFilter(type: string) {
-    const { pagination: _, ...rest } = query;
-    inventoryRoute.push('/', {
-      path: {},
-      query: {
-        ...rest,
-        // Override the current entity types
-        entityTypes: [type],
-      },
-    });
-  }
-
   return (
     <EntitiesGrid
       entities={value.entities}
@@ -124,7 +120,6 @@ export function GroupedEntitiesGrid({ field }: Props) {
       onChangePage={handlePageChange}
       onChangeSort={handleSortChange}
       pageIndex={pageIndex}
-      onFilterByType={handleTypeFilter}
     />
   );
 }
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx
index b376200495e43..b939f0fa5c423 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx
@@ -8,20 +8,18 @@ import { EuiSpacer } from '@elastic/eui';
 import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
 import React from 'react';
 import useEffectOnce from 'react-use/lib/useEffectOnce';
-import { InventoryGroupAccordion } from './inventory_group_accordion';
 import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async';
 import { useKibana } from '../../hooks/use_kibana';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
+import { InventoryGroupAccordion } from './inventory_group_accordion';
 import { InventorySummary } from './inventory_summary';
-import { useInventoryParams } from '../../hooks/use_inventory_params';
-import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider';
 
 export function GroupedInventory() {
   const {
     services: { inventoryAPIClient },
   } = useKibana();
-  const { query } = useInventoryParams('/');
-  const { kuery, entityTypes } = query;
-  const { refreshSubject$ } = useInventorySearchBarContext();
+  const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } =
+    useUnifiedSearchContext();
 
   const {
     value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 },
@@ -29,20 +27,19 @@ export function GroupedInventory() {
     loading,
   } = useInventoryAbortableAsync(
     ({ signal }) => {
-      return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', {
-        params: {
-          path: {
-            field: ENTITY_TYPE,
-          },
-          query: {
-            kuery,
-            entityTypes: entityTypes?.length ? JSON.stringify(entityTypes) : undefined,
+      if (isControlPanelsInitiated) {
+        return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', {
+          params: {
+            path: {
+              field: ENTITY_TYPE,
+            },
+            query: { esQuery: stringifiedEsQuery },
           },
-        },
-        signal,
-      });
+          signal,
+        });
+      }
     },
-    [entityTypes, inventoryAPIClient, kuery]
+    [inventoryAPIClient, stringifiedEsQuery, isControlPanelsInitiated]
   );
 
   useEffectOnce(() => {
@@ -58,8 +55,9 @@ export function GroupedInventory() {
       {value.groups.map((group) => (
         <InventoryGroupAccordion
           key={`${value.groupBy}-${group[value.groupBy]}`}
-          group={group}
           groupBy={value.groupBy}
+          groupValue={group[value.groupBy]}
+          groupCount={group.count}
           isLoading={loading}
         />
       ))}
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx
index 2cddbb8e46d79..bf0b7064033f4 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx
@@ -25,7 +25,13 @@ describe('Grouped Inventory Accordion', () => {
         },
       ],
     };
-    render(<InventoryGroupAccordion group={props.groups[0]} groupBy={props.groupBy} />);
+    render(
+      <InventoryGroupAccordion
+        groupValue={props.groups[0]['entity.type']}
+        groupCount={props.groups[0].count}
+        groupBy={props.groupBy}
+      />
+    );
     expect(screen.getByText(props.groups[0]['entity.type'])).toBeInTheDocument();
     const container = screen.getByTestId('inventoryPanelBadgeEntitiesCount_entity.type_host');
     expect(within(container).getByText('Entities:')).toBeInTheDocument();
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx
index 4c5d34e5a028f..0b4e9a46d4288 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx
@@ -4,12 +4,11 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-import React, { useCallback, useState } from 'react';
-import { i18n } from '@kbn/i18n';
-import { css } from '@emotion/react';
 import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, useEuiTheme } from '@elastic/eui';
+import { css } from '@emotion/react';
+import { i18n } from '@kbn/i18n';
+import React, { useCallback, useState } from 'react';
 import { GroupedEntitiesGrid } from './grouped_entities_grid';
-import type { EntityGroup } from '../../../common/entities';
 import { InventoryPanelBadge } from './inventory_panel_badge';
 
 const ENTITIES_COUNT_BADGE = i18n.translate(
@@ -18,18 +17,19 @@ const ENTITIES_COUNT_BADGE = i18n.translate(
 );
 
 export interface InventoryGroupAccordionProps {
-  group: EntityGroup;
   groupBy: string;
+  groupValue: string;
+  groupCount: number;
   isLoading?: boolean;
 }
 
 export function InventoryGroupAccordion({
-  group,
   groupBy,
+  groupValue,
+  groupCount,
   isLoading,
 }: InventoryGroupAccordionProps) {
   const { euiTheme } = useEuiTheme();
-  const field = group[groupBy];
   const [open, setOpen] = useState(false);
 
   const onToggle = useCallback(() => {
@@ -46,19 +46,19 @@ export function InventoryGroupAccordion({
         `}
       >
         <EuiAccordion
-          data-test-subj={`inventoryGroup_${groupBy}_${field}`}
-          id={`inventory-group-${groupBy}-${field}`}
+          data-test-subj={`inventoryGroup_${groupBy}_${groupValue}`}
+          id={`inventory-group-${groupBy}-${groupValue}`}
           buttonContent={
             <EuiTitle size="xs">
-              <h4 data-test-subj={`inventoryGroupTitle_${groupBy}_${field}`}>{field}</h4>
+              <h4 data-test-subj={`inventoryGroupTitle_${groupBy}_${groupValue}`}>{groupValue}</h4>
             </EuiTitle>
           }
           buttonElement="div"
           extraAction={
             <InventoryPanelBadge
-              data-test-subj={`inventoryPanelBadgeEntitiesCount_${groupBy}_${field}`}
+              data-test-subj={`inventoryPanelBadgeEntitiesCount_${groupBy}_${groupValue}`}
               name={ENTITIES_COUNT_BADGE}
-              value={group.count}
+              value={groupCount}
             />
           }
           buttonProps={{ paddingSize: 'm' }}
@@ -78,7 +78,7 @@ export function InventoryGroupAccordion({
           hasShadow={false}
           paddingSize="m"
         >
-          <GroupedEntitiesGrid field={field} />
+          <GroupedEntitiesGrid groupValue={groupValue} />
         </EuiPanel>
       )}
       <EuiSpacer size="s" />
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx
new file mode 100644
index 0000000000000..9c263e39562f1
--- /dev/null
+++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx
@@ -0,0 +1,98 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import {
+  ControlGroupRenderer,
+  ControlGroupRendererApi,
+  ControlGroupRuntimeState,
+} from '@kbn/controls-plugin/public';
+import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
+import { ControlPanels, useControlPanels } from '@kbn/observability-shared-plugin/public';
+import React, { useCallback, useEffect, useRef } from 'react';
+import { skip, Subscription } from 'rxjs';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
+
+const controlPanelDefinitions: ControlPanels = {
+  [ENTITY_TYPE]: {
+    order: 0,
+    type: 'optionsListControl',
+    fieldName: ENTITY_TYPE,
+    width: 'small',
+    grow: false,
+    title: 'Type',
+  },
+};
+
+export function ControlGroups() {
+  const {
+    isControlPanelsInitiated,
+    setIsControlPanelsInitiated,
+    dataView,
+    searchState,
+    onPanelFiltersChange,
+  } = useUnifiedSearchContext();
+  const [controlPanels, setControlPanels] = useControlPanels(controlPanelDefinitions, dataView);
+  const subscriptions = useRef<Subscription>(new Subscription());
+
+  const getInitialInput = useCallback(
+    () => async () => {
+      const initialInput: Partial<ControlGroupRuntimeState> = {
+        chainingSystem: 'HIERARCHICAL',
+        labelPosition: 'oneLine',
+        initialChildControlState: controlPanels,
+      };
+
+      return { initialState: initialInput };
+    },
+    [controlPanels]
+  );
+
+  const loadCompleteHandler = useCallback(
+    (controlGroup: ControlGroupRendererApi) => {
+      if (!controlGroup) return;
+
+      subscriptions.current.add(
+        controlGroup.filters$.pipe(skip(1)).subscribe((newFilters = []) => {
+          onPanelFiltersChange(newFilters);
+        })
+      );
+
+      subscriptions.current.add(
+        controlGroup.getInput$().subscribe(({ initialChildControlState }) => {
+          if (!isControlPanelsInitiated) {
+            setIsControlPanelsInitiated(true);
+          }
+          setControlPanels(initialChildControlState);
+        })
+      );
+    },
+    [isControlPanelsInitiated, onPanelFiltersChange, setControlPanels, setIsControlPanelsInitiated]
+  );
+
+  useEffect(() => {
+    const currentSubscriptions = subscriptions.current;
+    return () => {
+      currentSubscriptions.unsubscribe();
+    };
+  }, []);
+
+  if (!dataView) {
+    return null;
+  }
+
+  return (
+    <div>
+      <ControlGroupRenderer
+        getCreationOptions={getInitialInput()}
+        onApiAvailable={loadCompleteHandler}
+        query={searchState.query}
+        compressed={false}
+        filters={searchState.filters}
+      />
+    </div>
+  );
+}
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_controls.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_controls.tsx
deleted file mode 100644
index e2d9dba2709f1..0000000000000
--- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_controls.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
-import { css } from '@emotion/react';
-import { i18n } from '@kbn/i18n';
-import React from 'react';
-import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async';
-import { useInventoryParams } from '../../hooks/use_inventory_params';
-import { useKibana } from '../../hooks/use_kibana';
-
-interface Props {
-  onChange: (entityTypes: string[]) => void;
-}
-
-const toComboBoxOption = (entityType: string): EuiComboBoxOptionOption => ({
-  key: entityType,
-  label: entityType,
-  'data-test-subj': `entityTypesFilter${entityType}Option`,
-});
-
-export function EntityTypesControls({ onChange }: Props) {
-  const {
-    query: { entityTypes = [] },
-  } = useInventoryParams('/*');
-
-  const {
-    services: { inventoryAPIClient },
-  } = useKibana();
-
-  const { value, loading } = useInventoryAbortableAsync(
-    ({ signal }) => {
-      return inventoryAPIClient.fetch('GET /internal/inventory/entities/types', { signal });
-    },
-    [inventoryAPIClient]
-  );
-
-  const options = value?.entityTypes.map(toComboBoxOption);
-  const selectedOptions = entityTypes.map(toComboBoxOption);
-
-  return (
-    <EuiComboBox
-      data-test-subj="entityTypesFilterComboBox"
-      isLoading={loading}
-      css={css`
-        max-width: 325px;
-      `}
-      aria-label={i18n.translate(
-        'xpack.inventory.entityTypesControls.euiComboBox.accessibleScreenReaderLabel',
-        { defaultMessage: 'Entity types filter' }
-      )}
-      placeholder={i18n.translate(
-        'xpack.inventory.entityTypesControls.euiComboBox.placeHolderLabel',
-        { defaultMessage: 'Types' }
-      )}
-      options={options}
-      selectedOptions={selectedOptions}
-      onChange={(newOptions) => {
-        onChange(newOptions.map((option) => option.key).filter((key): key is string => !!key));
-      }}
-      isClearable
-    />
-  );
-}
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx
index 3a22d9bc19a1d..d1ccfd3f358e3 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx
@@ -4,39 +4,35 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
+import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import type { Query } from '@kbn/es-query';
 import { i18n } from '@kbn/i18n';
-import { SearchBarOwnProps } from '@kbn/unified-search-plugin/public/search_bar';
+import type { SearchBarOwnProps } from '@kbn/unified-search-plugin/public/search_bar';
 import deepEqual from 'fast-deep-equal';
 import React, { useCallback, useEffect } from 'react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { Query } from '@kbn/es-query';
-import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider';
-import { useInventoryParams } from '../../hooks/use_inventory_params';
 import { useKibana } from '../../hooks/use_kibana';
-import { EntityTypesControls } from './entity_types_controls';
-import { DiscoverButton } from './discover_button';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
 import { getKqlFieldsWithFallback } from '../../utils/get_kql_field_names_with_fallback';
+import { ControlGroups } from './control_groups';
+import { DiscoverButton } from './discover_button';
 
 export function SearchBar() {
-  const { refreshSubject$, searchBarContentSubject$, dataView } = useInventorySearchBarContext();
+  const { refreshSubject$, dataView, searchState, onQueryChange } = useUnifiedSearchContext();
+
   const {
     services: {
       unifiedSearch,
+      telemetry,
       data: {
         query: { queryString: queryStringService },
       },
-      telemetry,
     },
   } = useKibana();
 
-  const {
-    query: { kuery, entityTypes },
-  } = useInventoryParams('/*');
-
   const { SearchBar: UnifiedSearchBar } = unifiedSearch.ui;
 
   const syncSearchBarWithUrl = useCallback(() => {
-    const query = kuery ? { query: kuery, language: 'kuery' } : undefined;
+    const query = searchState.query;
     if (query && !deepEqual(queryStringService.getQuery(), query)) {
       queryStringService.setQuery(query);
     }
@@ -44,67 +40,36 @@ export function SearchBar() {
     if (!query) {
       queryStringService.clearQuery();
     }
-  }, [kuery, queryStringService]);
+  }, [searchState.query, queryStringService]);
 
   useEffect(() => {
     syncSearchBarWithUrl();
   }, [syncSearchBarWithUrl]);
 
   const registerSearchSubmittedEvent = useCallback(
-    ({
-      searchQuery,
-      searchIsUpdate,
-      searchEntityTypes,
-    }: {
-      searchQuery?: Query;
-      searchEntityTypes?: string[];
-      searchIsUpdate?: boolean;
-    }) => {
+    ({ searchQuery, searchIsUpdate }: { searchQuery?: Query; searchIsUpdate?: boolean }) => {
       telemetry.reportEntityInventorySearchQuerySubmitted({
         kuery_fields: getKqlFieldsWithFallback(searchQuery?.query as string),
-        entity_types: searchEntityTypes || [],
         action: searchIsUpdate ? 'submit' : 'refresh',
       });
     },
     [telemetry]
   );
 
-  const registerEntityTypeFilteredEvent = useCallback(
-    ({ filterEntityTypes, filterKuery }: { filterEntityTypes: string[]; filterKuery?: string }) => {
-      telemetry.reportEntityInventoryEntityTypeFiltered({
-        entity_types: filterEntityTypes,
-        kuery_fields: filterKuery ? getKqlFieldsWithFallback(filterKuery) : [],
-      });
-    },
-    [telemetry]
-  );
-
-  const handleEntityTypesChange = useCallback(
-    (nextEntityTypes: string[]) => {
-      searchBarContentSubject$.next({ kuery, entityTypes: nextEntityTypes });
-      registerEntityTypeFilteredEvent({ filterEntityTypes: nextEntityTypes, filterKuery: kuery });
-    },
-    [kuery, registerEntityTypeFilteredEvent, searchBarContentSubject$]
-  );
-
   const handleQuerySubmit = useCallback<NonNullable<SearchBarOwnProps['onQuerySubmit']>>(
-    ({ query }, isUpdate) => {
-      searchBarContentSubject$.next({
-        kuery: query?.query as string,
-        entityTypes,
-      });
+    ({ query = { language: 'kuery', query: '' } }, isUpdate) => {
+      if (isUpdate) {
+        onQueryChange(query);
+      } else {
+        refreshSubject$.next();
+      }
 
       registerSearchSubmittedEvent({
         searchQuery: query,
-        searchEntityTypes: entityTypes,
         searchIsUpdate: isUpdate,
       });
-
-      if (!isUpdate) {
-        refreshSubject$.next();
-      }
     },
-    [searchBarContentSubject$, entityTypes, registerSearchSubmittedEvent, refreshSubject$]
+    [registerSearchSubmittedEvent, onQueryChange, refreshSubject$]
   );
 
   return (
@@ -113,15 +78,17 @@ export function SearchBar() {
         <UnifiedSearchBar
           appName="Inventory"
           displayStyle="inPage"
-          showDatePicker={false}
-          showFilterBar={false}
           indexPatterns={dataView ? [dataView] : undefined}
-          renderQueryInputAppend={() => <EntityTypesControls onChange={handleEntityTypesChange} />}
+          renderQueryInputAppend={() => <ControlGroups />}
           onQuerySubmit={handleQuerySubmit}
           placeholder={i18n.translate('xpack.inventory.searchBar.placeholder', {
             defaultMessage:
               'Search for your entities by name or its metadata (e.g. entity.type : service)',
           })}
+          showDatePicker={false}
+          showFilterBar
+          showQueryInput
+          showQueryMenu
         />
       </EuiFlexItem>
 
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx b/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx
similarity index 71%
rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx
rename to x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx
index 05f7437a32c4b..1bec6dee990d1 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/unified_inventory.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx
@@ -5,21 +5,21 @@
  * 2.0.
  */
 import { EuiDataGridSorting } from '@elastic/eui';
+import { decodeOrThrow } from '@kbn/io-ts-utils';
 import React from 'react';
 import useEffectOnce from 'react-use/lib/useEffectOnce';
-import { decodeOrThrow } from '@kbn/io-ts-utils';
 import {
-  type EntityColumnIds,
   entityPaginationRt,
+  type EntityColumnIds,
   type EntityPagination,
 } from '../../../common/entities';
-import { EntitiesGrid } from '../entities_grid';
 import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async';
 import { useInventoryParams } from '../../hooks/use_inventory_params';
 import { useInventoryRouter } from '../../hooks/use_inventory_router';
 import { useKibana } from '../../hooks/use_kibana';
-import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider';
-import { InventorySummary } from './inventory_summary';
+import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context';
+import { EntitiesGrid } from '../entities_grid';
+import { InventorySummary } from '../grouped_inventory/inventory_summary';
 
 const paginationDecoder = decodeOrThrow(entityPaginationRt);
 
@@ -27,9 +27,11 @@ export function UnifiedInventory() {
   const {
     services: { inventoryAPIClient },
   } = useKibana();
-  const { refreshSubject$ } = useInventorySearchBarContext();
+  const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } =
+    useUnifiedSearchContext();
   const { query } = useInventoryParams('/');
-  const { sortDirection, sortField, kuery, entityTypes, pagination: paginationQuery } = query;
+  const { sortDirection, sortField, pagination: paginationQuery } = query;
+
   let pagination: EntityPagination | undefined = {};
   const inventoryRoute = useInventoryRouter();
   try {
@@ -38,9 +40,7 @@ export function UnifiedInventory() {
     inventoryRoute.push('/', {
       path: {},
       query: {
-        sortField,
-        sortDirection,
-        kuery,
+        ...query,
         pagination: undefined,
       },
     });
@@ -55,24 +55,24 @@ export function UnifiedInventory() {
     refresh,
   } = useInventoryAbortableAsync(
     ({ signal }) => {
-      return inventoryAPIClient.fetch('GET /internal/inventory/entities', {
-        params: {
-          query: {
-            sortDirection,
-            sortField,
-            entityTypes: entityTypes?.length ? JSON.stringify(entityTypes) : undefined,
-            kuery,
+      if (isControlPanelsInitiated) {
+        return inventoryAPIClient.fetch('GET /internal/inventory/entities', {
+          params: {
+            query: {
+              sortDirection,
+              sortField,
+              esQuery: stringifiedEsQuery,
+            },
           },
-        },
-        signal,
-      });
+          signal,
+        });
+      }
     },
-    [entityTypes, inventoryAPIClient, kuery, sortDirection, sortField]
+    [inventoryAPIClient, sortDirection, sortField, isControlPanelsInitiated, stringifiedEsQuery]
   );
 
   useEffectOnce(() => {
     const refreshSubscription = refreshSubject$.subscribe(refresh);
-
     return () => refreshSubscription.unsubscribe();
   });
 
@@ -100,19 +100,6 @@ export function UnifiedInventory() {
     });
   }
 
-  function handleTypeFilter(type: string) {
-    const { pagination: _, ...rest } = query;
-
-    inventoryRoute.push('/', {
-      path: {},
-      query: {
-        ...rest,
-        // Override the current entity types
-        entityTypes: [type],
-      },
-    });
-  }
-
   return (
     <>
       <InventorySummary />
@@ -124,7 +111,6 @@ export function UnifiedInventory() {
         onChangePage={handlePageChange}
         onChangeSort={handleSortChange}
         pageIndex={pageIndex}
-        onFilterByType={handleTypeFilter}
       />
     </>
   );
diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts
index 3c6ba331ec2a0..c29caca7e5b77 100644
--- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts
@@ -5,19 +5,16 @@
  * 2.0.
  */
 import {
-  ENTITY_TYPE,
   ENTITY_DEFINITION_ID,
   ENTITY_DISPLAY_NAME,
   ENTITY_LAST_SEEN,
+  ENTITY_TYPE,
 } from '@kbn/observability-shared-plugin/common';
 import { useCallback } from 'react';
-import { type PhrasesFilter, buildPhrasesFilter } from '@kbn/es-query';
-import type { DataViewField } from '@kbn/data-views-plugin/public';
 import type { Entity, EntityColumnIds } from '../../common/entities';
 import { unflattenEntity } from '../../common/utils/unflatten_entity';
 import { useKibana } from './use_kibana';
-import { useInventoryParams } from './use_inventory_params';
-import { useInventorySearchBarContext } from '../context/inventory_search_bar_context_provider';
+import { useUnifiedSearchContext } from './use_unified_search_context';
 
 const ACTIVE_COLUMNS: EntityColumnIds[] = [ENTITY_DISPLAY_NAME, ENTITY_TYPE, ENTITY_LAST_SEEN];
 
@@ -25,32 +22,22 @@ export const useDiscoverRedirect = () => {
   const {
     services: { share, application, entityManager },
   } = useKibana();
-  const {
-    query: { kuery, entityTypes },
-  } = useInventoryParams('/*');
 
-  const { dataView } = useInventorySearchBarContext();
+  const {
+    dataView,
+    searchState: { query, filters, panelFilters },
+  } = useUnifiedSearchContext();
 
   const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR');
 
   const getDiscoverEntitiesRedirectUrl = useCallback(
     (entity?: Entity) => {
-      const filters: PhrasesFilter[] = [];
-
-      const entityTypeField = (dataView?.getFieldByName(ENTITY_TYPE) ??
-        entity?.[ENTITY_TYPE]) as DataViewField;
-
-      if (entityTypes && entityTypeField && dataView) {
-        const entityTypeFilter = buildPhrasesFilter(entityTypeField, entityTypes, dataView);
-        filters.push(entityTypeFilter);
-      }
-
       const entityKqlFilter = entity
         ? entityManager.entityClient.asKqlFilter(unflattenEntity(entity))
         : '';
 
       const kueryWithEntityDefinitionFilters = [
-        kuery,
+        query.query,
         entityKqlFilter,
         `${ENTITY_DEFINITION_ID} : builtin*`,
       ]
@@ -62,17 +49,18 @@ export const useDiscoverRedirect = () => {
             indexPatternId: dataView?.id ?? '',
             columns: ACTIVE_COLUMNS,
             query: { query: kueryWithEntityDefinitionFilters, language: 'kuery' },
-            filters,
+            filters: [...filters, ...panelFilters],
           })
         : undefined;
     },
     [
       application.capabilities.discover?.show,
+      dataView?.id,
       discoverLocator,
       entityManager.entityClient,
-      entityTypes,
-      kuery,
-      dataView,
+      filters,
+      panelFilters,
+      query.query,
     ]
   );
 
diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts
new file mode 100644
index 0000000000000..94df3a035f3bb
--- /dev/null
+++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts
@@ -0,0 +1,166 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import { buildEsQuery, type Filter, fromKueryExpression, type Query } from '@kbn/es-query';
+import createContainer from 'constate';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { map, Subject, Subscription, tap } from 'rxjs';
+import { generateFilters } from '@kbn/data-plugin/public';
+import useEffectOnce from 'react-use/lib/useEffectOnce';
+import deepEqual from 'fast-deep-equal';
+import { i18n } from '@kbn/i18n';
+import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public';
+import { useAdHocInventoryDataView } from './use_adhoc_inventory_data_view';
+import { useUnifiedSearchUrl } from './use_unified_search_url';
+import { useKibana } from './use_kibana';
+
+function useUnifiedSearch() {
+  const [isControlPanelsInitiated, setIsControlPanelsInitiated] = useState(false);
+  const { dataView } = useAdHocInventoryDataView();
+  const [refreshSubject$] = useState<Subject<void>>(new Subject());
+  const { searchState, setSearchState } = useUnifiedSearchUrl();
+  const kibanaQuerySettings = useKibanaQuerySettings();
+  const {
+    services: {
+      data: {
+        query: { filterManager: filterManagerService, queryString: queryStringService },
+      },
+      notifications,
+    },
+  } = useKibana();
+
+  useEffectOnce(() => {
+    if (!deepEqual(filterManagerService.getFilters(), searchState.filters)) {
+      filterManagerService.setFilters(
+        searchState.filters.map((item) => ({
+          ...item,
+          meta: { ...item.meta, index: dataView?.id },
+        }))
+      );
+    }
+
+    if (!deepEqual(queryStringService.getQuery(), searchState.query)) {
+      queryStringService.setQuery(searchState.query);
+    }
+  });
+
+  useEffect(() => {
+    const subscription = new Subscription();
+    subscription.add(
+      filterManagerService
+        .getUpdates$()
+        .pipe(
+          map(() => filterManagerService.getFilters()),
+          tap((filters) => setSearchState({ type: 'SET_FILTERS', filters }))
+        )
+        .subscribe()
+    );
+
+    subscription.add(
+      queryStringService
+        .getUpdates$()
+        .pipe(
+          map(() => queryStringService.getQuery() as Query),
+          tap((query) => setSearchState({ type: 'SET_QUERY', query }))
+        )
+        .subscribe()
+    );
+
+    return () => {
+      subscription.unsubscribe();
+    };
+  }, [filterManagerService, queryStringService, setSearchState]);
+
+  const validateQuery = useCallback(
+    (query: Query) => {
+      fromKueryExpression(query.query, kibanaQuerySettings);
+    },
+    [kibanaQuerySettings]
+  );
+
+  const onQueryChange = useCallback(
+    (query: Query) => {
+      try {
+        validateQuery(query);
+        setSearchState({ type: 'SET_QUERY', query });
+      } catch (e) {
+        const err = e as Error;
+        notifications.toasts.addDanger({
+          title: i18n.translate('xpack.inventory.unifiedSearchContext.queryError', {
+            defaultMessage: 'Error while updating the new query',
+          }),
+          text: err.message,
+        });
+      }
+    },
+    [validateQuery, setSearchState, notifications.toasts]
+  );
+
+  const onPanelFiltersChange = useCallback(
+    (panelFilters: Filter[]) => {
+      setSearchState({ type: 'SET_PANEL_FILTERS', panelFilters });
+    },
+    [setSearchState]
+  );
+
+  const onFiltersChange = useCallback(
+    (filters: Filter[]) => {
+      setSearchState({ type: 'SET_FILTERS', filters });
+    },
+    [setSearchState]
+  );
+
+  const addFilter = useCallback(
+    ({
+      fieldName,
+      operation,
+      value,
+    }: {
+      fieldName: string;
+      value: string;
+      operation: '+' | '-';
+    }) => {
+      if (dataView) {
+        const newFilters = generateFilters(
+          filterManagerService,
+          fieldName,
+          value,
+          operation,
+          dataView
+        );
+        setSearchState({ type: 'SET_FILTERS', filters: [...newFilters, ...searchState.filters] });
+      }
+    },
+    [dataView, filterManagerService, searchState.filters, setSearchState]
+  );
+
+  const stringifiedEsQuery = useMemo(() => {
+    if (dataView) {
+      return JSON.stringify(
+        buildEsQuery(dataView, searchState.query, [
+          ...searchState.panelFilters,
+          ...searchState.filters,
+        ])
+      );
+    }
+  }, [dataView, searchState.panelFilters, searchState.filters, searchState.query]);
+
+  return {
+    isControlPanelsInitiated,
+    setIsControlPanelsInitiated,
+    dataView,
+    refreshSubject$,
+    searchState,
+    addFilter,
+    stringifiedEsQuery,
+    onQueryChange,
+    onPanelFiltersChange,
+    onFiltersChange,
+  };
+}
+
+const UnifiedSearch = createContainer(useUnifiedSearch);
+export const [UnifiedSearchProvider, useUnifiedSearchContext] = UnifiedSearch;
diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts
new file mode 100644
index 0000000000000..17cf0ef0d9597
--- /dev/null
+++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts
@@ -0,0 +1,100 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import { FilterStateStore } from '@kbn/es-query';
+import { useUrlState } from '@kbn/observability-shared-plugin/public';
+import { enumeration } from '@kbn/securitysolution-io-ts-types';
+import { fold } from 'fp-ts/lib/Either';
+import { constant, identity } from 'fp-ts/lib/function';
+import { pipe } from 'fp-ts/lib/pipeable';
+import * as t from 'io-ts';
+import { useReducer } from 'react';
+import deepEqual from 'fast-deep-equal';
+
+const FilterRT = t.intersection([
+  t.type({
+    meta: t.partial({
+      alias: t.union([t.null, t.string]),
+      disabled: t.boolean,
+      negate: t.boolean,
+      controlledBy: t.string,
+      group: t.string,
+      index: t.string,
+      isMultiIndex: t.boolean,
+      type: t.string,
+      key: t.string,
+      params: t.any,
+      value: t.any,
+    }),
+  }),
+  t.partial({
+    query: t.record(t.string, t.any),
+    $state: t.type({
+      store: enumeration('FilterStateStore', FilterStateStore),
+    }),
+  }),
+]);
+const FiltersRT = t.array(FilterRT);
+
+const QueryStateRT = t.type({
+  language: t.string,
+  query: t.union([t.string, t.record(t.string, t.any)]),
+});
+
+const SearchStateRT = t.type({
+  panelFilters: FiltersRT,
+  filters: FiltersRT,
+  query: QueryStateRT,
+});
+
+const encodeUrlState = SearchStateRT.encode;
+const decodeUrlState = (value: unknown) => {
+  return pipe(SearchStateRT.decode(value), fold(constant(undefined), identity));
+};
+
+type SearchState = t.TypeOf<typeof SearchStateRT>;
+
+const INITIAL_VALUE: SearchState = {
+  query: { language: 'kuery', query: '' },
+  panelFilters: [],
+  filters: [],
+};
+
+export type StateAction =
+  | { type: 'SET_FILTERS'; filters: SearchState['filters'] }
+  | { type: 'SET_QUERY'; query: SearchState['query'] }
+  | { type: 'SET_PANEL_FILTERS'; panelFilters: SearchState['panelFilters'] };
+
+const reducer = (state: SearchState, action: StateAction): SearchState => {
+  switch (action.type) {
+    case 'SET_FILTERS':
+      return { ...state, filters: action.filters };
+    case 'SET_QUERY':
+      return { ...state, query: action.query };
+    case 'SET_PANEL_FILTERS':
+      return { ...state, panelFilters: action.panelFilters };
+    default:
+      return state;
+  }
+};
+
+export function useUnifiedSearchUrl() {
+  const [urlState, setUrlState] = useUrlState<SearchState>({
+    defaultState: INITIAL_VALUE,
+    decodeUrlState,
+    encodeUrlState,
+    urlStateKey: '_a',
+    writeDefaultState: true,
+  });
+
+  const [searchState, setSearchState] = useReducer(reducer, urlState);
+
+  if (!deepEqual(searchState, urlState)) {
+    setUrlState(searchState);
+  }
+
+  return { searchState, setSearchState };
+}
diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx
index 03f8b6475175a..f34df1a3c8b32 100644
--- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx
@@ -4,36 +4,12 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-import React, { useEffect } from 'react';
-import { useInventoryParams } from '../../hooks/use_inventory_params';
-import { useInventorySearchBarContext } from '../../context/inventory_search_bar_context_provider';
-import { useInventoryRouter } from '../../hooks/use_inventory_router';
-import { UnifiedInventory } from '../../components/grouped_inventory/unified_inventory';
+import React from 'react';
 import { GroupedInventory } from '../../components/grouped_inventory';
+import { UnifiedInventory } from '../../components/unified_inventory';
+import { useInventoryParams } from '../../hooks/use_inventory_params';
 
 export function InventoryPage() {
-  const { searchBarContentSubject$ } = useInventorySearchBarContext();
-  const inventoryRoute = useInventoryRouter();
   const { query } = useInventoryParams('/');
-
-  useEffect(() => {
-    const searchBarContentSubscription = searchBarContentSubject$.subscribe(
-      ({ ...queryParams }) => {
-        const { pagination: _, ...rest } = query;
-
-        inventoryRoute.push('/', {
-          path: {},
-          query: { ...rest, ...queryParams },
-        });
-      }
-    );
-    return () => {
-      searchBarContentSubscription.unsubscribe();
-    };
-    // If query has updated, the inventoryRoute state is also updated
-    // as well, so we only need to track changes on query.
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [query, searchBarContentSubject$]);
-
   return query.view === 'unified' ? <UnifiedInventory /> : <GroupedInventory />;
 }
diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx
index 36a15c5ae542c..bf5f8324aab25 100644
--- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx
@@ -9,12 +9,7 @@ import * as t from 'io-ts';
 import React from 'react';
 import { InventoryPageTemplate } from '../components/inventory_page_template';
 import { InventoryPage } from '../pages/inventory_page';
-import {
-  defaultEntitySortField,
-  entityTypesRt,
-  entityColumnIdsRt,
-  entityViewRt,
-} from '../../common/entities';
+import { defaultEntitySortField, entityColumnIdsRt, entityViewRt } from '../../common/entities';
 
 /**
  * The array of route definitions to be used when the application
@@ -34,10 +29,10 @@ const inventoryRoutes = {
           sortDirection: t.union([t.literal('asc'), t.literal('desc')]),
         }),
         t.partial({
-          entityTypes: entityTypesRt,
-          kuery: t.string,
           view: entityViewRt,
           pagination: t.string,
+          _a: t.string,
+          controlPanels: t.string,
         }),
       ]),
     }),
diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts
index 54d20ea324b11..c4c238fba5f8f 100644
--- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts
@@ -14,7 +14,6 @@ import {
   type EntityInventoryViewedParams,
   type EntityInventorySearchQuerySubmittedParams,
   type EntityViewClickedParams,
-  type EntityInventoryEntityTypeFilteredParams,
 } from './types';
 
 export class TelemetryClient implements ITelemetryClient {
@@ -34,12 +33,6 @@ export class TelemetryClient implements ITelemetryClient {
     this.analytics.reportEvent(TelemetryEventTypes.ENTITY_INVENTORY_SEARCH_QUERY_SUBMITTED, params);
   };
 
-  public reportEntityInventoryEntityTypeFiltered = (
-    params: EntityInventoryEntityTypeFilteredParams
-  ) => {
-    this.analytics.reportEvent(TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, params);
-  };
-
   public reportEntityViewClicked = (params: EntityViewClickedParams) => {
     this.analytics.reportEvent(TelemetryEventTypes.ENTITY_VIEW_CLICKED, params);
   };
diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts
index d61a90f7d30ab..ec2623fe2a2cc 100644
--- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts
@@ -49,15 +49,6 @@ const searchQuerySubmittedEventType: TelemetryEvent = {
         },
       },
     },
-    entity_types: {
-      type: 'array',
-      items: {
-        type: 'keyword',
-        _meta: {
-          description: 'Entity types used in the search.',
-        },
-      },
-    },
     action: {
       type: 'keyword',
       _meta: {
@@ -67,30 +58,6 @@ const searchQuerySubmittedEventType: TelemetryEvent = {
   },
 };
 
-const entityInventoryEntityTypeFilteredEventType: TelemetryEvent = {
-  eventType: TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED,
-  schema: {
-    entity_types: {
-      type: 'array',
-      items: {
-        type: 'keyword',
-        _meta: {
-          description: 'Entity types used in the filter.',
-        },
-      },
-    },
-    kuery_fields: {
-      type: 'array',
-      items: {
-        type: 'text',
-        _meta: {
-          description: 'Kuery fields used in the filter.',
-        },
-      },
-    },
-  },
-};
-
 const entityViewClickedEventType: TelemetryEvent = {
   eventType: TelemetryEventTypes.ENTITY_VIEW_CLICKED,
   schema: {
@@ -113,6 +80,5 @@ export const inventoryTelemetryEventBasedTypes = [
   inventoryAddDataEventType,
   entityInventoryViewedEventType,
   searchQuerySubmittedEventType,
-  entityInventoryEntityTypeFilteredEventType,
   entityViewClickedEventType,
 ];
diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts
index 415cf0e7d4406..639b771788f5b 100644
--- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts
@@ -13,7 +13,6 @@ import {
   type EntityViewClickedParams,
   type EntityInventorySearchQuerySubmittedParams,
   TelemetryEventTypes,
-  type EntityInventoryEntityTypeFilteredParams,
 } from './types';
 
 describe('TelemetryService', () => {
@@ -115,7 +114,6 @@ describe('TelemetryService', () => {
       const params: EntityInventorySearchQuerySubmittedParams = {
         kuery_fields: ['_index'],
         action: 'submit',
-        entity_types: ['container'],
       };
 
       telemetry.reportEntityInventorySearchQuerySubmitted(params);
@@ -128,26 +126,6 @@ describe('TelemetryService', () => {
     });
   });
 
-  describe('#reportEntityInventoryEntityTypeFiltered', () => {
-    it('should report entity type filtered with properties', async () => {
-      const setupParams = getSetupParams();
-      service.setup(setupParams);
-      const telemetry = service.start();
-      const params: EntityInventoryEntityTypeFilteredParams = {
-        kuery_fields: ['_index'],
-        entity_types: ['container'],
-      };
-
-      telemetry.reportEntityInventoryEntityTypeFiltered(params);
-
-      expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1);
-      expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith(
-        TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED,
-        params
-      );
-    });
-  });
-
   describe('#reportEntityViewClicked', () => {
     it('should report entity view clicked with properties', async () => {
       const setupParams = getSetupParams();
diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts
index 0e52d115d4597..0d56f44c2c2f2 100644
--- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts
@@ -27,15 +27,9 @@ export interface EntityInventoryViewedParams {
 
 export interface EntityInventorySearchQuerySubmittedParams {
   kuery_fields: string[];
-  entity_types: string[];
   action: 'submit' | 'refresh';
 }
 
-export interface EntityInventoryEntityTypeFilteredParams {
-  kuery_fields: string[];
-  entity_types: string[];
-}
-
 export interface EntityViewClickedParams {
   entity_type: string;
   view_type: 'detail' | 'flyout';
@@ -45,7 +39,6 @@ export type TelemetryEventParams =
   | InventoryAddDataParams
   | EntityInventoryViewedParams
   | EntityInventorySearchQuerySubmittedParams
-  | EntityInventoryEntityTypeFilteredParams
   | EntityViewClickedParams;
 
 export interface ITelemetryClient {
@@ -54,7 +47,6 @@ export interface ITelemetryClient {
   reportEntityInventorySearchQuerySubmitted(
     params: EntityInventorySearchQuerySubmittedParams
   ): void;
-  reportEntityInventoryEntityTypeFiltered(params: EntityInventoryEntityTypeFilteredParams): void;
   reportEntityViewClicked(params: EntityViewClickedParams): void;
 }
 
diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts
index b61f245f1aaf2..8c72e18bc0740 100644
--- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts
@@ -5,11 +5,9 @@
  * 2.0.
  */
 
+import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
 import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client';
-import { kqlQuery } from '@kbn/observability-utils/es/queries/kql_query';
 import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects';
-import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
-import { ScalarValue } from '@elastic/elasticsearch/lib/api/types';
 import {
   ENTITIES_LATEST_ALIAS,
   type EntityGroup,
@@ -20,38 +18,23 @@ import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper';
 export async function getEntityGroupsBy({
   inventoryEsClient,
   field,
-  kuery,
-  entityTypes,
+  esQuery,
 }: {
   inventoryEsClient: ObservabilityElasticsearchClient;
   field: string;
-  kuery?: string;
-  entityTypes?: string[];
+  esQuery?: QueryDslQueryContainer;
 }) {
   const from = `FROM ${ENTITIES_LATEST_ALIAS}`;
   const where = [getBuiltinEntityDefinitionIdESQLWhereClause()];
-  const params: ScalarValue[] = [];
 
-  if (entityTypes) {
-    where.push(`WHERE ${ENTITY_TYPE} IN (${entityTypes.map(() => '?').join()})`);
-    params.push(...entityTypes);
-  }
-
-  // STATS doesn't support parameterisation.
   const group = `STATS count = COUNT(*) by ${field}`;
   const sort = `SORT ${field} asc`;
-  // LIMIT doesn't support parameterisation.
   const limit = `LIMIT ${MAX_NUMBER_OF_ENTITIES}`;
   const query = [from, ...where, group, sort, limit].join(' | ');
 
   const groups = await inventoryEsClient.esql('get_entities_groups', {
     query,
-    filter: {
-      bool: {
-        filter: kqlQuery(kuery),
-      },
-    },
-    params,
+    filter: esQuery,
   });
 
   return esqlResultToPlainObjects<EntityGroup>(groups);
diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts
index c95a488ad49dd..402d11720a9da 100644
--- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts
@@ -5,11 +5,10 @@
  * 2.0.
  */
 
+import type { QueryDslQueryContainer, ScalarValue } from '@elastic/elasticsearch/lib/api/types';
+import { ENTITY_LAST_SEEN, ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
 import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client';
-import { kqlQuery } from '@kbn/observability-utils/es/queries/kql_query';
 import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects';
-import { ENTITY_LAST_SEEN, ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
-import type { ScalarValue } from '@elastic/elasticsearch/lib/api/types';
 import {
   ENTITIES_LATEST_ALIAS,
   MAX_NUMBER_OF_ENTITIES,
@@ -22,14 +21,14 @@ export async function getLatestEntities({
   inventoryEsClient,
   sortDirection,
   sortField,
+  esQuery,
   entityTypes,
-  kuery,
 }: {
   inventoryEsClient: ObservabilityElasticsearchClient;
   sortDirection: 'asc' | 'desc';
   sortField: EntityColumnIds;
+  esQuery?: QueryDslQueryContainer;
   entityTypes?: string[];
-  kuery?: string;
 }) {
   // alertsCount doesn't exist in entities index. Ignore it and sort by entity.lastSeenTimestamp by default.
   const entitiesSortField = sortField === 'alertsCount' ? ENTITY_LAST_SEEN : sortField;
@@ -50,11 +49,7 @@ export async function getLatestEntities({
 
   const latestEntitiesEsqlResponse = await inventoryEsClient.esql('get_latest_entities', {
     query,
-    filter: {
-      bool: {
-        filter: [...kqlQuery(kuery)],
-      },
-    },
+    filter: esQuery,
     params,
   });
 
diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts
index e969f1d537e99..8126c69de6922 100644
--- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts
@@ -5,9 +5,9 @@
  * 2.0.
  */
 
-import { kqlQuery, termQuery } from '@kbn/observability-plugin/server';
-import { ALERT_STATUS, ALERT_STATUS_ACTIVE } from '@kbn/rule-data-utils';
+import { termQuery } from '@kbn/observability-plugin/server';
 import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common';
+import { ALERT_STATUS, ALERT_STATUS_ACTIVE } from '@kbn/rule-data-utils';
 import { AlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client';
 import { getGroupByTermsAgg } from './get_group_by_terms_agg';
 import { IdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type';
@@ -21,11 +21,9 @@ type EntityTypeBucketsAggregation = Record<string, { buckets: Bucket[] }>;
 
 export async function getLatestEntitiesAlerts({
   alertsClient,
-  kuery,
   identityFieldsPerEntityType,
 }: {
   alertsClient: AlertsClient;
-  kuery?: string;
   identityFieldsPerEntityType: IdentityFieldsPerEntityType;
 }): Promise<Array<{ [key: string]: any; alertsCount?: number; [ENTITY_TYPE]: string }>> {
   if (identityFieldsPerEntityType.size === 0) {
@@ -37,7 +35,7 @@ export async function getLatestEntitiesAlerts({
     track_total_hits: false,
     query: {
       bool: {
-        filter: [...termQuery(ALERT_STATUS, ALERT_STATUS_ACTIVE), ...kqlQuery(kuery)],
+        filter: termQuery(ALERT_STATUS, ALERT_STATUS_ACTIVE),
       },
     },
   };
diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts
index 88d6cb68ee214..ae99713375b19 100644
--- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts
@@ -47,8 +47,8 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({
         sortDirection: t.union([t.literal('asc'), t.literal('desc')]),
       }),
       t.partial({
+        esQuery: jsonRt.pipe(t.UnknownRecord),
         entityTypes: jsonRt.pipe(t.array(t.string)),
-        kuery: t.string,
       }),
     ]),
   }),
@@ -69,7 +69,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({
       plugin: `@kbn/${INVENTORY_APP_ID}-plugin`,
     });
 
-    const { sortDirection, sortField, entityTypes, kuery } = params.query;
+    const { sortDirection, sortField, esQuery, entityTypes } = params.query;
 
     const [alertsClient, latestEntities] = await Promise.all([
       createAlertsClient({ plugins, request }),
@@ -77,8 +77,8 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({
         inventoryEsClient,
         sortDirection,
         sortField,
+        esQuery,
         entityTypes,
-        kuery,
       }),
     ]);
 
@@ -87,7 +87,6 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({
     const alerts = await getLatestEntitiesAlerts({
       identityFieldsPerEntityType,
       alertsClient,
-      kuery,
     });
 
     const joined = joinByKey(
@@ -114,8 +113,7 @@ export const groupEntitiesByRoute = createInventoryServerRoute({
     t.type({ path: t.type({ field: t.literal(ENTITY_TYPE) }) }),
     t.partial({
       query: t.partial({
-        kuery: t.string,
-        entityTypes: jsonRt.pipe(t.array(t.string)),
+        esQuery: jsonRt.pipe(t.UnknownRecord),
       }),
     }),
   ]),
@@ -131,13 +129,12 @@ export const groupEntitiesByRoute = createInventoryServerRoute({
     });
 
     const { field } = params.path;
-    const { kuery, entityTypes } = params.query ?? {};
+    const { esQuery } = params.query ?? {};
 
     const groups = await getEntityGroupsBy({
       inventoryEsClient,
       field,
-      kuery,
-      entityTypes,
+      esQuery,
     });
 
     const entitiesCount = groups.reduce((acc, group) => acc + group.count, 0);
diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json
index d41ef612c9574..5cb95e8ac6de5 100644
--- a/x-pack/plugins/observability_solution/inventory/tsconfig.json
+++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json
@@ -56,6 +56,8 @@
     "@kbn/zod",
     "@kbn/dashboard-plugin",
     "@kbn/deeplinks-analytics",
+    "@kbn/controls-plugin",
+    "@kbn/securitysolution-io-ts-types",
     "@kbn/react-hooks"
   ]
 }
diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx
index a9c45828a7555..f82e9436fe5cd 100644
--- a/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx
+++ b/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx
@@ -16,13 +16,13 @@ import { noop } from 'lodash';
 import React, { useCallback, useEffect, useMemo } from 'react';
 import usePrevious from 'react-use/lib/usePrevious';
 import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
+import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public';
 import { LogEntryCursor } from '../../../common/log_entry';
 import { defaultLogViewsStaticConfig, LogViewReference } from '../../../common/log_views';
 import { BuiltEsQuery, useLogStream } from '../../containers/logs/log_stream';
 import { useLogView } from '../../hooks/use_log_view';
 import { LogViewsClient } from '../../services/log_views';
 import { LogColumnRenderConfiguration } from '../../utils/log_column_render_configuration';
-import { useKibanaQuerySettings } from '../../utils/use_kibana_query_settings';
 import { useLogEntryFlyout } from '../logging/log_entry_flyout';
 import { ScrollableLogTextStreamView, VisibleInterval } from '../logging/log_text_stream';
 import { LogStreamErrorBoundary } from './log_stream_error_boundary';
diff --git a/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts b/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts
deleted file mode 100644
index 521cd0142303b..0000000000000
--- a/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import type { EsQueryConfig } from '@kbn/es-query';
-import { SerializableRecord } from '@kbn/utility-types';
-import { useMemo } from 'react';
-import { UI_SETTINGS } from '@kbn/data-plugin/public';
-import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
-
-export const useKibanaQuerySettings = (): EsQueryConfig => {
-  const [allowLeadingWildcards] = useUiSetting$<boolean>(UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS);
-  const [queryStringOptions] = useUiSetting$<SerializableRecord>(UI_SETTINGS.QUERY_STRING_OPTIONS);
-  const [dateFormatTZ] = useUiSetting$<string>(UI_SETTINGS.DATEFORMAT_TZ);
-  const [ignoreFilterIfFieldNotInIndex] = useUiSetting$<boolean>(
-    UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX
-  );
-
-  return useMemo(
-    () => ({
-      allowLeadingWildcards,
-      queryStringOptions,
-      dateFormatTZ,
-      ignoreFilterIfFieldNotInIndex,
-    }),
-    [allowLeadingWildcards, dateFormatTZ, ignoreFilterIfFieldNotInIndex, queryStringOptions]
-  );
-};
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts
similarity index 63%
rename from x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts
rename to x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts
index 19c0580c73f86..0ade125dcf816 100644
--- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts
+++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts
@@ -12,85 +12,49 @@ import { fold } from 'fp-ts/lib/Either';
 import { constant, identity } from 'fp-ts/lib/function';
 import type { DataView } from '@kbn/data-views-plugin/public';
 import { useMemo } from 'react';
-import { useUrlState } from '../../../../hooks/use_url_state';
+import { useUrlState } from './use_url_state';
 
-const HOST_FILTERS_URL_STATE_KEY = 'controlPanels';
+const CONTROL_PANELS_URL_KEY = 'controlPanels';
 
-export const availableControlsPanels = {
-  HOST_OS_NAME: 'host.os.name',
-  CLOUD_PROVIDER: 'cloud.provider',
-  SERVICE_NAME: 'service.name',
-};
-
-const controlPanelConfigs: ControlPanels = {
-  [availableControlsPanels.HOST_OS_NAME]: {
-    order: 0,
-    width: 'medium',
-    grow: false,
-    type: 'optionsListControl',
-    fieldName: availableControlsPanels.HOST_OS_NAME,
-    title: 'Operating System',
-  },
-  [availableControlsPanels.CLOUD_PROVIDER]: {
-    order: 1,
-    width: 'medium',
-    grow: false,
-    type: 'optionsListControl',
-    fieldName: availableControlsPanels.CLOUD_PROVIDER,
-    title: 'Cloud Provider',
-  },
-  [availableControlsPanels.SERVICE_NAME]: {
-    order: 2,
-    width: 'medium',
-    grow: false,
-    type: 'optionsListControl',
-    fieldName: availableControlsPanels.SERVICE_NAME,
-    title: 'Service Name',
-  },
-};
+const PanelRT = rt.intersection([
+  rt.type({
+    order: rt.number,
+    type: rt.string,
+  }),
+  rt.partial({
+    width: rt.union([rt.literal('medium'), rt.literal('small'), rt.literal('large')]),
+    grow: rt.boolean,
+    dataViewId: rt.string,
+    fieldName: rt.string,
+    title: rt.union([rt.string, rt.undefined]),
+    selectedOptions: rt.array(rt.string),
+  }),
+]);
 
-const availableControlPanelFields = Object.values(availableControlsPanels);
+const ControlPanelRT = rt.record(rt.string, PanelRT);
+export type ControlPanels = rt.TypeOf<typeof ControlPanelRT>;
 
-export const useControlPanels = (
+const getVisibleControlPanels = (
+  availableControlPanelFields: string[],
   dataView: DataView | undefined
-): [ControlPanels, (state: ControlPanels) => void] => {
-  const defaultState = useMemo(() => getVisibleControlPanelsConfig(dataView), [dataView]);
-
-  const [controlPanels, setControlPanels] = useUrlState<ControlPanels>({
-    defaultState,
-    decodeUrlState,
-    encodeUrlState,
-    urlStateKey: HOST_FILTERS_URL_STATE_KEY,
-  });
-
-  /**
-   * Configure the control panels as
-   * 1. Available fields from the data view
-   * 2. Existing filters from the URL parameter (not colliding with allowed fields from data view)
-   * 3. Enhanced with dataView.id
-   */
-  const controlsPanelsWithId = dataView
-    ? mergeDefaultPanelsWithUrlConfig(dataView, controlPanels)
-    : ({} as ControlPanels);
-
-  return [controlsPanelsWithId, setControlPanels];
-};
-
-/**
- * Utils
- */
-const getVisibleControlPanels = (dataView: DataView | undefined) => {
+) => {
   return availableControlPanelFields.filter(
     (panelKey) => dataView?.fields.getByName(panelKey) !== undefined
   );
 };
 
-const getVisibleControlPanelsConfig = (dataView: DataView | undefined) => {
-  return getVisibleControlPanels(dataView).reduce((panelsMap, panelKey) => {
-    const config = controlPanelConfigs[panelKey];
-
-    return { ...panelsMap, [panelKey]: config };
-  }, {} as ControlPanels);
+const getVisibleControlPanelsConfig = (
+  controlPanelConfigs: ControlPanels,
+  dataView: DataView | undefined
+) => {
+  return getVisibleControlPanels(Object.keys(controlPanelConfigs), dataView).reduce(
+    (panelsMap, panelKey) => {
+      const config = controlPanelConfigs[panelKey];
+
+      return { ...panelsMap, [panelKey]: config };
+    },
+    {} as ControlPanels
+  );
 };
 
 const addDataViewIdToControlPanels = (controlPanels: ControlPanels, dataViewId: string = '') => {
@@ -115,9 +79,13 @@ const cleanControlPanels = (controlPanels: ControlPanels) => {
   }, {});
 };
 
-const mergeDefaultPanelsWithUrlConfig = (dataView: DataView, urlPanels: ControlPanels = {}) => {
+const mergeDefaultPanelsWithUrlConfig = (
+  dataView: DataView,
+  urlPanels: ControlPanels = {},
+  controlPanelConfigs: ControlPanels
+) => {
   // Get default panel configs from existing fields in data view
-  const visiblePanels = getVisibleControlPanelsConfig(dataView);
+  const visiblePanels = getVisibleControlPanelsConfig(controlPanelConfigs, dataView);
 
   // Get list of panel which can be overridden to avoid merging additional config from url
   const existingKeys = Object.keys(visiblePanels);
@@ -130,25 +98,6 @@ const mergeDefaultPanelsWithUrlConfig = (dataView: DataView, urlPanels: ControlP
   );
 };
 
-const PanelRT = rt.intersection([
-  rt.type({
-    order: rt.number,
-    type: rt.string,
-  }),
-  rt.partial({
-    width: rt.union([rt.literal('medium'), rt.literal('small'), rt.literal('large')]),
-    grow: rt.boolean,
-    dataViewId: rt.string,
-    fieldName: rt.string,
-    title: rt.union([rt.string, rt.undefined]),
-    selectedOptions: rt.array(rt.string),
-  }),
-]);
-
-const ControlPanelRT = rt.record(rt.string, PanelRT);
-
-type ControlPanels = rt.TypeOf<typeof ControlPanelRT>;
-
 const encodeUrlState = (value: ControlPanels) => {
   if (value) {
     // Remove the dataView.id on update to make the control panels portable between data views
@@ -163,3 +112,32 @@ const decodeUrlState = (value: unknown) => {
     return pipe(ControlPanelRT.decode(value), fold(constant({}), identity));
   }
 };
+
+export const useControlPanels = (
+  controlPanelConfigs: ControlPanels,
+  dataView: DataView | undefined
+): [ControlPanels, (state: ControlPanels) => void] => {
+  const defaultState = useMemo(
+    () => getVisibleControlPanelsConfig(controlPanelConfigs, dataView),
+    [controlPanelConfigs, dataView]
+  );
+
+  const [controlPanels, setControlPanels] = useUrlState<ControlPanels>({
+    defaultState,
+    decodeUrlState,
+    encodeUrlState,
+    urlStateKey: CONTROL_PANELS_URL_KEY,
+  });
+
+  /**
+   * Configure the control panels as
+   * 1. Available fields from the data view
+   * 2. Existing filters from the URL parameter (not colliding with allowed fields from data view)
+   * 3. Enhanced with dataView.id
+   */
+  const controlsPanelsWithId = dataView
+    ? mergeDefaultPanelsWithUrlConfig(dataView, controlPanels, controlPanelConfigs)
+    : ({} as ControlPanels);
+
+  return [controlsPanelsWithId, setControlPanels];
+};
diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_kibana_query_settings.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_kibana_query_settings.ts
similarity index 100%
rename from x-pack/plugins/observability_solution/infra/public/hooks/use_kibana_query_settings.ts
rename to x-pack/plugins/observability_solution/observability_shared/public/hooks/use_kibana_query_settings.ts
diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_url_state.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_url_state.ts
similarity index 81%
rename from x-pack/plugins/observability_solution/infra/public/hooks/use_url_state.ts
rename to x-pack/plugins/observability_solution/observability_shared/public/hooks/use_url_state.ts
index a581e6536e487..ac18fbe413005 100644
--- a/x-pack/plugins/observability_solution/infra/public/hooks/use_url_state.ts
+++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_url_state.ts
@@ -5,12 +5,12 @@
  * 2.0.
  */
 
-import { parse } from 'query-string';
+import { parse, stringify } from 'query-string';
 import { Location } from 'history';
 import { useCallback, useEffect, useMemo, useState } from 'react';
-import { decode, RisonValue } from '@kbn/rison';
+import { decode, encode, RisonValue } from '@kbn/rison';
 import { useHistory } from 'react-router-dom';
-import { replaceStateKeyInQueryString } from '../../common/url_state_storage_service';
+import { url } from '@kbn/kibana-utils-plugin/common';
 
 export const useUrlState = <State>({
   defaultState,
@@ -94,7 +94,7 @@ export const useUrlState = <State>({
   return [state, setState] as [typeof state, typeof setState];
 };
 
-const decodeRisonUrlState = (value: string | undefined | null): RisonValue | undefined => {
+export const decodeRisonUrlState = (value: string | undefined | null): RisonValue | undefined => {
   try {
     return value ? decode(value) : undefined;
   } catch (error) {
@@ -124,3 +124,19 @@ const replaceQueryStringInLocation = (location: Location, queryString: string):
     };
   }
 };
+
+const encodeRisonUrlState = (state: any) => encode(state);
+
+const replaceStateKeyInQueryString =
+  <UrlState extends any>(stateKey: string, urlState: UrlState | undefined) =>
+  (queryString: string) => {
+    const previousQueryValues = parse(queryString, { sort: false });
+    const newValue =
+      typeof urlState === 'undefined'
+        ? previousQueryValues
+        : {
+            ...previousQueryValues,
+            [stateKey]: encodeRisonUrlState(urlState),
+          };
+    return stringify(url.encodeQuery(newValue), { sort: false, encode: false });
+  };
diff --git a/x-pack/plugins/observability_solution/observability_shared/public/index.ts b/x-pack/plugins/observability_solution/observability_shared/public/index.ts
index d732a669e45bd..bc9f2c452cc8c 100644
--- a/x-pack/plugins/observability_solution/observability_shared/public/index.ts
+++ b/x-pack/plugins/observability_solution/observability_shared/public/index.ts
@@ -104,3 +104,7 @@ export { BottomBarActions } from './components/bottom_bar_actions/bottom_bar_act
 export { FieldValueSelection, FieldValueSuggestions } from './components';
 
 export { AddDataPanel, type AddDataPanelProps } from './components/add_data_panel';
+
+export { useUrlState } from './hooks/use_url_state';
+export { type ControlPanels, useControlPanels } from './hooks/use_control_panels_url_state';
+export { useKibanaQuerySettings } from './hooks/use_kibana_query_settings';
diff --git a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
index f68649c85cea6..f7b8a7ff6c573 100644
--- a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
+++ b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
@@ -45,6 +45,7 @@
     "@kbn/rule-data-utils",
     "@kbn/es-query",
     "@kbn/serverless",
+    "@kbn/data-views-plugin",
   ],
   "exclude": ["target/**/*", ".storybook/**/*.js"]
 }
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index b09cf530d4d81..e08e20da3db7f 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -26278,8 +26278,6 @@
     "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "Horodatage des dernières données reçues pour l'entité (entity.lastSeenTimestamp)",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "Type",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "Type d'entité (entity.type)",
-    "xpack.inventory.entityTypesControls.euiComboBox.accessibleScreenReaderLabel": "Filtre des types d'entités",
-    "xpack.inventory.entityTypesControls.euiComboBox.placeHolderLabel": "Types",
     "xpack.inventory.featureRegistry.inventoryFeatureName": "Inventory",
     "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "Alertes actives",
     "xpack.inventory.inventoryLinkTitle": "Inventory",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 2d688e5515168..fb6c140e387b2 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -26249,8 +26249,6 @@
     "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "エンティティで最後に受信したデータのタイムスタンプ(entity.lastSeenTimestamp)",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "型",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "エンティティのタイプ(entity.type)",
-    "xpack.inventory.entityTypesControls.euiComboBox.accessibleScreenReaderLabel": "エンティティタイプフィルター",
-    "xpack.inventory.entityTypesControls.euiComboBox.placeHolderLabel": "タイプ",
     "xpack.inventory.featureRegistry.inventoryFeatureName": "インベントリ",
     "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "アクティブアラート",
     "xpack.inventory.inventoryLinkTitle": "インベントリ",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 9207d831ac72e..a903fc5900e61 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -26306,8 +26306,6 @@
     "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "上次接收的实体数据的时间戳 (entity.lastSeenTimestamp)",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "类型",
     "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "实体的类型 (entity.type)",
-    "xpack.inventory.entityTypesControls.euiComboBox.accessibleScreenReaderLabel": "实体类型筛选",
-    "xpack.inventory.entityTypesControls.euiComboBox.placeHolderLabel": "类型",
     "xpack.inventory.featureRegistry.inventoryFeatureName": "库存",
     "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "活动告警",
     "xpack.inventory.inventoryLinkTitle": "库存",