Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ import { CreateIndexButton } from '../../sections/home/index_list/create_index/c
import type { ExtensionsService } from '../../../services/extensions_service';

export const NoMatch = ({
loadIndices,
filter,
resetFilter,
extensionsService,
share,
}: {
loadIndices: () => void;
filter: string;
resetFilter: () => void;
extensionsService: ExtensionsService;
Expand Down Expand Up @@ -66,11 +64,7 @@ export const NoMatch = ({
if (extensionsService.emptyListContent) {
return extensionsService.emptyListContent.renderContent({
createIndexButton: (
<CreateIndexButton
loadIndices={loadIndices}
share={share}
dataTestSubj="createIndexButtonEmptyList"
/>
<CreateIndexButton share={share} dataTestSubj="createIndexButtonEmptyList" />
),
});
}
Expand All @@ -94,13 +88,7 @@ export const NoMatch = ({
/>
</p>
}
actions={
<CreateIndexButton
loadIndices={loadIndices}
share={share}
dataTestSubj="createIndexButtonEmptyList"
/>
}
actions={<CreateIndexButton share={share} dataTestSubj="createIndexButtonEmptyList" />}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import {
useKibana as useKibanaReactPlugin,
KibanaRenderContextProvider,
} from '../shared_imports';
import { loadIndices$ } from './services/api';

import type { AppDependencies } from './app_context';
import { AppContextProvider } from './app_context';
import { App } from './app';
import { indexManagementStore } from './store';
import { ComponentTemplatesProvider, MappingsEditorProvider } from './components';
import { loadIndicesSuccess } from './store/actions/load_indices';

const { GlobalFlyoutProvider } = GlobalFlyout;

Expand Down Expand Up @@ -80,11 +82,16 @@ export const IndexManagementAppContext: React.FC<IndexManagementAppContextProps>
startServices,
};

const store = indexManagementStore(services);
loadIndices$.subscribe((indices) => {
store.dispatch(loadIndicesSuccess({ indices }));
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if this is the right place to park this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe I should pass the loadIndices function via the AppContextProvider.

There's also a reloadIndices function somewhere in there that I should examine.

return (
<KibanaRenderContextProvider {...core}>
<KibanaReactContextProvider>
<RedirectAppLinks coreStart={core}>
<Provider store={indexManagementStore(services)}>
<Provider store={store}>
<AppContextProvider value={{ ...dependencies, overlays }}>
<MappingsEditorProvider>
<ComponentTemplatesProvider value={componentTemplateProviderValues}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ import { CreateIndexModal } from './create_index_modal';
import { useAppContext } from '../../../../app_context';

export interface CreateIndexButtonProps {
loadIndices: () => void;
share?: SharePluginStart;
dataTestSubj?: string;
}

export const CreateIndexButton = ({ loadIndices, share, dataTestSubj }: CreateIndexButtonProps) => {
export const CreateIndexButton = ({ share, dataTestSubj }: CreateIndexButtonProps) => {
const [createIndexModalOpen, setCreateIndexModalOpen] = useState<boolean>(false);
const createIndexUrl = share?.url.locators.get('SEARCH_CREATE_INDEX')?.useUrl({});

Expand Down Expand Up @@ -51,10 +50,7 @@ export const CreateIndexButton = ({ loadIndices, share, dataTestSubj }: CreateIn
/>
</EuiButton>
{createIndexModalOpen && (
<CreateIndexModal
closeModal={() => setCreateIndexModalOpen(false)}
loadIndices={loadIndices}
/>
<CreateIndexModal closeModal={() => setCreateIndexModalOpen(false)} />
)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { LOOKUP_INDEX_MODE, STANDARD_INDEX_MODE } from '../../../../../../common
import { indexModeDescriptions, indexModeLabels } from '../../../../lib/index_mode_labels';
import { createIndex } from '../../../../services';
import { notificationService } from '../../../../services/notification';
import { loadIndices } from '../../../../services/api';

import { isValidIndexName } from './utils';

Expand All @@ -40,10 +41,9 @@ const INVALID_INDEX_NAME_ERROR = i18n.translate(

export interface CreateIndexModalProps {
closeModal: () => void;
loadIndices: () => void;
}

export const CreateIndexModal = ({ closeModal, loadIndices }: CreateIndexModalProps) => {
export const CreateIndexModal = ({ closeModal }: CreateIndexModalProps) => {
const modalTitleId = useGeneratedHtmlId();

const [indexName, setIndexName] = useState<string>('');
Expand All @@ -65,6 +65,7 @@ export const CreateIndexModal = ({ closeModal, loadIndices }: CreateIndexModalPr
})
);
closeModal();

loadIndices();
return;
}
Expand All @@ -73,7 +74,7 @@ export const CreateIndexModal = ({ closeModal, loadIndices }: CreateIndexModalPr
setIsSaving(false);
setCreateError(e.message);
}
}, [closeModal, indexMode, indexName, loadIndices]);
}, [closeModal, indexMode, indexName]);

const onSave = () => {
if (isValidIndexName(indexName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
pageChanged,
pageSizeChanged,
sortChanged,
loadIndices,
toggleChanged,
performExtensionAction,
} from '../../../../store/actions';
Expand Down Expand Up @@ -61,9 +60,6 @@ const mapDispatchToProps = (dispatch) => {
toggleChanged: (toggleName, toggleValue) => {
dispatch(toggleChanged({ toggleName, toggleValue }));
},
loadIndices: () => {
dispatch(loadIndices());
},
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Previously this was firing off the request and then getting the data back. I need something that could respond to multiple data sets being passed.

Copy link
Copy Markdown
Contributor

@kapral18 kapral18 Jan 15, 2026

Choose a reason for hiding this comment

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

Previously this was firing off the request and then getting the data back. I need something that could respond to multiple data sets being passed.

Totally get the intent, but we don't need RxJS here to achieve this. Redux already provides the “emit + subscribe” mechanism: each dispatch() is an emit, and the UI is already subscribed via react-redux (connect/selectors). So “multiple data sets” maps naturally to “dispatch multiple times as each chunk arrives”.

Here's an async/await shape (pseudo-code — names like currentRequestId / indicesEnrichmentSuccess are illustrative; you'd need to add the corresponding state/actions if you want this exact pattern) that probably matches what you're aiming for:

import { v4 as uuidv4 } from 'uuid';

export const loadIndices = () => async (dispatch, getState, { api }) => {
  const requestId = uuidv4();
  dispatch(loadIndicesStart({ requestId }));

  // 1) base list first (renders quickly)
  try {
    const base = await api.getIndicesBase();
    if (getState().indices.currentRequestId !== requestId) return; // ignore stale
    dispatch(loadIndicesSuccess({ requestId, indices: base }));
  } catch (error) {
    if (getState().indices.currentRequestId !== requestId) return; // ignore stale
    dispatch(loadIndicesError({ requestId, error }));
    return;
  }

  // 2) slow/optional enrichers in parallel (best-effort, progressive)
  const run = async (name, fn) => {
    try {
      const patch = await fn();
      if (getState().indices.currentRequestId !== requestId) return; // ignore stale
      dispatch(indicesEnrichmentSuccess({ requestId, name, patch }));
    } catch (error) {
      if (getState().indices.currentRequestId !== requestId) return; // ignore stale
      dispatch(indicesEnrichmentError({ requestId, name, error }));
    }
  };

  void run('stats', () => api.getIndicesStats());
  void run('other', () => api.getOtherEnrichment());
  // ...repeat for the other calls
};

The key idea is just: dispatch base ASAP, then dispatch progressive updates as each slow call returns, and record enrich failures without breaking the base list.

performExtensionAction: (requestMethod, successMessage, indexNames) => {
dispatch(performExtensionAction({ requestMethod, successMessage, indexNames }));
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { CreateIndexButton } from '../create_index/create_index_button';
import { IndexTablePagination, PAGE_SIZE_OPTIONS } from './index_table_pagination';
import { DocCountCell } from './doc_count';
import { docCountApi } from './get_doc_count';
import { loadIndices } from '../../../../services/api';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pulling loadIndices from services/api here means this component is directly triggering the fetch/emission path, instead of going through the existing Redux async flow. In this PR, store/actions/load_indices.js only defines loadIndicesStart/loadIndicesSuccess/loadIndicesError, so indicesLoading/indicesError won't naturally reflect retries/failures when callers invoke services/api.loadIndices() directly.

I think it’ll be easier to keep the progressive behavior and keep React/Redux happy if IndexTable calls a connected prop (e.g. props.loadIndices() from index_table.container.js), and that entrypoint dispatches start/error and kicks off the progressive load.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah, I think I need to learn the redux way of doing things. This is my first time using it in quite a while and this isn't a simple use case so its not immediately clear how to. Sorting my thoughts out in another PR where I'm only concerned with data loading is helpful so I can have a better idea of the specific needs I have for working with the state system.


const getColumnConfigs = ({
showIndexStats,
Expand Down Expand Up @@ -207,7 +208,7 @@ export class IndexTable extends Component {
}

componentDidMount() {
this.props.loadIndices();
loadIndices();

const { filterChanged, pageSizeChanged, pageChanged, toggleNameToVisibleMap, toggleChanged } =
this.props;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { IndicesStatsResponse } from '@elastic/elasticsearch/lib/api/types'
import type { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils';
import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types';
import type { ReindexService } from '@kbn/reindex-service-plugin/public';
import { from, Subject, mergeMap } from 'rxjs';
import {
API_BASE_PATH,
INTERNAL_API_BASE_PATH,
Expand Down Expand Up @@ -142,9 +143,12 @@ export async function updateDSFailureStore(

export async function loadIndices() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

While this function currently passes a single response to the Subject, the plan is to integrate code that would call a number of endpoints and mush the data together and return it.

const response = await httpService.httpClient.get<any>(`${API_BASE_PATH}/indices`);
return response.data ? response.data : response;
internalLoadIndicesSubject.next(response.data);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Perhaps this could update the store directly instead of using RxJS

Copy link
Copy Markdown
Contributor

@kapral18 kapral18 Jan 16, 2026

Choose a reason for hiding this comment

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

I’d keep services/api.ts free of direct store dispatching; better to orchestrate progressive loads in a thunk and let Redux dispatches be the “emissions”.

}

const internalLoadIndicesSubject = new Subject<{}>();
export const loadIndices$ = internalLoadIndicesSubject.asObservable();

export async function reloadIndices(
indexNames: string[],
{ asSystemRequest }: ReloadIndicesOptions = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,7 @@
*/

import { createAction } from 'redux-actions';
import { loadIndices as request } from '../../services';

export const loadIndicesStart = createAction('INDEX_MANAGEMENT_LOAD_INDICES_START');
export const loadIndicesSuccess = createAction('INDEX_MANAGEMENT_LOAD_INDICES_SUCCESS');
export const loadIndicesError = createAction('INDEX_MANAGEMENT_LOAD_INDICES_ERROR');

export const loadIndices = () => async (dispatch) => {
dispatch(loadIndicesStart());
let indices;
try {
indices = await request();
} catch (error) {
return dispatch(loadIndicesError(error));
}
dispatch(loadIndicesSuccess({ indices }));
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import { createAction } from 'redux-actions';
import { i18n } from '@kbn/i18n';
import { reloadIndices as request } from '../../services';
import { loadIndices } from './load_indices';
import { notificationService } from '../../services/notification';
import { loadIndices } from '../../services/api';

export const reloadIndicesSuccess = createAction('INDEX_MANAGEMENT_RELOAD_INDICES_SUCCESS');
export const reloadIndices = (indexNames, options) => async (dispatch) => {
Expand All @@ -21,7 +21,7 @@ export const reloadIndices = (indexNames, options) => async (dispatch) => {
// or the user does not have privileges for one of the indices on the current page,
// reload the full list
if (error.status === 404 || error.status === 403) {
return dispatch(loadIndices());
loadIndices();
}
return notificationService.showDangerToast(error.body.message);
}
Expand Down