Add RecordField abstraction (#13923)
This PR adds a new RecordField abstraction to mimick the behavior of RecordFilter, RecordSort and other similar concepts that allow to have something that is not related directly to views. It is closely following the same pattern with an Effect component to initialize it from views and CRUD hooks to modify it. Although for this concept we save to view fields automatically for every modification. This PR does not implement saving to view fields, it is just a parallel code path that is meant to be built to see if everything behaves the same then we'll remove the old code path at the end by saving record fields instead of the many states for columns, fields definitions, etc.
This commit is contained in:
@@ -58,9 +58,9 @@ const jestConfig: JestConfigWithTsJest = {
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 55,
|
||||
lines: 54,
|
||||
functions: 44,
|
||||
statements: 54,
|
||||
lines: 53,
|
||||
functions: 43,
|
||||
},
|
||||
},
|
||||
collectCoverageFrom: ['<rootDir>/src/**/*.ts'],
|
||||
|
||||
+16
-30
@@ -8,9 +8,7 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
@@ -50,35 +48,23 @@ export const CommandMenuContainer = ({
|
||||
useCommandMenuHotKeys();
|
||||
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<RecordComponentInstanceContextsWrapper componentInstanceId={recordIndexId}>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
<AnimatePresence
|
||||
mode="wait"
|
||||
onExitComplete={commandMenuCloseAnimationCompleteCleanup}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<AnimatePresence
|
||||
mode="wait"
|
||||
onExitComplete={commandMenuCloseAnimationCompleteCleanup}
|
||||
>
|
||||
{isCommandMenuOpened && (
|
||||
<CommandMenuOpenContainer>
|
||||
{children}
|
||||
</CommandMenuOpenContainer>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
{isCommandMenuOpened && (
|
||||
<CommandMenuOpenContainer>{children}</CommandMenuOpenContainer>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
+14
-24
@@ -25,9 +25,7 @@ import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpe
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { HttpResponse, graphql } from 'msw';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
@@ -38,33 +36,25 @@ const openTimeout = 50;
|
||||
|
||||
const ContextStoreDecorator: Decorator = (Story) => {
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={COMMAND_MENU_COMPONENT_INSTANCE_ID}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
<JestContextStoreSetter
|
||||
contextStoreCurrentObjectMetadataNameSingular="company"
|
||||
contextStoreCurrentViewId="1"
|
||||
contextStoreCurrentViewType={ContextStoreViewType.Table}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<JestContextStoreSetter
|
||||
contextStoreCurrentObjectMetadataNameSingular="company"
|
||||
contextStoreCurrentViewId="1"
|
||||
contextStoreCurrentViewType={ContextStoreViewType.Table}
|
||||
>
|
||||
<Story />
|
||||
</JestContextStoreSetter>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<Story />
|
||||
</JestContextStoreSetter>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+16
-26
@@ -3,10 +3,8 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/c
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { MergeRecordsContainer } from '@/object-record/record-merge/components/MergeRecordsContainer';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import styled from '@emotion/styled';
|
||||
@@ -35,31 +33,23 @@ export const CommandMenuMergeRecordPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-merge-${commandMenuPageInstanceId}` }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={`record-merge-${commandMenuPageInstanceId}`}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-merge-${commandMenuPageInstanceId}` }}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-merge-${commandMenuPageInstanceId}` }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||
<MergeRecordsContainer
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
componentInstanceId={commandMenuPageInstanceId}
|
||||
/>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||
<MergeRecordsContainer
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
componentInstanceId={commandMenuPageInstanceId}
|
||||
/>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
+31
-41
@@ -5,12 +5,10 @@ import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/r
|
||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { INFORMATION_BANNER_HEIGHT } from '@/information-banner/constants/InformationBannerHeight';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
@@ -71,48 +69,40 @@ export const CommandMenuRecordPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={`record-show-${objectRecordId}`}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: commandMenuPageInstanceId,
|
||||
}}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: commandMenuPageInstanceId,
|
||||
}}
|
||||
<StyledRightDrawerRecord
|
||||
isMobile={isMobile}
|
||||
hasDeletedRecordBanner={!!recordDeletedAt}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<StyledRightDrawerRecord
|
||||
isMobile={isMobile}
|
||||
hasDeletedRecordBanner={!!recordDeletedAt}
|
||||
>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { type PropsWithChildren } from 'react';
|
||||
|
||||
export type RecordComponentInstanceContextsWrapperProps = PropsWithChildren<{
|
||||
componentInstanceId: string;
|
||||
}>;
|
||||
|
||||
export const RecordComponentInstanceContextsWrapper = ({
|
||||
componentInstanceId,
|
||||
children,
|
||||
}: RecordComponentInstanceContextsWrapperProps) => {
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
>
|
||||
<RecordFieldsComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
>
|
||||
{children}
|
||||
</RecordFieldsComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
+13
-25
@@ -1,14 +1,12 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext';
|
||||
import { type ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
@@ -42,30 +40,20 @@ const meta: Meta<typeof ObjectOptionsDropdownContent> = {
|
||||
}, [setObjectMetadataItems]);
|
||||
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={instanceId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
>
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<RecordTableComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
},
|
||||
ContextStoreDecorator,
|
||||
|
||||
+9
-1
@@ -1,6 +1,7 @@
|
||||
import { type OnDragEndResponder } from '@hello-pangea/dnd';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useReorderRecordFields } from '@/object-record/record-field/hooks/useReorderRecordFields';
|
||||
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
@@ -24,6 +25,8 @@ export const useObjectOptionsForTable = (
|
||||
{ recordTableId, objectMetadataId },
|
||||
);
|
||||
|
||||
const { reorderRecordFields } = useReorderRecordFields();
|
||||
|
||||
const handleReorderColumns: OnDragEndResponder = useCallback(
|
||||
async (result) => {
|
||||
if (
|
||||
@@ -39,9 +42,14 @@ export const useObjectOptionsForTable = (
|
||||
toIndex: result.destination.index - 1,
|
||||
});
|
||||
|
||||
reorderRecordFields({
|
||||
fromIndex: result.source.index - 1,
|
||||
toIndex: result.destination.index - 1,
|
||||
});
|
||||
|
||||
handleColumnReorder(reorderedFields);
|
||||
},
|
||||
[visibleTableColumns, handleColumnReorder],
|
||||
[visibleTableColumns, handleColumnReorder, reorderRecordFields],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useMoveRecordField = () => {
|
||||
const currentRecordFieldsCallbackState = useRecoilComponentCallbackState(
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
const moveRecordField = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
({
|
||||
direction,
|
||||
fieldMetadataItemIdToMove,
|
||||
}: {
|
||||
direction: 'before' | 'after';
|
||||
fieldMetadataItemIdToMove: string;
|
||||
}) => {
|
||||
const currentRecordFields = snapshot
|
||||
.getLoadable(currentRecordFieldsCallbackState)
|
||||
.getValue();
|
||||
|
||||
const indexOfRecordFieldToMove = currentRecordFields.findIndex(
|
||||
(recordField) =>
|
||||
recordField.fieldMetadataItemId === fieldMetadataItemIdToMove,
|
||||
);
|
||||
|
||||
if (indexOfRecordFieldToMove === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newRecordFields = [...currentRecordFields];
|
||||
|
||||
const targetArrayIndex =
|
||||
direction === 'before'
|
||||
? indexOfRecordFieldToMove - 1
|
||||
: indexOfRecordFieldToMove + 1;
|
||||
|
||||
const targetArraySize = newRecordFields.length - 1;
|
||||
|
||||
if (
|
||||
indexOfRecordFieldToMove >= 0 &&
|
||||
targetArrayIndex >= 0 &&
|
||||
indexOfRecordFieldToMove <= targetArraySize &&
|
||||
targetArrayIndex <= targetArraySize
|
||||
) {
|
||||
const currentRecordField = newRecordFields[indexOfRecordFieldToMove];
|
||||
const targetRecordField = newRecordFields[targetArrayIndex];
|
||||
|
||||
const targetRecordFieldNewPosition = currentRecordField.position;
|
||||
const currentRecordFieldNewPosition = targetRecordField.position;
|
||||
|
||||
newRecordFields[indexOfRecordFieldToMove] = {
|
||||
...newRecordFields[indexOfRecordFieldToMove],
|
||||
position: currentRecordFieldNewPosition,
|
||||
};
|
||||
|
||||
newRecordFields[targetRecordFieldNewPosition] = {
|
||||
...newRecordFields[targetRecordFieldNewPosition],
|
||||
position: targetRecordFieldNewPosition,
|
||||
};
|
||||
|
||||
set(currentRecordFieldsCallbackState, newRecordFields);
|
||||
}
|
||||
},
|
||||
[currentRecordFieldsCallbackState],
|
||||
);
|
||||
|
||||
return { moveRecordField };
|
||||
};
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
|
||||
export const useReorderRecordFields = () => {
|
||||
const currentRecordFieldsCallbackState = useRecoilComponentCallbackState(
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
const reorderRecordFields = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
|
||||
const currentRecordFields = snapshot
|
||||
.getLoadable(currentRecordFieldsCallbackState)
|
||||
.getValue();
|
||||
|
||||
const reorderedRecordFields = moveArrayItem(currentRecordFields, {
|
||||
fromIndex,
|
||||
toIndex,
|
||||
});
|
||||
|
||||
const reorderedRecordFieldsWithNewPosition =
|
||||
reorderedRecordFields.map<RecordField>((recordField, index) => ({
|
||||
...recordField,
|
||||
position: index,
|
||||
}));
|
||||
|
||||
set(
|
||||
currentRecordFieldsCallbackState,
|
||||
reorderedRecordFieldsWithNewPosition,
|
||||
);
|
||||
},
|
||||
[currentRecordFieldsCallbackState],
|
||||
);
|
||||
|
||||
return { reorderRecordFields };
|
||||
};
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useUpdateRecordField = () => {
|
||||
const currentRecordFieldsCallbackState = useRecoilComponentCallbackState(
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
const updateRecordField = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(
|
||||
fieldMetadataItemId: string,
|
||||
partialRecordField: Partial<
|
||||
Pick<RecordField, 'isVisible' | 'size' | 'position'>
|
||||
>,
|
||||
) => {
|
||||
const currentRecordFields = getSnapshotValue(
|
||||
snapshot,
|
||||
currentRecordFieldsCallbackState,
|
||||
);
|
||||
|
||||
const foundRecordFieldInCurrentRecordFields = currentRecordFields.some(
|
||||
(existingRecordField) =>
|
||||
existingRecordField.fieldMetadataItemId === fieldMetadataItemId,
|
||||
);
|
||||
|
||||
if (!foundRecordFieldInCurrentRecordFields) {
|
||||
throw new Error(
|
||||
`Cannot find record field to update with field metadata item id : ${fieldMetadataItemId}`,
|
||||
);
|
||||
} else {
|
||||
set(currentRecordFieldsCallbackState, (currentRecordFields) => {
|
||||
const newCurrentRecordFields = [...currentRecordFields];
|
||||
|
||||
const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex(
|
||||
(existingRecordField) =>
|
||||
existingRecordField.fieldMetadataItemId === fieldMetadataItemId,
|
||||
);
|
||||
|
||||
newCurrentRecordFields[indexOfRecordFieldToUpdate] = {
|
||||
...newCurrentRecordFields[indexOfRecordFieldToUpdate],
|
||||
...partialRecordField,
|
||||
};
|
||||
|
||||
return newCurrentRecordFields;
|
||||
});
|
||||
}
|
||||
},
|
||||
[currentRecordFieldsCallbackState],
|
||||
);
|
||||
|
||||
return {
|
||||
updateRecordField,
|
||||
};
|
||||
};
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useUpsertRecordField = () => {
|
||||
const currentRecordFieldsCallbackState = useRecoilComponentCallbackState(
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
const upsertRecordField = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(recordFieldToUpsert: RecordField) => {
|
||||
const currentRecordFields = getSnapshotValue(
|
||||
snapshot,
|
||||
currentRecordFieldsCallbackState,
|
||||
);
|
||||
|
||||
const foundRecordFieldInCurrentRecordFields = currentRecordFields.some(
|
||||
(existingRecordField) =>
|
||||
existingRecordField.id === recordFieldToUpsert.id,
|
||||
);
|
||||
|
||||
if (!foundRecordFieldInCurrentRecordFields) {
|
||||
set(currentRecordFieldsCallbackState, [
|
||||
...currentRecordFields,
|
||||
recordFieldToUpsert,
|
||||
]);
|
||||
} else {
|
||||
set(currentRecordFieldsCallbackState, (currentRecordFields) => {
|
||||
const newCurrentRecordFields = [...currentRecordFields];
|
||||
|
||||
const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex(
|
||||
(existingRecordField) =>
|
||||
existingRecordField.id === recordFieldToUpsert.id,
|
||||
);
|
||||
|
||||
newCurrentRecordFields[indexOfRecordFieldToUpdate] = {
|
||||
...recordFieldToUpsert,
|
||||
};
|
||||
|
||||
return newCurrentRecordFields;
|
||||
});
|
||||
}
|
||||
},
|
||||
[currentRecordFieldsCallbackState],
|
||||
);
|
||||
|
||||
return {
|
||||
upsertRecordField,
|
||||
};
|
||||
};
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
|
||||
|
||||
export const RecordFieldsComponentInstanceContext =
|
||||
createComponentInstanceContext();
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const currentRecordFieldsComponentState = createComponentState<
|
||||
RecordField[]
|
||||
>({
|
||||
key: 'currentRecordFieldsComponentState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: RecordFieldsComponentInstanceContext,
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { type AggregateOperations } from '~/generated/graphql';
|
||||
|
||||
export type RecordField = {
|
||||
id: string;
|
||||
fieldMetadataItemId: string;
|
||||
position: number;
|
||||
isVisible: boolean;
|
||||
size: number;
|
||||
aggregateOperation?: AggregateOperations | null;
|
||||
};
|
||||
+18
-28
@@ -3,17 +3,15 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/ui/states/lastShowPageRecordId';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
||||
import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect';
|
||||
import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect';
|
||||
import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader';
|
||||
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass';
|
||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||
@@ -74,34 +72,26 @@ export const RecordIndexContainerGater = () => {
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={recordIndexId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
<PageTitle title={objectMetadataItem.labelPlural} />
|
||||
<RecordIndexPageHeader />
|
||||
<PageBody>
|
||||
<StyledIndexContainer
|
||||
className={RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS}
|
||||
>
|
||||
<PageTitle title={objectMetadataItem.labelPlural} />
|
||||
<RecordIndexPageHeader />
|
||||
<PageBody>
|
||||
<StyledIndexContainer
|
||||
className={RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS}
|
||||
>
|
||||
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||
<RecordIndexContainer />
|
||||
</StyledIndexContainer>
|
||||
</PageBody>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||
<RecordIndexContainer />
|
||||
</StyledIndexContainer>
|
||||
</PageBody>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
<RecordIndexLoadBaseOnContextStoreEffect />
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ import { type ColumnDefinition } from '@/object-record/record-table/types/Column
|
||||
|
||||
// TODO: see how we can better abstract this and set the correct interaction between view and table
|
||||
// but for now it allows to have a cleaner API globally.
|
||||
// TODO: should be solved with new RecordField abstraction
|
||||
export const useHandleColumnsChange = () => {
|
||||
const { saveColumnsToView } = useSaveColumnsToView();
|
||||
const { setTableColumns } = useSetTableColumns();
|
||||
|
||||
@@ -4,11 +4,15 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldM
|
||||
import { useUnfocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell';
|
||||
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
||||
|
||||
import { useMoveRecordField } from '@/object-record/record-field/hooks/useMoveRecordField';
|
||||
import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField';
|
||||
import { useUpsertRecordField } from '@/object-record/record-field/hooks/useUpsertRecordField';
|
||||
import { useHandleColumnsChange } from '@/object-record/record-table/hooks/useHandleColumnsChange';
|
||||
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { v4 } from 'uuid';
|
||||
import { type ColumnDefinition } from '../types/ColumnDefinition';
|
||||
|
||||
type useRecordTableProps = {
|
||||
@@ -40,6 +44,9 @@ export const useTableColumns = ({
|
||||
|
||||
const { handleColumnsChange } = useHandleColumnsChange();
|
||||
|
||||
const { updateRecordField } = useUpdateRecordField();
|
||||
const { upsertRecordField } = useUpsertRecordField();
|
||||
|
||||
const handleColumnVisibilityChange = useCallback(
|
||||
async (
|
||||
viewField: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
|
||||
@@ -68,6 +75,14 @@ export const useTableColumns = ({
|
||||
{ ...newColumn, isVisible: true, position: lastPosition + 1 },
|
||||
];
|
||||
|
||||
upsertRecordField({
|
||||
id: v4(),
|
||||
fieldMetadataItemId: viewField.fieldMetadataId,
|
||||
size: 100,
|
||||
isVisible: true,
|
||||
position: lastPosition + 1,
|
||||
});
|
||||
|
||||
await handleColumnsChange({
|
||||
columns: nextColumns,
|
||||
objectMetadataId,
|
||||
@@ -80,6 +95,10 @@ export const useTableColumns = ({
|
||||
: previousColumn,
|
||||
);
|
||||
|
||||
updateRecordField(viewField.fieldMetadataId, {
|
||||
isVisible: !viewField.isVisible,
|
||||
});
|
||||
|
||||
await handleColumnsChange({
|
||||
columns: nextColumns,
|
||||
objectMetadataId,
|
||||
@@ -88,15 +107,19 @@ export const useTableColumns = ({
|
||||
}
|
||||
},
|
||||
[
|
||||
upsertRecordField,
|
||||
tableColumns,
|
||||
availableTableColumns,
|
||||
handleColumnsChange,
|
||||
visibleTableColumns,
|
||||
objectMetadataId,
|
||||
recordTableId,
|
||||
updateRecordField,
|
||||
],
|
||||
);
|
||||
|
||||
const { moveRecordField } = useMoveRecordField();
|
||||
|
||||
const handleMoveTableColumn = useCallback(
|
||||
async (
|
||||
direction: 'left' | 'right',
|
||||
@@ -115,6 +138,11 @@ export const useTableColumns = ({
|
||||
visibleTableColumns,
|
||||
);
|
||||
|
||||
moveRecordField({
|
||||
direction: direction === 'left' ? 'before' : 'after',
|
||||
fieldMetadataItemIdToMove: column.fieldMetadataId,
|
||||
});
|
||||
|
||||
await handleColumnsChange({
|
||||
columns,
|
||||
objectMetadataId,
|
||||
@@ -128,6 +156,7 @@ export const useTableColumns = ({
|
||||
handleColumnsChange,
|
||||
objectMetadataId,
|
||||
recordTableId,
|
||||
moveRecordField,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+25
-12
@@ -2,6 +2,7 @@ import styled from '@emotion/styled';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField';
|
||||
import { isObjectReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isObjectReadOnly';
|
||||
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
@@ -135,13 +136,17 @@ export const RecordTableHeaderCell = ({
|
||||
const [initialPointerPositionX, setInitialPointerPositionX] = useState<
|
||||
number | null
|
||||
>(null);
|
||||
const [resizedFieldKey, setResizedFieldKey] = useState<string | null>(null);
|
||||
const [resizedFieldMetadataItemId, setResizedFieldMetadataItemId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
const { handleColumnsChange } = useTableColumns({
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
recordTableId,
|
||||
});
|
||||
|
||||
const { updateRecordField } = useUpdateRecordField();
|
||||
|
||||
const handleResizeHandlerStart = useCallback<PointerEventListener>(
|
||||
({ x }) => {
|
||||
setInitialPointerPositionX(x);
|
||||
@@ -162,7 +167,7 @@ export const RecordTableHeaderCell = ({
|
||||
const handleResizeHandlerEnd = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async () => {
|
||||
if (!resizedFieldKey) return;
|
||||
if (!resizedFieldMetadataItemId) return;
|
||||
|
||||
const resizeFieldOffset = getSnapshotValue(
|
||||
snapshot,
|
||||
@@ -171,22 +176,27 @@ export const RecordTableHeaderCell = ({
|
||||
|
||||
const nextWidth = Math.round(
|
||||
Math.max(
|
||||
tableColumnsByKey[resizedFieldKey].size + resizeFieldOffset,
|
||||
tableColumnsByKey[resizedFieldMetadataItemId].size +
|
||||
resizeFieldOffset,
|
||||
COLUMN_MIN_WIDTH,
|
||||
),
|
||||
);
|
||||
|
||||
set(resizeFieldOffsetState, 0);
|
||||
setInitialPointerPositionX(null);
|
||||
setResizedFieldKey(null);
|
||||
setResizedFieldMetadataItemId(null);
|
||||
|
||||
if (nextWidth !== tableColumnsByKey[resizedFieldKey].size) {
|
||||
if (nextWidth !== tableColumnsByKey[resizedFieldMetadataItemId].size) {
|
||||
const nextColumns = tableColumns.map((column) =>
|
||||
column.fieldMetadataId === resizedFieldKey
|
||||
column.fieldMetadataId === resizedFieldMetadataItemId
|
||||
? { ...column, size: nextWidth }
|
||||
: column,
|
||||
);
|
||||
|
||||
updateRecordField(resizedFieldMetadataItemId, {
|
||||
size: nextWidth,
|
||||
});
|
||||
|
||||
await handleColumnsChange({
|
||||
columns: nextColumns,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
@@ -195,19 +205,20 @@ export const RecordTableHeaderCell = ({
|
||||
}
|
||||
},
|
||||
[
|
||||
resizedFieldKey,
|
||||
resizedFieldMetadataItemId,
|
||||
resizeFieldOffsetState,
|
||||
tableColumnsByKey,
|
||||
setResizedFieldKey,
|
||||
setResizedFieldMetadataItemId,
|
||||
tableColumns,
|
||||
handleColumnsChange,
|
||||
objectMetadataItem,
|
||||
recordTableId,
|
||||
updateRecordField,
|
||||
],
|
||||
);
|
||||
|
||||
useTrackPointer({
|
||||
shouldTrackPointer: resizedFieldKey !== null,
|
||||
shouldTrackPointer: resizedFieldMetadataItemId !== null,
|
||||
onMouseDown: handleResizeHandlerStart,
|
||||
onMouseMove: handleResizeHandlerMove,
|
||||
onMouseUp: handleResizeHandlerEnd,
|
||||
@@ -251,10 +262,12 @@ export const RecordTableHeaderCell = ({
|
||||
return (
|
||||
<StyledColumnHeaderCell
|
||||
key={column.fieldMetadataId}
|
||||
isResizing={resizedFieldKey === column.fieldMetadataId}
|
||||
isResizing={resizedFieldMetadataItemId === column.fieldMetadataId}
|
||||
columnWidth={Math.max(
|
||||
tableColumnsByKey[column.fieldMetadataId].size +
|
||||
(resizedFieldKey === column.fieldMetadataId ? resizeFieldOffset : 0) +
|
||||
(resizedFieldMetadataItemId === column.fieldMetadataId
|
||||
? resizeFieldOffset
|
||||
: 0) +
|
||||
24,
|
||||
COLUMN_MIN_WIDTH,
|
||||
)}
|
||||
@@ -286,7 +299,7 @@ export const RecordTableHeaderCell = ({
|
||||
className="cursor-col-resize"
|
||||
role="separator"
|
||||
onPointerDown={() => {
|
||||
setResizedFieldKey(column.fieldMetadataId);
|
||||
setResizedFieldMetadataItemId(column.fieldMetadataId);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
+30
-40
@@ -5,10 +5,8 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
@@ -57,48 +55,40 @@ export const SignInBackgroundMockContainer = () => {
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={recordIndexId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
<SignInBackgroundMockContainerEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
recordTableId={recordIndexId}
|
||||
viewId={viewBarId}
|
||||
/>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}}
|
||||
>
|
||||
<SignInBackgroundMockContainerEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
recordTableId={recordIndexId}
|
||||
viewId={viewBarId}
|
||||
/>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
{isDefined(objectMetadataItem) && (
|
||||
<>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
optionsDropdownButton={<></>}
|
||||
/>
|
||||
{isDefined(objectMetadataItem) && (
|
||||
<>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
optionsDropdownButton={<></>}
|
||||
/>
|
||||
|
||||
<RecordTableWithWrappers
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={viewBarId}
|
||||
updateRecordMutation={() => {}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<RecordTableWithWrappers
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={viewBarId}
|
||||
updateRecordMutation={() => {}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
</StyledContainer>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/cons
|
||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||
import { ViewBarAnyFieldFilterEffect } from '@/views/components/ViewBarAnyFieldFilterEffect';
|
||||
import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown';
|
||||
import { ViewBarRecordFieldEffect } from '@/views/components/ViewBarRecordFieldEffect';
|
||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||
import { ViewBarRecordFilterGroupEffect } from '@/views/components/ViewBarRecordFilterGroupEffect';
|
||||
import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect';
|
||||
@@ -45,6 +46,7 @@ export const ViewBar = ({
|
||||
>
|
||||
<ViewBarRecordFilterGroupEffect />
|
||||
<ViewBarAnyFieldFilterEffect />
|
||||
<ViewBarRecordFieldEffect />
|
||||
<ViewBarRecordFilterEffect />
|
||||
<ViewBarRecordSortEffect />
|
||||
<QueryParamsFiltersEffect />
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { hasInitializedCurrentRecordFieldsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState';
|
||||
import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField';
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const ViewBarRecordFieldEffect = () => {
|
||||
const currentViewId = useRecoilComponentValue(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const currentView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
const [
|
||||
hasInitializedCurrentRecordFields,
|
||||
setHasInitializedCurrentRecordFields,
|
||||
] = useRecoilComponentFamilyState(
|
||||
hasInitializedCurrentRecordFieldsComponentFamilyState,
|
||||
{
|
||||
viewId: currentViewId ?? undefined,
|
||||
},
|
||||
);
|
||||
|
||||
const setCurrentRecordFields = useSetRecoilComponentState(
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasInitializedCurrentRecordFields && isDefined(currentView)) {
|
||||
if (currentView.objectMetadataId !== objectMetadataItem.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordFields = currentView.viewFields
|
||||
.map(mapViewFieldToRecordField)
|
||||
.filter(isDefined);
|
||||
|
||||
setCurrentRecordFields(recordFields);
|
||||
|
||||
setHasInitializedCurrentRecordFields(true);
|
||||
}
|
||||
}, [
|
||||
currentViewId,
|
||||
setCurrentRecordFields,
|
||||
hasInitializedCurrentRecordFields,
|
||||
setHasInitializedCurrentRecordFields,
|
||||
currentView,
|
||||
objectMetadataItem,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
+15
-27
@@ -6,10 +6,7 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
@@ -20,6 +17,7 @@ import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { type View } from '@/views/types/View';
|
||||
@@ -106,33 +104,23 @@ const meta: Meta<typeof ViewBarFilterDropdown> = {
|
||||
recordIndexId: instanceId,
|
||||
}}
|
||||
>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={instanceId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: instanceId,
|
||||
}}
|
||||
>
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
>
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: instanceId,
|
||||
}}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
>
|
||||
<Story />
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<Story />
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</RecordIndexContextProvider>
|
||||
);
|
||||
},
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext';
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
|
||||
export const hasInitializedCurrentRecordFieldsComponentFamilyState =
|
||||
createComponentFamilyState<boolean, { viewId?: string }>({
|
||||
key: 'hasInitializedCurrentRecordFieldsComponentFamilyState',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: RecordFieldsComponentInstanceContext,
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const areRecordFieldsEqual = (
|
||||
recordFieldA: RecordField,
|
||||
recordFieldB: RecordField,
|
||||
) => {
|
||||
const propertiesToCompare: (keyof RecordField)[] = [
|
||||
'fieldMetadataItemId',
|
||||
'isVisible',
|
||||
'position',
|
||||
'size',
|
||||
'aggregateOperation',
|
||||
];
|
||||
|
||||
return propertiesToCompare.every((property) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
recordFieldA[property],
|
||||
recordFieldB[property],
|
||||
),
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
|
||||
export const mapViewFieldToRecordField = (viewField: ViewField) => {
|
||||
const recordField: RecordField = {
|
||||
id: viewField.id,
|
||||
fieldMetadataItemId: viewField.fieldMetadataId,
|
||||
isVisible: viewField.isVisible,
|
||||
position: viewField.position,
|
||||
size: viewField.size,
|
||||
aggregateOperation: viewField.aggregateOperation,
|
||||
};
|
||||
|
||||
return recordField;
|
||||
};
|
||||
@@ -5,12 +5,10 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
||||
import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||
import { computeRecordShowComponentInstanceId } from '@/object-record/record-show/utils/computeRecordShowComponentInstanceId';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
@@ -33,55 +31,47 @@ export const RecordShowPage = () => {
|
||||
computeRecordShowComponentInstanceId(objectRecordId);
|
||||
|
||||
return (
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordShowComponentInstanceId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={recordShowComponentInstanceId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordShowComponentInstanceId }}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordShowComponentInstanceId }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordShowComponentInstanceId }}
|
||||
<PageContainer>
|
||||
<RecordShowPageTitle
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowPageHeader
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
>
|
||||
<PageContainer>
|
||||
<RecordShowPageTitle
|
||||
<RecordShowActionMenu />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowPageHeader
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
>
|
||||
<RecordShowActionMenu />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
loading={false}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,9 +24,7 @@ import { MainContextStoreProvider } from '@/context-store/components/MainContext
|
||||
import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserver';
|
||||
import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect';
|
||||
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider';
|
||||
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
|
||||
import { WorkspaceProviderEffect } from '@/workspace/components/WorkspaceProviderEffect';
|
||||
@@ -97,26 +95,11 @@ const Providers = () => {
|
||||
<HelmetProvider>
|
||||
<IconsProvider>
|
||||
<PrefetchDataProvider>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId:
|
||||
'storybook-test-record-filter-groups',
|
||||
}}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={'storybook-test-record'}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'storybook-test-record-filters',
|
||||
}}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'storybook-test-record-sorts',
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<Outlet />
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</PrefetchDataProvider>
|
||||
</IconsProvider>
|
||||
</HelmetProvider>
|
||||
|
||||
@@ -5,12 +5,10 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||
import {
|
||||
RecordTableContextProvider,
|
||||
@@ -145,32 +143,24 @@ export const RecordTableDecorator: Decorator = (Story, context) => {
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={recordIndexId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<InternalTableContextProviders
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
>
|
||||
<InternalTableContextProviders
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
>
|
||||
<InternalTableStateLoaderEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
<Story />
|
||||
</InternalTableContextProviders>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<InternalTableStateLoaderEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
<Story />
|
||||
</InternalTableContextProviders>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
);
|
||||
|
||||
+38
-50
@@ -1,9 +1,7 @@
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { type MockedResponse } from '@apollo/client/testing';
|
||||
import { type ReactNode } from 'react';
|
||||
import { type MutableSnapshot } from 'recoil';
|
||||
@@ -51,58 +49,48 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
||||
|
||||
return ({ children }: { children: ReactNode }) => (
|
||||
<Wrapper>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={componentInstanceId}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: componentInstanceId,
|
||||
}}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: componentInstanceId,
|
||||
}}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: componentInstanceId }}
|
||||
<RecordIndexContextProvider
|
||||
value={{
|
||||
objectPermissionsByObjectMetadataId: {},
|
||||
indexIdentifierUrl: () => 'indexIdentifierUrl',
|
||||
onIndexRecordsLoaded: () => {},
|
||||
objectNamePlural: mockObjectMetadataItem.namePlural,
|
||||
objectNameSingular: mockObjectMetadataItem.nameSingular,
|
||||
objectMetadataItem: mockObjectMetadataItem,
|
||||
recordIndexId: 'recordIndexId',
|
||||
}}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: componentInstanceId,
|
||||
}}
|
||||
<JestContextStoreSetter
|
||||
contextStoreCurrentViewId={contextStoreCurrentViewId}
|
||||
contextStoreFilters={contextStoreFilters}
|
||||
contextStoreTargetedRecordsRule={
|
||||
contextStoreTargetedRecordsRule
|
||||
}
|
||||
contextStoreNumberOfSelectedRecords={
|
||||
contextStoreNumberOfSelectedRecords
|
||||
}
|
||||
contextStoreCurrentObjectMetadataNameSingular={
|
||||
contextStoreCurrentObjectMetadataNameSingular
|
||||
}
|
||||
contextStoreCurrentViewType={contextStoreCurrentViewType}
|
||||
>
|
||||
<RecordIndexContextProvider
|
||||
value={{
|
||||
objectPermissionsByObjectMetadataId: {},
|
||||
indexIdentifierUrl: () => 'indexIdentifierUrl',
|
||||
onIndexRecordsLoaded: () => {},
|
||||
objectNamePlural: mockObjectMetadataItem.namePlural,
|
||||
objectNameSingular: mockObjectMetadataItem.nameSingular,
|
||||
objectMetadataItem: mockObjectMetadataItem,
|
||||
recordIndexId: 'recordIndexId',
|
||||
}}
|
||||
>
|
||||
<JestContextStoreSetter
|
||||
contextStoreCurrentViewId={contextStoreCurrentViewId}
|
||||
contextStoreFilters={contextStoreFilters}
|
||||
contextStoreTargetedRecordsRule={
|
||||
contextStoreTargetedRecordsRule
|
||||
}
|
||||
contextStoreNumberOfSelectedRecords={
|
||||
contextStoreNumberOfSelectedRecords
|
||||
}
|
||||
contextStoreCurrentObjectMetadataNameSingular={
|
||||
contextStoreCurrentObjectMetadataNameSingular
|
||||
}
|
||||
contextStoreCurrentViewType={contextStoreCurrentViewType}
|
||||
>
|
||||
{children}
|
||||
</JestContextStoreSetter>
|
||||
</RecordIndexContextProvider>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
{children}
|
||||
</JestContextStoreSetter>
|
||||
</RecordIndexContextProvider>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { MockedProvider, type MockedResponse } from '@apollo/client/testing';
|
||||
import { type ReactNode } from 'react';
|
||||
import { type MutableSnapshot, RecoilRoot } from 'recoil';
|
||||
import { RecoilRoot, type MutableSnapshot } from 'recoil';
|
||||
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { type InMemoryCache } from '@apollo/client';
|
||||
@@ -30,31 +28,21 @@ export const getJestMetadataAndApolloMocksWrapper = ({
|
||||
value={{ instanceId: 'snack-bar-manager' }}
|
||||
>
|
||||
<MockedProvider mocks={apolloMocks} addTypename={false} cache={cache}>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'instanceId' }}
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={'instanceId'}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'instanceId' }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'instanceId' }}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
<JestObjectMetadataItemSetter>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'instanceId' }}
|
||||
>
|
||||
<JestObjectMetadataItemSetter>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'instanceId' }}
|
||||
>
|
||||
<JestContextStoreSetter>
|
||||
{children}
|
||||
</JestContextStoreSetter>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</JestObjectMetadataItemSetter>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
<JestContextStoreSetter>{children}</JestContextStoreSetter>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</JestObjectMetadataItemSetter>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</MockedProvider>
|
||||
</SnackBarComponentInstanceContext.Provider>
|
||||
</RecoilRoot>
|
||||
|
||||
Reference in New Issue
Block a user