refactor: metadata store cleanup, SSE unification, mock metadata loading & login redirect fix (#18651)
## Summary - **SSE unification**: Replaced 11 individual SSE effect components with a single generic `MetadataStoreSSEEffect` - **Metadata store cleanup**: Merged `metadataCollectionHashesState` into `metadataStoreState` (currentCollectionHash / draftCollectionHash per entity), moved `objectMetadataItemsSelector` to `object-metadata` domain, converted `navigationMenuItemsState` to a derived selector - **Naming clarity**: Renamed `isAppMetadataReadyState` → `isMinimalMetadataReadyState`, `MetadataGater` → `MinimalMetadataGater`, `useIsLogged` → `useHasAccessTokenPair`, `patchMetadataStoreFromSSEEvent` now takes named object params - **Mock metadata loading**: Added `generate-navigation-menu-items.ts` script, rewrote `useLoadMockedMinimalMetadata` to load full objects/fields/indexes/views/navItems from generated mock data, enabling proper sign-in background rendering (table columns, view picker, navigation) - **Login/logout transitions**: `MinimalMetadataLoadEffect` manages mocked↔real metadata transitions based on auth state, `MainContextStoreProvider` computes context on auth pages for view picker support - **Login redirect fix**: `handleLoadWorkspaceAfterAuthentication` now re-enables `isAppEffectRedirectEnabled` after `loadCurrentUser()` completes, fixing the blocked post-login navigation - **Dead code removal**: Deleted `useRefreshPageLayouts`, `useApplyPageLayouts`, `useStaleMetadataEntities`, `metadataCollectionHashesState`, and all individual SSE effects ## Test plan - [x] Login from welcome page redirects to companies page - [x] Logout transitions cleanly to mocked metadata on welcome page - [x] Sign-in background shows table columns, view picker, and navigation items - [x] SSE events still update metadata store entries correctly - [x] Navigation menu items persist across page refreshes - [ ] CI: lint, typecheck, tests pass
This commit is contained in:
+2
-35
@@ -5,11 +5,10 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { type GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore';
|
||||
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
|
||||
import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
@@ -39,7 +38,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const existingCoreViews = store.get(coreViewsState.atom);
|
||||
const existingCoreViews = store.get(coreViewsSelector.atom);
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
throw new Error('No view id found');
|
||||
@@ -74,16 +73,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
mainGroupByFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
await updateCurrentView(updateCurrentViewParams);
|
||||
return;
|
||||
}
|
||||
@@ -95,16 +84,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
updateCurrentViewParams.mainGroupByFieldMetadataId = null;
|
||||
await updateCurrentView(updateCurrentViewParams);
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
mainGroupByFieldMetadataId: null,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
case ViewType.Calendar: {
|
||||
@@ -115,18 +94,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
const calendarFieldMetadataId = availableFieldsForCalendar[0].id;
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
mainGroupByFieldMetadataId: null,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
calendarLayout: ViewCalendarLayout.MONTH,
|
||||
calendarFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
|
||||
loadRecordIndexStates(
|
||||
{
|
||||
|
||||
+4
-7
@@ -4,12 +4,12 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { type TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
@@ -18,9 +18,8 @@ import { RecordCalendarMonth } from '@/object-record/record-calendar/month/compo
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||
@@ -28,6 +27,7 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { mockedCoreViews } from '~/testing/mock-data/generated/metadata/views/mock-views-data';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
import { setTestCoreViewsInMetadataStore } from '~/testing/utils/setTestCoreViewsInMetadataStore';
|
||||
|
||||
const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
title: 'Modules/ObjectRecord/RecordCalendar/Month',
|
||||
@@ -44,8 +44,6 @@ const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const setCoreViews = useSetAtomState(coreViewsState);
|
||||
|
||||
const mockCoreView = mockedCoreViews.find(
|
||||
(v) => v.name === 'All Companies',
|
||||
)!;
|
||||
@@ -73,12 +71,11 @@ const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setCoreViews([mockCoreView]);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [mockCoreView]);
|
||||
setContextStoreCurrentViewId(mockCoreView.id);
|
||||
setCurrentRecordFields(columns);
|
||||
setIsLoaded(true);
|
||||
}, [
|
||||
setCoreViews,
|
||||
setContextStoreCurrentViewId,
|
||||
setCurrentRecordFields,
|
||||
mockCoreView,
|
||||
|
||||
-6
@@ -6,7 +6,6 @@ import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/use
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate';
|
||||
import { useGetViewFromState } from '@/views/hooks/useGetViewFromState';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { type ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useStore } from 'jotai';
|
||||
@@ -29,8 +28,6 @@ export const useHandleRecordGroupField = () => {
|
||||
|
||||
const { performViewAPIUpdate } = usePerformViewAPIUpdate();
|
||||
const { loadRecordIndexStates } = useLoadRecordIndexStates();
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -121,8 +118,6 @@ export const useHandleRecordGroupField = () => {
|
||||
viewGroups: newViewGroupsList,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id);
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
@@ -130,7 +125,6 @@ export const useHandleRecordGroupField = () => {
|
||||
performViewAPIUpdate,
|
||||
setRecordGroupsFromViewGroups,
|
||||
objectMetadataItem,
|
||||
refreshCoreViewsByObjectMetadataId,
|
||||
loadRecordIndexStates,
|
||||
store,
|
||||
],
|
||||
|
||||
-8
@@ -1,4 +1,3 @@
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
@@ -6,7 +5,6 @@ import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -20,10 +18,6 @@ export const useViewFieldAggregateOperation = () => {
|
||||
(viewField) => viewField.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
const { performViewFieldAPIUpdate } = usePerformViewFieldAPIPersist();
|
||||
const updateViewFieldAggregateOperation = async (
|
||||
aggregateOperation: ExtendedAggregateOperations | null,
|
||||
@@ -48,8 +42,6 @@ export const useViewFieldAggregateOperation = () => {
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
refreshCoreViewsByObjectMetadataId(objectMetadataItem.id);
|
||||
};
|
||||
|
||||
const viewFieldAggregateOperation = useAtomFamilyStateValue(
|
||||
|
||||
Reference in New Issue
Block a user