Skip to content

Commit

Permalink
use separate cases state context
Browse files Browse the repository at this point in the history
  • Loading branch information
semd committed May 24, 2024
1 parent 39e1468 commit 96f5924
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { CasesContext } from '../../cases_context';
import {
CasesContextStoreActionsList,
getInitialCasesContextState,
} from '../../cases_context/cases_context_reducer';
} from '../../cases_context/state/cases_context_reducer';
import { ExternalReferenceAttachmentTypeRegistry } from '../../../client/attachment_framework/external_reference_registry';
import type { AddToExistingCaseModalProps } from './use_cases_add_to_existing_case_modal';
import { useCasesAddToExistingCaseModal } from './use_cases_add_to_existing_case_modal';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CaseStatuses } from '../../../../common/types/domain';
import type { AllCasesSelectorModalProps } from '.';
import { useCasesToast } from '../../../common/use_cases_toast';
import type { CaseUI } from '../../../containers/types';
import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer';
import { CasesContextStoreActionsList } from '../../cases_context/state/cases_context_reducer';
import { useCasesContext } from '../../cases_context/use_cases_context';
import { useCasesAddToNewCaseFlyout } from '../../create/flyout/use_cases_add_to_new_case_flyout';
import type { CaseAttachmentsWithoutOwner } from '../../../types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getAllCasesSelectorModalNoProviderLazy } from '../../client/ui/get_all_
import { getCreateCaseFlyoutLazyNoProvider } from '../../client/ui/get_create_case_flyout';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
import { getInitialCasesContextState } from './cases_context_reducer';
import { getInitialCasesContextState } from './state/cases_context_reducer';
import { CasesGlobalComponents } from './cases_global_components';

jest.mock('../../client/ui/get_create_case_flyout');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { getAllCasesSelectorModalNoProviderLazy } from '../../client/ui/get_all_cases_selector_modal';
import { getCreateCaseFlyoutLazyNoProvider } from '../../client/ui/get_create_case_flyout';
import type { CasesContextState } from './cases_context_reducer';
import type { CasesContextState } from './state/cases_context_reducer';

export const CasesGlobalComponents = React.memo(({ state }: { state: CasesContextState }) => {
return (
Expand Down
96 changes: 42 additions & 54 deletions x-pack/plugins/cases/public/components/cases_context/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
import type { Dispatch, ReactNode, FC, PropsWithChildren } from 'react';

import { merge } from 'lodash';
import { BehaviorSubject } from 'rxjs';
import React, { useCallback, useMemo, useReducer, useEffect } from 'react';
import React, { useCallback, useMemo, useReducer } from 'react';

import type { ScopedFilesClient } from '@kbn/files-plugin/public';
import { FilesContext } from '@kbn/shared-ux-file-context';

import type { QueryClient } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';
import type { CasesContextState, CasesContextStoreAction } from './cases_context_reducer';
import type {
CasesFeaturesAllRequired,
CasesFeatures,
Expand All @@ -30,12 +28,14 @@ import { CasesGlobalComponents } from './cases_global_components';
import { DEFAULT_FEATURES } from '../../../common/constants';
import { constructFileKindIdByOwner } from '../../../common/files';
import { DEFAULT_BASE_PATH } from '../../common/navigation';
import { casesContextReducer, getInitialCasesContextState } from './cases_context_reducer';
import type { CasesContextStoreAction } from './state/cases_context_reducer';
import { casesContextReducer, getInitialCasesContextState } from './state/cases_context_reducer';
import { CasesStateContext } from './state/cases_state_context';
import { isRegisteredOwner } from '../../files';
import { casesQueryClient } from './query_client';

type CasesContextValueDispatch = Dispatch<CasesContextStoreAction>;
type CasesContextState$ = BehaviorSubject<CasesContextState>;

export interface CasesContextValue {
externalReferenceAttachmentTypeRegistry: ExternalReferenceAttachmentTypeRegistry;
persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry;
Expand All @@ -45,7 +45,6 @@ export interface CasesContextValue {
features: CasesFeaturesAllRequired;
releasePhase: ReleasePhase;
dispatch: CasesContextValueDispatch;
casesContextState$: CasesContextState$;
}

export interface CasesContextProps
Expand Down Expand Up @@ -85,47 +84,34 @@ export const CasesProvider: FC<
}) => {
const [state, dispatch] = useReducer(casesContextReducer, getInitialCasesContextState());

// The state behavior subject wil be created only once so it won't trigger a context rerender
// This is needed to retrieve state information from the plugin contract.
// This BehaviorSubject should be used only inside cases.
// eslint-disable-next-line react-hooks/exhaustive-deps
const casesContextState$ = useMemo(() => new BehaviorSubject<CasesContextState>(state), []);
useEffect(() => {
casesContextState$.next(state);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state]);

const value: CasesContextValue = useMemo(
() => {
return {
externalReferenceAttachmentTypeRegistry,
persistableStateAttachmentTypeRegistry,
owner,
permissions: {
all: permissions.all,
connectors: permissions.connectors,
create: permissions.create,
delete: permissions.delete,
push: permissions.push,
read: permissions.read,
settings: permissions.settings,
update: permissions.update,
},
basePath,
/**
* The empty object at the beginning avoids the mutation
* of the DEFAULT_FEATURES object
*/
features: merge<object, CasesFeaturesAllRequired, CasesFeatures>(
{},
DEFAULT_FEATURES,
features
),
releasePhase,
dispatch,
casesContextState$,
};
},
() => ({
externalReferenceAttachmentTypeRegistry,
persistableStateAttachmentTypeRegistry,
owner,
permissions: {
all: permissions.all,
connectors: permissions.connectors,
create: permissions.create,
delete: permissions.delete,
push: permissions.push,
read: permissions.read,
settings: permissions.settings,
update: permissions.update,
},
basePath,
/**
* The empty object at the beginning avoids the mutation
* of the DEFAULT_FEATURES object
*/
features: merge<object, CasesFeaturesAllRequired, CasesFeatures>(
{},
DEFAULT_FEATURES,
features
),
releasePhase,
dispatch,
}),
/**
* We want to trigger a rerender only when the permissions will change.
* The registries, the owner, and the rest of the values should
Expand Down Expand Up @@ -167,14 +153,16 @@ export const CasesProvider: FC<

return (
<QueryClientProvider client={queryClient}>
<CasesContext.Provider value={value}>
{applyFilesContext(
<>
<CasesGlobalComponents state={state} />
{children}
</>
)}
</CasesContext.Provider>
<CasesStateContext.Provider value={state}>
<CasesContext.Provider value={value}>
{applyFilesContext(
<>
<CasesGlobalComponents state={state} />
{children}
</>
)}
</CasesContext.Provider>
</CasesStateContext.Provider>
</QueryClientProvider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
*/

import { assertNever } from '@kbn/std';
import type { AllCasesSelectorModalProps } from '../all_cases/selector_modal';
import type { CreateCaseFlyoutProps } from '../create/flyout';
import type { Dispatch } from 'react';
import type { AllCasesSelectorModalProps } from '../../all_cases/selector_modal';
import type { CreateCaseFlyoutProps } from '../../create/flyout';

export const getInitialCasesContextState = (): CasesContextState => {
return {
Expand Down Expand Up @@ -49,6 +50,8 @@ export type CasesContextStoreAction =
}
| { type: CasesContextStoreActionsList.CLOSE_ADD_TO_CASE_MODAL };

export type CasesContextValueDispatch = Dispatch<CasesContextStoreAction>;

export const casesContextReducer: React.Reducer<CasesContextState, CasesContextStoreAction> = (
state: CasesContextState,
action: CasesContextStoreAction
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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 React, { useContext } from 'react';
import type { CasesContextState } from './cases_context_reducer';

export const CasesStateContext = React.createContext<CasesContextState | undefined>(undefined);

export const useCasesStateContext = () => {
const casesStateContext = useContext(CasesStateContext);
if (!casesStateContext) {
throw new Error(
'useCasesStateContext must be used within a CasesProvider and have a defined value. See https://github.com/elastic/kibana/blob/main/x-pack/plugins/cases/README.md#cases-ui'
);
}
return casesStateContext;
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,9 @@ describe('use is add to existing case modal open hook', () => {
});

it('should throw if called outside of a cases context', () => {
const { result } = renderHook(() => {
useIsAddToCaseOpen();
});
const { result } = renderHook(useIsAddToCaseOpen);
expect(result.error?.message).toContain(
'useCasesContext must be used within a CasesProvider and have a defined value'
'useCasesStateContext must be used within a CasesProvider and have a defined value'
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
* 2.0.
*/

import { useCasesContextState } from './use_cases_context_state';
import { useCasesStateContext } from './cases_state_context';

export type UseIsAddToCaseOpen = () => boolean;

/*
** This hook is to check if the add to existing case modal or create new case modal is open
/**
* This hook is to check if the "add to case" is open, either the modal or the flyout
*/
export const useIsAddToCaseOpen: UseIsAddToCaseOpen = () => {
const { selectCaseModal, createCaseFlyout } = useCasesContextState();
const { selectCaseModal, createCaseFlyout } = useCasesStateContext();
return selectCaseModal.isModalOpen || createCaseFlyout.isFlyoutOpen;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { CasesContext } from '../../cases_context';
import {
CasesContextStoreActionsList,
getInitialCasesContextState,
} from '../../cases_context/cases_context_reducer';
} from '../../cases_context/state/cases_context_reducer';
import { useCasesAddToNewCaseFlyout } from './use_cases_add_to_new_case_flyout';
import { allCasesPermissions } from '../../../common/mock';
import { ExternalReferenceAttachmentTypeRegistry } from '../../../client/attachment_framework/external_reference_registry';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useCallback, useMemo } from 'react';
import type { CaseAttachmentsWithoutOwner } from '../../../types';
import { useCasesToast } from '../../../common/use_cases_toast';
import type { CaseUI } from '../../../containers/types';
import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer';
import { CasesContextStoreActionsList } from '../../cases_context/state/cases_context_reducer';
import { useCasesContext } from '../../cases_context/use_cases_context';
import type { CreateCaseFlyoutProps } from './create_case_flyout';

Expand Down

0 comments on commit 96f5924

Please sign in to comment.