feat: record group add new (#8925)
Fix #8757 This PR is adding the Add new button on view groups. Also this PR fix an issue where the pending record can be draggable, and is causing error. <img width="1119" alt="Screenshot 2024-12-10 at 4 24 43 PM" src="https://github.com/user-attachments/assets/4fd01e99-c85e-4a06-a733-cbf3cc32957d"> It also start to issues with the way we're using Context. We're initializing pretty much all Context like this: ```typescript export const RecordTableContext = createContext<RecordTableContextProps>( {} as RecordTableContextProps, ); ``` This is causing issues when by mistake we use the context like this outside the Provider hierarchy: ```typescript const context = useContext(RecordTableContext); ``` This is going to fail silently, and all the context variables become undefined... To fix this I've introduced an util called `createRequiredContext`, this one is returning an array containing the provider and the hook to retrieve the context. The context is initialized to undefined inside this utility, this way we can check if the value has been initialized with the provider to check if we're inside it. It'll throw an error if this one is used outside the provider. The return values are properly typed, so `undefined` is not added to the value of the Context. I'll create a followup ticket to use this new utility function, if that's ok and replace it everywhere in the codebase. We can also consider adding a eslint rule to warn about the use of `createContext` directly.
This commit is contained in:
@ -9,7 +9,7 @@ import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdow
|
|||||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
@ -20,7 +20,6 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ type ObjectFilterDropdownFilterSelectProps = {
|
|||||||
export const ObjectFilterDropdownFilterSelect = ({
|
export const ObjectFilterDropdownFilterSelect = ({
|
||||||
isAdvancedFilterButtonVisible,
|
isAdvancedFilterButtonVisible,
|
||||||
}: ObjectFilterDropdownFilterSelectProps) => {
|
}: ObjectFilterDropdownFilterSelectProps) => {
|
||||||
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setObjectFilterDropdownSearchInput,
|
setObjectFilterDropdownSearchInput,
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
||||||
|
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
||||||
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
||||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
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 { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
@ -19,6 +22,7 @@ import { FieldMetadataType } from '~/generated/graphql';
|
|||||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
||||||
title:
|
title:
|
||||||
@ -26,6 +30,9 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
component: MultipleFiltersDropdownButton,
|
component: MultipleFiltersDropdownButton,
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => {
|
(Story) => {
|
||||||
|
const companyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === CoreObjectNameSingular.Company,
|
||||||
|
)!;
|
||||||
const instanceId = 'entity-tasks-filter-scope';
|
const instanceId = 'entity-tasks-filter-scope';
|
||||||
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
||||||
availableFilterDefinitionsComponentState,
|
availableFilterDefinitionsComponentState,
|
||||||
@ -91,19 +98,30 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
return (
|
return (
|
||||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
<RecordIndexContextProvider
|
||||||
value={{ instanceId }}
|
value={{
|
||||||
|
indexIdentifierUrl: () => '',
|
||||||
|
onIndexRecordsLoaded: () => {},
|
||||||
|
objectNamePlural: CoreObjectNamePlural.Company,
|
||||||
|
objectNameSingular: CoreObjectNameSingular.Company,
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordIndexId: instanceId,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableComponentInstanceContext.Provider
|
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||||
value={{ instanceId: instanceId, onColumnsChange: () => {} }}
|
value={{ instanceId }}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
<RecordTableComponentInstanceContext.Provider
|
||||||
<ObjectFilterDropdownScope filterScopeId={instanceId}>
|
value={{ instanceId: instanceId, onColumnsChange: () => {} }}
|
||||||
<Story />
|
>
|
||||||
</ObjectFilterDropdownScope>
|
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||||
</ViewComponentInstanceContext.Provider>
|
<ObjectFilterDropdownScope filterScopeId={instanceId}>
|
||||||
</RecordTableComponentInstanceContext.Provider>
|
<Story />
|
||||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
</ObjectFilterDropdownScope>
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordTableComponentInstanceContext.Provider>
|
||||||
|
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||||
|
</RecordIndexContextProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ObjectMetadataItemsDecorator,
|
ObjectMetadataItemsDecorator,
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dro
|
|||||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
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 { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext';
|
||||||
import { ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId';
|
import { ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
@ -76,11 +76,10 @@ const createStory = (contentId: ObjectOptionsContentId | null): Story => ({
|
|||||||
)!;
|
)!;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordIndexRootPropsContext.Provider
|
<RecordIndexContextProvider
|
||||||
value={{
|
value={{
|
||||||
indexIdentifierUrl: () => '',
|
indexIdentifierUrl: () => '',
|
||||||
onIndexRecordsLoaded: () => {},
|
onIndexRecordsLoaded: () => {},
|
||||||
onCreateRecord: () => {},
|
|
||||||
objectNamePlural: 'companies',
|
objectNamePlural: 'companies',
|
||||||
objectNameSingular: 'company',
|
objectNameSingular: 'company',
|
||||||
objectMetadataItem: companyObjectMetadataItem,
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
@ -102,7 +101,7 @@ const createStory = (contentId: ObjectOptionsContentId | null): Story => ({
|
|||||||
<Story />
|
<Story />
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</ObjectOptionsDropdownContext.Provider>
|
</ObjectOptionsDropdownContext.Provider>
|
||||||
</RecordIndexRootPropsContext.Provider>
|
</RecordIndexContextProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
|
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
@ -11,13 +11,13 @@ describe('useSearchRecordGroupField', () => {
|
|||||||
renderHook(() => useSearchRecordGroupField(), {
|
renderHook(() => useSearchRecordGroupField(), {
|
||||||
wrapper: ({ children }) => (
|
wrapper: ({ children }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
<RecordIndexRootPropsContext.Provider value={contextValue}>
|
<RecordIndexContextProvider value={contextValue}>
|
||||||
<ViewComponentInstanceContext.Provider
|
<ViewComponentInstanceContext.Provider
|
||||||
value={{ instanceId: 'myViewInstanceId' }}
|
value={{ instanceId: 'myViewInstanceId' }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ViewComponentInstanceContext.Provider>
|
</ViewComponentInstanceContext.Provider>
|
||||||
</RecordIndexRootPropsContext.Provider>
|
</RecordIndexContextProvider>
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { objectOptionsDropdownSearchInputComponentState } from '@/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState';
|
import { objectOptionsDropdownSearchInputComponentState } from '@/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useContext, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const useSearchRecordGroupField = () => {
|
export const useSearchRecordGroupField = () => {
|
||||||
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const [recordGroupFieldSearchInput, setRecordGroupFieldSearchInput] =
|
const [recordGroupFieldSearchInput, setRecordGroupFieldSearchInput] =
|
||||||
useRecoilComponentStateV2(objectOptionsDropdownSearchInputComponentState);
|
useRecoilComponentStateV2(objectOptionsDropdownSearchInputComponentState);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { IconChevronDown, MenuItem, useIcons } from 'twenty-ui';
|
|||||||
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
|
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
|
||||||
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
|
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
|
||||||
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
|
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
@ -16,7 +16,6 @@ import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/Styl
|
|||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { SORT_DIRECTIONS } from '../types/SortDirection';
|
import { SORT_DIRECTIONS } from '../types/SortDirection';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
@ -77,7 +76,7 @@ export const ObjectSortDropdownButton = ({
|
|||||||
resetSearchInput,
|
resetSearchInput,
|
||||||
} = useObjectSortDropdown();
|
} = useObjectSortDropdown();
|
||||||
|
|
||||||
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const { isDropdownOpen } = useDropdown(OBJECT_SORT_DROPDOWN_ID);
|
const { isDropdownOpen } = useDropdown(OBJECT_SORT_DROPDOWN_ID);
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,41 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { ComponentDecorator } from 'twenty-ui';
|
import { ComponentDecorator } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { ChipFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ChipFieldDisplay';
|
import { ChipFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ChipFieldDisplay';
|
||||||
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
||||||
import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator';
|
import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator';
|
||||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Data/Field/Display/ChipFieldDisplay',
|
title: 'UI/Data/Field/Display/ChipFieldDisplay',
|
||||||
decorators: [
|
decorators: [
|
||||||
|
(Story) => {
|
||||||
|
const instanceId = 'child-field-display-scope';
|
||||||
|
|
||||||
|
const companyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === CoreObjectNameSingular.Company,
|
||||||
|
)!;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordIndexContextProvider
|
||||||
|
value={{
|
||||||
|
indexIdentifierUrl: () => '',
|
||||||
|
onIndexRecordsLoaded: () => {},
|
||||||
|
objectNamePlural: CoreObjectNamePlural.Company,
|
||||||
|
objectNameSingular: CoreObjectNameSingular.Company,
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordIndexId: instanceId,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</RecordIndexContextProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
MemoryRouterDecorator,
|
MemoryRouterDecorator,
|
||||||
ChipGeneratorsDecorator,
|
ChipGeneratorsDecorator,
|
||||||
getFieldDecorator('person', 'name'),
|
getFieldDecorator('person', 'name'),
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
export const useCurrentRecordGroupId = () => {
|
export const useCurrentRecordGroupId = (): string => {
|
||||||
const context = useContext(RecordGroupContext);
|
const context = useContext(RecordGroupContext);
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { RecordBoardColumnContext } from '@/object-record/record-board/record-bo
|
|||||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
import { RecordGroupAction } from '@/object-record/record-group/types/RecordGroupActions';
|
import { RecordGroupAction } from '@/object-record/record-group/types/RecordGroupActions';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useCallback, useContext, useMemo } from 'react';
|
import { useCallback, useContext, useMemo } from 'react';
|
||||||
@ -17,9 +17,7 @@ export const useRecordGroupActions = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const { objectNameSingular, recordIndexId } = useContext(
|
const { objectNameSingular, recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
RecordIndexRootPropsContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { columnDefinition: recordGroupDefinition } = useContext(
|
const { columnDefinition: recordGroupDefinition } = useContext(
|
||||||
RecordBoardColumnContext,
|
RecordBoardColumnContext,
|
||||||
|
|||||||
@ -2,15 +2,14 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/s
|
|||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
export const useSetRecordGroup = (viewId?: string) => {
|
export const useSetRecordGroup = (viewId?: string) => {
|
||||||
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||||
recordGroupIdsComponentState,
|
recordGroupIdsComponentState,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import { recordIndexSortsState } from '@/object-record/record-index/states/recor
|
|||||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||||
|
|
||||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||||
@ -39,7 +39,7 @@ import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
|||||||
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
||||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useCallback, useContext } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -67,7 +67,7 @@ export const RecordIndexContainer = () => {
|
|||||||
recordIndexId,
|
recordIndexId,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
} = useContext(RecordIndexRootPropsContext);
|
} = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import { computeContextStoreFilters } from '@/context-store/utils/computeContext
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useContext, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
||||||
() => {
|
() => {
|
||||||
@ -21,7 +21,7 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
|||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { objectNamePlural } = useContext(RecordIndexRootPropsContext);
|
const { objectNamePlural } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useContext, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export const RecordIndexContainerContextStoreObjectMetadataEffect = () => {
|
export const RecordIndexContainerContextStoreObjectMetadataEffect = () => {
|
||||||
const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2(
|
const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
);
|
);
|
||||||
const { objectNamePlural } = useContext(RecordIndexRootPropsContext);
|
const { objectNamePlural } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||||
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
|
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
|
||||||
@ -12,7 +12,7 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
export const RecordIndexFiltersToContextStoreEffect = () => {
|
export const RecordIndexFiltersToContextStoreEffect = () => {
|
||||||
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||||
|
|
||||||
|
|||||||
@ -3,16 +3,14 @@ import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-sto
|
|||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
||||||
import { RecordIndexPageKanbanAddButton } from '@/object-record/record-index/components/RecordIndexPageKanbanAddButton';
|
import { RecordIndexPageKanbanAddButton } from '@/object-record/record-index/components/RecordIndexPageKanbanAddButton';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { RecordIndexPageTableAddButton } from '@/object-record/record-index/components/RecordIndexPageTableAddButton';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||||
import { PageHeaderOpenCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton';
|
import { PageHeaderOpenCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton';
|
||||||
import { PageAddButton } from '@/ui/layout/page/components/PageAddButton';
|
|
||||||
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||||
import { PageHotkeysEffect } from '@/ui/layout/page/components/PageHotkeysEffect';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined, useIcons } from 'twenty-ui';
|
import { isDefined, useIcons } from 'twenty-ui';
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
@ -21,17 +19,13 @@ export const RecordIndexPageHeader = () => {
|
|||||||
const { findObjectMetadataItemByNamePlural } =
|
const { findObjectMetadataItemByNamePlural } =
|
||||||
useFilteredObjectMetadataItems();
|
useFilteredObjectMetadataItems();
|
||||||
|
|
||||||
const { objectNamePlural, onCreateRecord } = useContext(
|
const { objectNamePlural } = useRecordIndexContextOrThrow();
|
||||||
RecordIndexRootPropsContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const objectMetadataItem =
|
const objectMetadataItem =
|
||||||
findObjectMetadataItemByNamePlural(objectNamePlural);
|
findObjectMetadataItemByNamePlural(objectNamePlural);
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const Icon = getIcon(
|
const Icon = getIcon(objectMetadataItem?.icon);
|
||||||
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordIndexViewType = useRecoilValue(recordIndexViewTypeState);
|
const recordIndexViewType = useRecoilValue(recordIndexViewTypeState);
|
||||||
|
|
||||||
@ -56,17 +50,14 @@ export const RecordIndexPageHeader = () => {
|
|||||||
const pageHeaderTitle =
|
const pageHeaderTitle =
|
||||||
objectMetadataItem?.labelPlural ?? capitalize(objectNamePlural);
|
objectMetadataItem?.labelPlural ?? capitalize(objectNamePlural);
|
||||||
|
|
||||||
const handleAddButtonClick = () => {
|
|
||||||
onCreateRecord();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageHeader title={pageHeaderTitle} Icon={Icon}>
|
<PageHeader title={pageHeaderTitle} Icon={Icon}>
|
||||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
|
||||||
|
|
||||||
{shouldDisplayAddButton &&
|
{shouldDisplayAddButton &&
|
||||||
|
/**
|
||||||
|
* TODO: Logic between Table and Kanban should be merged here when we move some states to record-index
|
||||||
|
*/
|
||||||
(isTable ? (
|
(isTable ? (
|
||||||
<PageAddButton onClick={handleAddButtonClick} />
|
<RecordIndexPageTableAddButton />
|
||||||
) : (
|
) : (
|
||||||
<RecordIndexPageKanbanAddButton />
|
<RecordIndexPageKanbanAddButton />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
||||||
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
|
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
|
||||||
@ -6,33 +5,20 @@ import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-re
|
|||||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||||
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
|
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { PageAddButton } from '@/ui/layout/page/components/PageAddButton';
|
import { PageAddButton } from '@/ui/layout/page/components/PageAddButton';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import styled from '@emotion/styled';
|
import { useCallback } from 'react';
|
||||||
import { useCallback, useContext } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledDropDownMenu = styled(DropdownMenu)`
|
|
||||||
width: 200px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const RecordIndexPageKanbanAddButton = () => {
|
export const RecordIndexPageKanbanAddButton = () => {
|
||||||
const dropdownId = `record-index-page-add-button-dropdown`;
|
const dropdownId = `record-index-page-add-button-dropdown`;
|
||||||
|
|
||||||
const { recordIndexId, objectNameSingular } = useContext(
|
const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
RecordIndexRootPropsContext,
|
|
||||||
);
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
|
||||||
|
|
||||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||||
visibleRecordGroupIdsComponentSelector,
|
visibleRecordGroupIdsComponentSelector,
|
||||||
@ -95,17 +81,15 @@ export const RecordIndexPageKanbanAddButton = () => {
|
|||||||
clickableComponent={<PageAddButton />}
|
clickableComponent={<PageAddButton />}
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<StyledDropDownMenu>
|
<DropdownMenuItemsContainer>
|
||||||
<StyledDropdownMenuItemsContainer>
|
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
<RecordIndexPageKanbanAddMenuItem
|
||||||
<RecordIndexPageKanbanAddMenuItem
|
key={recordGroupId}
|
||||||
key={recordGroupId}
|
columnId={recordGroupId}
|
||||||
columnId={recordGroupId}
|
onItemClick={handleItemClick}
|
||||||
onItemClick={handleItemClick}
|
/>
|
||||||
/>
|
))}
|
||||||
))}
|
</DropdownMenuItemsContainer>
|
||||||
</StyledDropdownMenuItemsContainer>
|
|
||||||
</StyledDropDownMenu>
|
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||||
|
import { RecordIndexPageTableAddButtonInGroup } from '@/object-record/record-index/components/RecordIndexPageTableAddButtonInGroup';
|
||||||
|
import { RecordIndexPageTableAddButtonNoGroup } from '@/object-record/record-index/components/RecordIndexPageTableAddButtonNoGroup';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
|
export const RecordIndexPageTableAddButton = () => {
|
||||||
|
const hasRecordGroups = useRecoilComponentValueV2(
|
||||||
|
hasRecordGroupsComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasRecordGroups) {
|
||||||
|
return <RecordIndexPageTableAddButtonNoGroup />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <RecordIndexPageTableAddButtonInGroup />;
|
||||||
|
};
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
|
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||||
|
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||||
|
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useCreateNewTableRecordInGroup } from '@/object-record/record-table/hooks/useCreateNewTableRecordInGroup';
|
||||||
|
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
|
||||||
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { PageAddButton } from '@/ui/layout/page/components/PageAddButton';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
export const RecordIndexPageTableAddButtonInGroup = () => {
|
||||||
|
const dropdownId = `record-index-page-table-add-button-dropdown`;
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||||
|
visibleRecordGroupIdsComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||||
|
recordGroupFieldMetadataComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isRecordGroupTableSectionToggledState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
isRecordGroupTableSectionToggledComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
||||||
|
(field) => field.id === recordGroupFieldMetadata?.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { createNewTableRecordInGroup } = useCreateNewTableRecordInGroup();
|
||||||
|
|
||||||
|
const { closeDropdown } = useDropdown(dropdownId);
|
||||||
|
|
||||||
|
const handleCreateNewTableRecordInGroup = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(recordGroup: RecordGroupDefinition) => {
|
||||||
|
set(isRecordGroupTableSectionToggledState(recordGroup.id), true);
|
||||||
|
createNewTableRecordInGroup(recordGroup.id);
|
||||||
|
closeDropdown();
|
||||||
|
},
|
||||||
|
[
|
||||||
|
closeDropdown,
|
||||||
|
createNewTableRecordInGroup,
|
||||||
|
isRecordGroupTableSectionToggledState,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectFieldMetadataItem) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
dropdownMenuWidth="200px"
|
||||||
|
dropdownPlacement="bottom-start"
|
||||||
|
clickableComponent={<PageAddButton />}
|
||||||
|
dropdownId={dropdownId}
|
||||||
|
dropdownComponents={
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||||
|
<RecordIndexPageKanbanAddMenuItem
|
||||||
|
key={recordGroupId}
|
||||||
|
columnId={recordGroupId}
|
||||||
|
onItemClick={handleCreateNewTableRecordInGroup}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
}
|
||||||
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||||
|
import { PageAddButton } from '@/ui/layout/page/components/PageAddButton';
|
||||||
|
import { PageHotkeysEffect } from '@/ui/layout/page/components/PageHotkeysEffect';
|
||||||
|
|
||||||
|
export const RecordIndexPageTableAddButtonNoGroup = () => {
|
||||||
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const { createNewTableRecord } = useCreateNewTableRecord(recordIndexId);
|
||||||
|
|
||||||
|
const handleCreateNewTableRecord = () => {
|
||||||
|
createNewTableRecord();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PageHotkeysEffect onAddButtonClick={handleCreateNewTableRecord} />
|
||||||
|
<PageAddButton onClick={handleCreateNewTableRecord} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,8 +1,7 @@
|
|||||||
import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon';
|
import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon';
|
||||||
import { useRecordChipData } from '@/object-record/hooks/useRecordChipData';
|
import { useRecordChipData } from '@/object-record/hooks/useRecordChipData';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { AvatarChip, AvatarChipVariant, ChipSize } from 'twenty-ui';
|
import { AvatarChip, AvatarChipVariant, ChipSize } from 'twenty-ui';
|
||||||
|
|
||||||
export type RecordIdentifierChipProps = {
|
export type RecordIdentifierChipProps = {
|
||||||
@ -20,7 +19,7 @@ export const RecordIdentifierChip = ({
|
|||||||
size,
|
size,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
}: RecordIdentifierChipProps) => {
|
}: RecordIdentifierChipProps) => {
|
||||||
const { indexIdentifierUrl } = useContext(RecordIndexRootPropsContext);
|
const { indexIdentifierUrl } = useRecordIndexContextOrThrow();
|
||||||
const { recordChipData } = useRecordChipData({
|
const { recordChipData } = useRecordChipData({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
record,
|
record,
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { RecordUpdateHookParams } from '@/object-record/record-field/contexts/FieldContext';
|
import { RecordUpdateHookParams } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordIndexRemoveSortingModal } from '@/object-record/record-index/components/RecordIndexRemoveSortingModal';
|
import { RecordIndexRemoveSortingModal } from '@/object-record/record-index/components/RecordIndexRemoveSortingModal';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
type RecordIndexTableContainerProps = {
|
type RecordIndexTableContainerProps = {
|
||||||
recordTableId: string;
|
recordTableId: string;
|
||||||
@ -14,7 +13,7 @@ export const RecordIndexTableContainer = ({
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
viewBarId,
|
viewBarId,
|
||||||
}: RecordIndexTableContainerProps) => {
|
}: RecordIndexTableContainerProps) => {
|
||||||
const { objectNameSingular } = useContext(RecordIndexRootPropsContext);
|
const { objectNameSingular } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const { updateOneRecord } = useUpdateOneRecord({
|
const { updateOneRecord } = useUpdateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { useContext, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
|
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
|
||||||
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
|
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
@ -13,9 +13,7 @@ import { ViewField } from '@/views/types/ViewField';
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
export const RecordIndexTableContainerEffect = () => {
|
export const RecordIndexTableContainerEffect = () => {
|
||||||
const { recordIndexId, objectNameSingular } = useContext(
|
const { recordIndexId, objectNameSingular } = useRecordIndexContextOrThrow();
|
||||||
RecordIndexRootPropsContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const viewBarId = recordIndexId;
|
const viewBarId = recordIndexId;
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { createRootPropsContext } from '~/utils/createRootPropsContext';
|
import { createRequiredContext } from '~/utils/createRequiredContext';
|
||||||
|
|
||||||
export type RecordIndexRootPropsContextProps = {
|
export type RecordIndexContextValue = {
|
||||||
indexIdentifierUrl: (recordId: string) => string;
|
indexIdentifierUrl: (recordId: string) => string;
|
||||||
onIndexRecordsLoaded: () => void;
|
onIndexRecordsLoaded: () => void;
|
||||||
onCreateRecord: () => void;
|
|
||||||
objectNamePlural: string;
|
objectNamePlural: string;
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
recordIndexId: string;
|
recordIndexId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordIndexRootPropsContext =
|
export const [RecordIndexContextProvider, useRecordIndexContextOrThrow] =
|
||||||
createRootPropsContext<RecordIndexRootPropsContextProps>();
|
createRequiredContext<RecordIndexContextValue>('RecordIndexContext');
|
||||||
@ -3,10 +3,9 @@ import { isNonEmptyString, isNull } from '@sniptt/guards';
|
|||||||
|
|
||||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
|
||||||
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
|
||||||
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
|
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
|
||||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
|
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { RecordTableBodyUnselectEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyUnselectEffect';
|
import { RecordTableBodyUnselectEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyUnselectEffect';
|
||||||
@ -29,19 +28,9 @@ const StyledTable = styled.table`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type RecordTableProps = {
|
export const RecordTable = () => {
|
||||||
viewBarId: string;
|
const { recordTableId, objectNameSingular } = useRecordTableContextOrThrow();
|
||||||
recordTableId: string;
|
|
||||||
objectNameSingular: string;
|
|
||||||
onColumnsChange: (columns: any) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RecordTable = ({
|
|
||||||
viewBarId,
|
|
||||||
recordTableId,
|
|
||||||
objectNameSingular,
|
|
||||||
onColumnsChange,
|
|
||||||
}: RecordTableProps) => {
|
|
||||||
const tableBodyRef = useRef<HTMLTableElement>(null);
|
const tableBodyRef = useRef<HTMLTableElement>(null);
|
||||||
|
|
||||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
@ -82,51 +71,39 @@ export const RecordTable = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableComponentInstance
|
<>
|
||||||
recordTableId={recordTableId}
|
{!hasRecordGroups ? (
|
||||||
onColumnsChange={onColumnsChange}
|
<RecordTableNoRecordGroupBodyEffect />
|
||||||
>
|
) : (
|
||||||
<RecordTableContextProvider
|
<RecordTableRecordGroupBodyEffects />
|
||||||
objectNameSingular={objectNameSingular}
|
)}
|
||||||
recordTableId={recordTableId}
|
<RecordTableBodyUnselectEffect tableBodyRef={tableBodyRef} />
|
||||||
viewBarId={viewBarId}
|
{recordTableIsEmpty ? (
|
||||||
>
|
<RecordTableEmptyState />
|
||||||
{!hasRecordGroups ? (
|
) : (
|
||||||
<RecordTableNoRecordGroupBodyEffect />
|
<>
|
||||||
) : (
|
<StyledTable className="entity-table-cell" ref={tableBodyRef}>
|
||||||
<RecordTableRecordGroupBodyEffects />
|
<RecordTableHeader />
|
||||||
)}
|
{!hasRecordGroups ? (
|
||||||
<RecordTableBodyUnselectEffect
|
<RecordTableNoRecordGroupBody />
|
||||||
tableBodyRef={tableBodyRef}
|
) : (
|
||||||
recordTableId={recordTableId}
|
<RecordTableRecordGroupsBody />
|
||||||
/>
|
)}
|
||||||
{recordTableIsEmpty ? (
|
<RecordTableStickyEffect />
|
||||||
<RecordTableEmptyState />
|
</StyledTable>
|
||||||
) : (
|
<DragSelect
|
||||||
<>
|
dragSelectable={tableBodyRef}
|
||||||
<StyledTable className="entity-table-cell" ref={tableBodyRef}>
|
onDragSelectionStart={() => {
|
||||||
<RecordTableHeader objectNameSingular={objectNameSingular} />
|
resetTableRowSelection();
|
||||||
{!hasRecordGroups ? (
|
toggleClickOutsideListener(false);
|
||||||
<RecordTableNoRecordGroupBody />
|
}}
|
||||||
) : (
|
onDragSelectionChange={setRowSelected}
|
||||||
<RecordTableRecordGroupsBody />
|
onDragSelectionEnd={() => {
|
||||||
)}
|
toggleClickOutsideListener(true);
|
||||||
<RecordTableStickyEffect />
|
}}
|
||||||
</StyledTable>
|
/>
|
||||||
<DragSelect
|
</>
|
||||||
dragSelectable={tableBodyRef}
|
)}
|
||||||
onDragSelectionStart={() => {
|
</>
|
||||||
resetTableRowSelection();
|
|
||||||
toggleClickOutsideListener(false);
|
|
||||||
}}
|
|
||||||
onDragSelectionChange={setRowSelected}
|
|
||||||
onDragSelectionEnd={() => {
|
|
||||||
toggleClickOutsideListener(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</RecordTableContextProvider>
|
|
||||||
</RecordTableComponentInstance>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,117 +1,44 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { RecordTableContextProvider as RecordTableContextInternalProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
|
||||||
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
|
|
||||||
import { useCloseRecordTableCellV2 } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCellV2';
|
|
||||||
import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2';
|
|
||||||
import {
|
|
||||||
OpenTableCellArgs,
|
|
||||||
useOpenRecordTableCellV2,
|
|
||||||
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
|
||||||
import { useTriggerActionMenuDropdown } from '@/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown';
|
|
||||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
|
||||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
|
type RecordTableContextProviderProps = {
|
||||||
|
viewBarId: string;
|
||||||
|
recordTableId: string;
|
||||||
|
objectNameSingular: string;
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
export const RecordTableContextProvider = ({
|
export const RecordTableContextProvider = ({
|
||||||
viewBarId,
|
viewBarId,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: RecordTableContextProviderProps) => {
|
||||||
viewBarId: string;
|
|
||||||
recordTableId: string;
|
|
||||||
objectNameSingular: string;
|
|
||||||
children: ReactNode;
|
|
||||||
}) => {
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { upsertRecord } = useUpsertRecord({
|
|
||||||
objectNameSingular,
|
|
||||||
recordTableId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleUpsertRecord = ({
|
|
||||||
persistField,
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
}: {
|
|
||||||
persistField: () => void;
|
|
||||||
recordId: string;
|
|
||||||
fieldName: string;
|
|
||||||
}) => {
|
|
||||||
upsertRecord(persistField, recordId, fieldName);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { openTableCell } = useOpenRecordTableCellV2(recordTableId);
|
|
||||||
|
|
||||||
const handleOpenTableCell = (args: OpenTableCellArgs) => {
|
|
||||||
openTableCell(args);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { moveFocus } = useRecordTableMoveFocus(recordTableId);
|
|
||||||
|
|
||||||
const handleMoveFocus = (direction: MoveFocusDirection) => {
|
|
||||||
moveFocus(direction);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { closeTableCell } = useCloseRecordTableCellV2(recordTableId);
|
|
||||||
|
|
||||||
const handleCloseTableCell = () => {
|
|
||||||
closeTableCell();
|
|
||||||
};
|
|
||||||
|
|
||||||
const { moveSoftFocusToCell } =
|
|
||||||
useMoveSoftFocusToCellOnHoverV2(recordTableId);
|
|
||||||
|
|
||||||
const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => {
|
|
||||||
moveSoftFocusToCell(cellPosition);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { triggerActionMenuDropdown } = useTriggerActionMenuDropdown({
|
|
||||||
recordTableId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleActionMenuDropdown = (
|
|
||||||
event: React.MouseEvent,
|
|
||||||
recordId: string,
|
|
||||||
) => {
|
|
||||||
triggerActionMenuDropdown(event, recordId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { handleContainerMouseEnter } = useHandleContainerMouseEnter({
|
|
||||||
recordTableId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const visibleTableColumns = useRecoilComponentValueV2(
|
const visibleTableColumns = useRecoilComponentValueV2(
|
||||||
visibleTableColumnsComponentSelector,
|
visibleTableColumnsComponentSelector,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableContext.Provider
|
<RecordTableContextInternalProvider
|
||||||
value={{
|
value={{
|
||||||
viewBarId,
|
viewBarId,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
onUpsertRecord: handleUpsertRecord,
|
|
||||||
onOpenTableCell: handleOpenTableCell,
|
|
||||||
onMoveFocus: handleMoveFocus,
|
|
||||||
onCloseTableCell: handleCloseTableCell,
|
|
||||||
onMoveSoftFocusToCell: handleMoveSoftFocusToCell,
|
|
||||||
onActionMenuDropdownOpened: handleActionMenuDropdown,
|
|
||||||
onCellMouseEnter: handleContainerMouseEnter,
|
|
||||||
visibleTableColumns,
|
visibleTableColumns,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</RecordTableContext.Provider>
|
</RecordTableContextInternalProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,95 @@
|
|||||||
|
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
||||||
|
import { useUpsertTableRecordNoGroup } from '@/object-record/record-table/hooks/internal/useUpsertTableRecordNoGroup';
|
||||||
|
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
|
||||||
|
import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup';
|
||||||
|
import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2';
|
||||||
|
import {
|
||||||
|
OpenTableCellArgs,
|
||||||
|
useOpenRecordTableCellV2,
|
||||||
|
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useTriggerActionMenuDropdown } from '@/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown';
|
||||||
|
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||||
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
type RecordTableNoRecordGroupBodyContextProviderProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordTableNoRecordGroupBodyContextProvider = ({
|
||||||
|
children,
|
||||||
|
}: RecordTableNoRecordGroupBodyContextProviderProps) => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
|
const { upsertTableRecordNoGroup } = useUpsertTableRecordNoGroup();
|
||||||
|
|
||||||
|
const handleUpsertTableRecordNoRecordGroup = ({
|
||||||
|
persistField,
|
||||||
|
recordId,
|
||||||
|
fieldName,
|
||||||
|
}: {
|
||||||
|
persistField: () => void;
|
||||||
|
recordId: string;
|
||||||
|
fieldName: string;
|
||||||
|
}) => {
|
||||||
|
upsertTableRecordNoGroup(persistField, recordId, fieldName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { openTableCell } = useOpenRecordTableCellV2(recordTableId);
|
||||||
|
|
||||||
|
const handleOpenTableCell = (args: OpenTableCellArgs) => {
|
||||||
|
openTableCell(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { moveFocus } = useRecordTableMoveFocus(recordTableId);
|
||||||
|
|
||||||
|
const handleMoveFocus = (direction: MoveFocusDirection) => {
|
||||||
|
moveFocus(direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { closeTableCellNoGroup } = useCloseRecordTableCellNoGroup();
|
||||||
|
|
||||||
|
const handleCloseTableCell = () => {
|
||||||
|
closeTableCellNoGroup();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { moveSoftFocusToCell } =
|
||||||
|
useMoveSoftFocusToCellOnHoverV2(recordTableId);
|
||||||
|
|
||||||
|
const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => {
|
||||||
|
moveSoftFocusToCell(cellPosition);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { triggerActionMenuDropdown } = useTriggerActionMenuDropdown({
|
||||||
|
recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleActionMenuDropdown = (
|
||||||
|
event: React.MouseEvent,
|
||||||
|
recordId: string,
|
||||||
|
) => {
|
||||||
|
triggerActionMenuDropdown(event, recordId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { handleContainerMouseEnter } = useHandleContainerMouseEnter({
|
||||||
|
recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableBodyContextProvider
|
||||||
|
value={{
|
||||||
|
onUpsertRecord: handleUpsertTableRecordNoRecordGroup,
|
||||||
|
onOpenTableCell: handleOpenTableCell,
|
||||||
|
onMoveFocus: handleMoveFocus,
|
||||||
|
onCloseTableCell: handleCloseTableCell,
|
||||||
|
onMoveSoftFocusToCell: handleMoveSoftFocusToCell,
|
||||||
|
onActionMenuDropdownOpened: handleActionMenuDropdown,
|
||||||
|
onCellMouseEnter: handleContainerMouseEnter,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RecordTableBodyContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
||||||
|
import { useUpsertTableRecordInGroup } from '@/object-record/record-table/hooks/internal/useUpsertTableRecordInGroup';
|
||||||
|
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
|
||||||
|
import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup';
|
||||||
|
import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2';
|
||||||
|
import {
|
||||||
|
OpenTableCellArgs,
|
||||||
|
useOpenRecordTableCellV2,
|
||||||
|
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useTriggerActionMenuDropdown } from '@/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown';
|
||||||
|
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||||
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
type RecordTableRecordGroupBodyContextProviderProps = {
|
||||||
|
recordGroupId: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordTableRecordGroupBodyContextProvider = ({
|
||||||
|
recordGroupId,
|
||||||
|
children,
|
||||||
|
}: RecordTableRecordGroupBodyContextProviderProps) => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
|
const { upsertTableRecordInGroup } =
|
||||||
|
useUpsertTableRecordInGroup(recordGroupId);
|
||||||
|
|
||||||
|
const handleupsertTableRecordInGroup = ({
|
||||||
|
persistField,
|
||||||
|
recordId,
|
||||||
|
fieldName,
|
||||||
|
}: {
|
||||||
|
persistField: () => void;
|
||||||
|
recordId: string;
|
||||||
|
fieldName: string;
|
||||||
|
}) => {
|
||||||
|
upsertTableRecordInGroup(persistField, recordId, fieldName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { openTableCell } = useOpenRecordTableCellV2(recordTableId);
|
||||||
|
|
||||||
|
const handleOpenTableCell = (args: OpenTableCellArgs) => {
|
||||||
|
openTableCell(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { moveFocus } = useRecordTableMoveFocus(recordTableId);
|
||||||
|
|
||||||
|
const handleMoveFocus = (direction: MoveFocusDirection) => {
|
||||||
|
moveFocus(direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { closeTableCellInGroup } =
|
||||||
|
useCloseRecordTableCellInGroup(recordGroupId);
|
||||||
|
|
||||||
|
const handlecloseTableCellInGroup = () => {
|
||||||
|
closeTableCellInGroup();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { moveSoftFocusToCell } =
|
||||||
|
useMoveSoftFocusToCellOnHoverV2(recordTableId);
|
||||||
|
|
||||||
|
const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => {
|
||||||
|
moveSoftFocusToCell(cellPosition);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { triggerActionMenuDropdown } = useTriggerActionMenuDropdown({
|
||||||
|
recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleActionMenuDropdown = (
|
||||||
|
event: React.MouseEvent,
|
||||||
|
recordId: string,
|
||||||
|
) => {
|
||||||
|
triggerActionMenuDropdown(event, recordId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { handleContainerMouseEnter } = useHandleContainerMouseEnter({
|
||||||
|
recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableBodyContextProvider
|
||||||
|
value={{
|
||||||
|
onUpsertRecord: handleupsertTableRecordInGroup,
|
||||||
|
onOpenTableCell: handleOpenTableCell,
|
||||||
|
onMoveFocus: handleMoveFocus,
|
||||||
|
onCloseTableCell: handlecloseTableCellInGroup,
|
||||||
|
onMoveSoftFocusToCell: handleMoveSoftFocusToCell,
|
||||||
|
onActionMenuDropdownOpened: handleActionMenuDropdown,
|
||||||
|
onCellMouseEnter: handleContainerMouseEnter,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RecordTableBodyContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,7 +1,10 @@
|
|||||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
|
import { RecordTablePendingRecordGroupRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRecordGroupRow';
|
||||||
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
||||||
|
import { RecordTableRecordGroupSectionAddNew } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew';
|
||||||
|
import { RecordTableRecordGroupSectionLoadMore } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore';
|
||||||
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
|
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -30,24 +33,32 @@ export const RecordTableRecordGroupRows = () => {
|
|||||||
[allRecordIds],
|
[allRecordIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!isRecordGroupTableSectionToggled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isRecordGroupTableSectionToggled &&
|
<>
|
||||||
recordIdsByGroup.map((recordId, rowIndexInGroup) => {
|
{recordIdsByGroup.map((recordId, rowIndexInGroup) => {
|
||||||
const rowIndex = rowIndexMap.get(recordId);
|
const rowIndex = rowIndexMap.get(recordId);
|
||||||
|
|
||||||
if (!isDefined(rowIndex)) {
|
if (!isDefined(rowIndex)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableRow
|
<RecordTableRow
|
||||||
key={recordId}
|
key={recordId}
|
||||||
recordId={recordId}
|
recordId={recordId}
|
||||||
rowIndexForFocus={rowIndex}
|
rowIndexForFocus={rowIndex}
|
||||||
rowIndexForDrag={rowIndexInGroup}
|
rowIndexForDrag={rowIndexInGroup}
|
||||||
isPendingRow={!isRecordGroupTableSectionToggled}
|
isPendingRow={!isRecordGroupTableSectionToggled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})}
|
||||||
|
<RecordTableRecordGroupSectionLoadMore />
|
||||||
|
<RecordTablePendingRecordGroupRow />
|
||||||
|
<RecordTableRecordGroupSectionAddNew />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import { RecordUpdateContext } from '../contexts/EntityUpdateMutationHookContext
|
|||||||
import { useRecordTable } from '../hooks/useRecordTable';
|
import { useRecordTable } from '../hooks/useRecordTable';
|
||||||
|
|
||||||
import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope';
|
import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope';
|
||||||
|
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
@ -96,27 +98,33 @@ export const RecordTableWithWrappers = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
<RecordTableComponentInstance
|
||||||
<ScrollWrapper
|
recordTableId={recordTableId}
|
||||||
enableXScroll={isScrollEnabledForRecordTable.enableXScroll}
|
onColumnsChange={handleColumnsChange}
|
||||||
enableYScroll={isScrollEnabledForRecordTable.enableYScroll}
|
>
|
||||||
contextProviderName="recordTableWithWrappers"
|
<RecordTableContextProvider
|
||||||
|
recordTableId={recordTableId}
|
||||||
|
viewBarId={viewBarId}
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
>
|
>
|
||||||
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
||||||
<StyledTableWithHeader>
|
<ScrollWrapper
|
||||||
<StyledTableContainer>
|
enableXScroll={isScrollEnabledForRecordTable.enableXScroll}
|
||||||
<StyledTableInternalContainer>
|
enableYScroll={isScrollEnabledForRecordTable.enableYScroll}
|
||||||
<RecordTable
|
contextProviderName="recordTableWithWrappers"
|
||||||
viewBarId={viewBarId}
|
>
|
||||||
recordTableId={recordTableId}
|
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
||||||
objectNameSingular={objectNameSingular}
|
<StyledTableWithHeader>
|
||||||
onColumnsChange={handleColumnsChange}
|
<StyledTableContainer>
|
||||||
/>
|
<StyledTableInternalContainer>
|
||||||
</StyledTableInternalContainer>
|
<RecordTable />
|
||||||
</StyledTableContainer>
|
</StyledTableInternalContainer>
|
||||||
</StyledTableWithHeader>
|
</StyledTableContainer>
|
||||||
</RecordUpdateContext.Provider>
|
</StyledTableWithHeader>
|
||||||
</ScrollWrapper>
|
</RecordUpdateContext.Provider>
|
||||||
</EntityDeleteContext.Provider>
|
</ScrollWrapper>
|
||||||
|
</EntityDeleteContext.Provider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
|
</RecordTableComponentInstance>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,12 +14,13 @@ import {
|
|||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
||||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||||
|
|
||||||
|
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { mockPerformance } from './mock';
|
import { mockPerformance } from './mock';
|
||||||
@ -61,78 +62,83 @@ const meta: Meta = {
|
|||||||
(Story) => {
|
(Story) => {
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<RecordFieldValueSelectorContextProvider>
|
||||||
<RecordTableContext.Provider
|
<RecordTableContextProvider
|
||||||
value={{
|
value={{
|
||||||
|
recordTableId: 'recordTableId',
|
||||||
viewBarId: mockPerformance.recordId,
|
viewBarId: mockPerformance.recordId,
|
||||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||||
onUpsertRecord: () => {},
|
|
||||||
onOpenTableCell: () => {},
|
|
||||||
onMoveFocus: () => {},
|
|
||||||
onCloseTableCell: () => {},
|
|
||||||
onMoveSoftFocusToCell: () => {},
|
|
||||||
onActionMenuDropdownOpened: () => {},
|
|
||||||
onCellMouseEnter: () => {},
|
|
||||||
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
||||||
objectNameSingular:
|
objectNameSingular:
|
||||||
mockPerformance.objectMetadataItem.nameSingular,
|
mockPerformance.objectMetadataItem.nameSingular,
|
||||||
recordTableId: 'recordTableId',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableComponentInstance
|
<RecordTableComponentInstance
|
||||||
recordTableId="asd"
|
recordTableId="asd"
|
||||||
onColumnsChange={() => {}}
|
onColumnsChange={() => {}}
|
||||||
>
|
>
|
||||||
<RecordTableRowContext.Provider
|
<RecordTableBodyContextProvider
|
||||||
value={{
|
value={{
|
||||||
objectNameSingular:
|
onUpsertRecord: () => {},
|
||||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
onOpenTableCell: () => {},
|
||||||
recordId: mockPerformance.recordId,
|
onMoveFocus: () => {},
|
||||||
rowIndex: 0,
|
onCloseTableCell: () => {},
|
||||||
pathToShowPage:
|
onMoveSoftFocusToCell: () => {},
|
||||||
getBasePathToShowPage({
|
onActionMenuDropdownOpened: () => {},
|
||||||
objectNameSingular:
|
onCellMouseEnter: () => {},
|
||||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
|
||||||
}) + mockPerformance.recordId,
|
|
||||||
isSelected: false,
|
|
||||||
isDragging: false,
|
|
||||||
dragHandleProps: null,
|
|
||||||
inView: true,
|
|
||||||
isPendingRow: false,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableCellContext.Provider
|
<RecordTableRowContext.Provider
|
||||||
value={{
|
value={{
|
||||||
columnDefinition: mockPerformance.fieldDefinition,
|
objectNameSingular:
|
||||||
columnIndex: 0,
|
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||||
cellPosition: { row: 0, column: 0 },
|
recordId: mockPerformance.recordId,
|
||||||
hasSoftFocus: false,
|
rowIndex: 0,
|
||||||
isInEditMode: false,
|
pathToShowPage:
|
||||||
|
getBasePathToShowPage({
|
||||||
|
objectNameSingular:
|
||||||
|
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||||
|
}) + mockPerformance.recordId,
|
||||||
|
isSelected: false,
|
||||||
|
isDragging: false,
|
||||||
|
dragHandleProps: null,
|
||||||
|
inView: true,
|
||||||
|
isPendingRow: false,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<RecordTableCellContext.Provider
|
||||||
value={{
|
value={{
|
||||||
recordId: mockPerformance.recordId,
|
columnDefinition: mockPerformance.fieldDefinition,
|
||||||
basePathToShowPage: '/object-record/',
|
columnIndex: 0,
|
||||||
isLabelIdentifier: false,
|
cellPosition: { row: 0, column: 0 },
|
||||||
fieldDefinition: {
|
hasSoftFocus: false,
|
||||||
...mockPerformance.fieldDefinition,
|
isInEditMode: false,
|
||||||
},
|
|
||||||
hotkeyScope: 'hotkey-scope',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RelationFieldValueSetterEffect />
|
<FieldContext.Provider
|
||||||
<table>
|
value={{
|
||||||
<tbody>
|
recordId: mockPerformance.recordId,
|
||||||
<tr>
|
basePathToShowPage: '/object-record/',
|
||||||
<Story />
|
isLabelIdentifier: false,
|
||||||
</tr>
|
fieldDefinition: {
|
||||||
</tbody>
|
...mockPerformance.fieldDefinition,
|
||||||
</table>
|
},
|
||||||
</FieldContext.Provider>
|
hotkeyScope: 'hotkey-scope',
|
||||||
</RecordTableCellContext.Provider>
|
}}
|
||||||
</RecordTableRowContext.Provider>
|
>
|
||||||
|
<RelationFieldValueSetterEffect />
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<Story />
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</RecordTableCellContext.Provider>
|
||||||
|
</RecordTableRowContext.Provider>
|
||||||
|
</RecordTableBodyContextProvider>
|
||||||
</RecordTableComponentInstance>
|
</RecordTableComponentInstance>
|
||||||
</RecordTableContext.Provider>
|
</RecordTableContextProvider>
|
||||||
</RecordFieldValueSelectorContextProvider>
|
</RecordFieldValueSelectorContextProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { HandleContainerMouseEnterArgs } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
||||||
|
import { OpenTableCellArgs } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||||
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
|
import { createRequiredContext } from '~/utils/createRequiredContext';
|
||||||
|
|
||||||
|
export type RecordTableBodyContextProps = {
|
||||||
|
recordGroupId?: string;
|
||||||
|
onUpsertRecord: ({
|
||||||
|
persistField,
|
||||||
|
recordId,
|
||||||
|
fieldName,
|
||||||
|
}: {
|
||||||
|
persistField: () => void;
|
||||||
|
recordId: string;
|
||||||
|
fieldName: string;
|
||||||
|
}) => void;
|
||||||
|
onOpenTableCell: (args: OpenTableCellArgs) => void;
|
||||||
|
onMoveFocus: (direction: MoveFocusDirection) => void;
|
||||||
|
onCloseTableCell: () => void;
|
||||||
|
onMoveSoftFocusToCell: (cellPosition: TableCellPosition) => void;
|
||||||
|
onActionMenuDropdownOpened: (
|
||||||
|
event: React.MouseEvent,
|
||||||
|
recordId: string,
|
||||||
|
) => void;
|
||||||
|
onCellMouseEnter: (args: HandleContainerMouseEnterArgs) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const [
|
||||||
|
RecordTableBodyContextProvider,
|
||||||
|
useRecordTableBodyContextOrThrow,
|
||||||
|
] = createRequiredContext<RecordTableBodyContextProps>(
|
||||||
|
'RecordTableBodyContext',
|
||||||
|
);
|
||||||
@ -1,39 +1,15 @@
|
|||||||
import React, { createContext } from 'react';
|
|
||||||
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { HandleContainerMouseEnterArgs } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
|
||||||
import { OpenTableCellArgs } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
import { createRequiredContext } from '~/utils/createRequiredContext';
|
||||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
|
||||||
|
|
||||||
export type RecordTableContextProps = {
|
export type RecordTableContextValue = {
|
||||||
viewBarId: string;
|
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
|
||||||
onUpsertRecord: ({
|
|
||||||
persistField,
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
}: {
|
|
||||||
persistField: () => void;
|
|
||||||
recordId: string;
|
|
||||||
fieldName: string;
|
|
||||||
}) => void;
|
|
||||||
onOpenTableCell: (args: OpenTableCellArgs) => void;
|
|
||||||
onMoveFocus: (direction: MoveFocusDirection) => void;
|
|
||||||
onCloseTableCell: () => void;
|
|
||||||
onMoveSoftFocusToCell: (cellPosition: TableCellPosition) => void;
|
|
||||||
onActionMenuDropdownOpened: (
|
|
||||||
event: React.MouseEvent,
|
|
||||||
recordId: string,
|
|
||||||
) => void;
|
|
||||||
onCellMouseEnter: (args: HandleContainerMouseEnterArgs) => void;
|
|
||||||
visibleTableColumns: ColumnDefinition<FieldMetadata>[];
|
|
||||||
recordTableId: string;
|
recordTableId: string;
|
||||||
|
viewBarId: string;
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
visibleTableColumns: ColumnDefinition<FieldMetadata>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableContext = createContext<RecordTableContextProps>(
|
export const [RecordTableContextProvider, useRecordTableContextOrThrow] =
|
||||||
{} as RecordTableContextProps,
|
createRequiredContext<RecordTableContextValue>('RecordTableContext');
|
||||||
);
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export type RecordTableRowContextProps = {
|
|||||||
isDragging: boolean;
|
isDragging: boolean;
|
||||||
dragHandleProps: DraggableProvidedDragHandleProps | null;
|
dragHandleProps: DraggableProvidedDragHandleProps | null;
|
||||||
inView?: boolean;
|
inView?: boolean;
|
||||||
|
isDragDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableRowContext = createContext<RecordTableRowContextProps>(
|
export const RecordTableRowContext = createContext<RecordTableRowContextProps>(
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableEmptyStateNoRecordAtAll } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordAtAll';
|
import { RecordTableEmptyStateNoRecordAtAll } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordAtAll';
|
||||||
import { RecordTableEmptyStateNoRecordFoundForFilter } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordFoundForFilter';
|
import { RecordTableEmptyStateNoRecordFoundForFilter } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordFoundForFilter';
|
||||||
import { RecordTableEmptyStateRemote } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateRemote';
|
import { RecordTableEmptyStateRemote } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateRemote';
|
||||||
import { RecordTableEmptyStateSoftDelete } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete';
|
import { RecordTableEmptyStateSoftDelete } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete';
|
||||||
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
export const RecordTableEmptyState = () => {
|
export const RecordTableEmptyState = () => {
|
||||||
const { objectNameSingular, recordTableId, objectMetadataItem } =
|
const { recordTableId, objectNameSingular, objectMetadataItem } =
|
||||||
useContext(RecordTableContext);
|
useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { totalCount } = useFindManyRecords({ objectNameSingular, limit: 1 });
|
const { totalCount } = useFindManyRecords({ objectNameSingular, limit: 1 });
|
||||||
const noRecordAtAll = totalCount === 0;
|
const noRecordAtAll = totalCount === 0;
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useContext } from 'react';
|
|
||||||
import {
|
import {
|
||||||
AnimatedPlaceholder,
|
AnimatedPlaceholder,
|
||||||
AnimatedPlaceholderEmptyContainer,
|
AnimatedPlaceholderEmptyContainer,
|
||||||
@ -29,7 +28,7 @@ export const RecordTableEmptyStateDisplay = ({
|
|||||||
subTitle,
|
subTitle,
|
||||||
title,
|
title,
|
||||||
}: RecordTableEmptyStateDisplayProps) => {
|
}: RecordTableEmptyStateDisplayProps) => {
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
const isReadOnly = isObjectMetadataReadOnly(objectMetadataItem);
|
const isReadOnly = isObjectMetadataReadOnly(objectMetadataItem);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { IconPlus } from 'twenty-ui';
|
import { IconPlus } from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
||||||
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
export const RecordTableEmptyStateNoRecordAtAll = () => {
|
export const RecordTableEmptyStateNoRecordAtAll = () => {
|
||||||
const { createNewTableRecord } = useCreateNewTableRecord();
|
const { objectMetadataItem, recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { createNewTableRecord } = useCreateNewTableRecord(recordTableId);
|
||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
createNewTableRecord();
|
createNewTableRecord();
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { IconPlus } from 'twenty-ui';
|
import { IconPlus } from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
||||||
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
export const RecordTableEmptyStateNoRecordFoundForFilter = () => {
|
export const RecordTableEmptyStateNoRecordFoundForFilter = () => {
|
||||||
const { createNewTableRecord } = useCreateNewTableRecord();
|
const { recordTableId, objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { createNewTableRecord } = useCreateNewTableRecord(recordTableId);
|
||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
createNewTableRecord();
|
createNewTableRecord();
|
||||||
|
|||||||
@ -2,16 +2,15 @@ import { IconFilterOff } from 'twenty-ui';
|
|||||||
|
|
||||||
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
||||||
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay';
|
||||||
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
export const RecordTableEmptyStateSoftDelete = () => {
|
export const RecordTableEmptyStateSoftDelete = () => {
|
||||||
const { objectMetadataItem, objectNameSingular, recordTableId } =
|
const { objectMetadataItem, objectNameSingular, recordTableId } =
|
||||||
useContext(RecordTableContext);
|
useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { deleteCombinedViewFilter } =
|
const { deleteCombinedViewFilter } =
|
||||||
useDeleteCombinedViewFilters(recordTableId);
|
useDeleteCombinedViewFilters(recordTableId);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { act, renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode, act } from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
import { createState } from 'twenty-ui';
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
@ -9,12 +9,16 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
|
import { useUpsertTableRecordInGroup } from '@/object-record/record-table/hooks/internal/useUpsertTableRecordInGroup';
|
||||||
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
const draftValue = 'updated Name';
|
const draftValue = 'updated Name';
|
||||||
|
const recordGroupId = 'recordGroupId';
|
||||||
|
|
||||||
// Todo refactor this test to inject the states in a cleaner way instead of mocking hooks
|
// Todo refactor this test to inject the states in a cleaner way instead of mocking hooks
|
||||||
// (this is not easy to maintain while refactoring)
|
// (this is not easy to maintain while refactoring)
|
||||||
@ -37,8 +41,11 @@ jest.mock(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const pendingRecordIdState = createState<string | null>({
|
const recordTablePendingRecordIdByGroupComponentFamilyState = createFamilyState<
|
||||||
key: 'pendingRecordIdState',
|
string | null,
|
||||||
|
string
|
||||||
|
>({
|
||||||
|
key: 'recordTablePendingRecordIdByGroupComponentFamilyState',
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,46 +67,64 @@ const Wrapper = ({
|
|||||||
<RecoilRoot
|
<RecoilRoot
|
||||||
initializeState={(snapshot) => {
|
initializeState={(snapshot) => {
|
||||||
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||||
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
|
snapshot.set(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState(recordGroupId),
|
||||||
|
pendingRecordIdMockedValue,
|
||||||
|
);
|
||||||
snapshot.set(draftValueState, draftValueMockedValue);
|
snapshot.set(draftValueState, draftValueMockedValue);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<RecordTableContextProvider
|
||||||
value={{ instanceId: CoreObjectNamePlural.Person }}
|
recordTableId="recordTableId"
|
||||||
|
objectNameSingular={CoreObjectNameSingular.Person}
|
||||||
|
viewBarId="viewBarId"
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<RecordTableComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
recordId: 'recordId',
|
instanceId: CoreObjectNamePlural.Person,
|
||||||
fieldDefinition: {
|
onColumnsChange: jest.fn(),
|
||||||
...textfieldDefinition,
|
|
||||||
metadata: {
|
|
||||||
...textfieldDefinition.metadata,
|
|
||||||
objectMetadataNameSingular: CoreObjectNameSingular.Person,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hotkeyScope: TableHotkeyScope.Table,
|
|
||||||
isLabelIdentifier: false,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
<ViewComponentInstanceContext.Provider
|
||||||
</FieldContext.Provider>
|
value={{ instanceId: CoreObjectNamePlural.Person }}
|
||||||
</ViewComponentInstanceContext.Provider>
|
>
|
||||||
|
<FieldContext.Provider
|
||||||
|
value={{
|
||||||
|
recordId: 'recordId',
|
||||||
|
fieldDefinition: {
|
||||||
|
...textfieldDefinition,
|
||||||
|
metadata: {
|
||||||
|
...textfieldDefinition.metadata,
|
||||||
|
objectMetadataNameSingular: CoreObjectNameSingular.Person,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hotkeyScope: TableHotkeyScope.Table,
|
||||||
|
isLabelIdentifier: false,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordTableComponentInstanceContext.Provider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('useUpsertRecord', () => {
|
describe('useUpsertTableRecordInGroup', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
createOneRecordMock.mockClear();
|
createOneRecordMock.mockClear();
|
||||||
updateOneRecordMock.mockClear();
|
updateOneRecordMock.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls update record if there is no pending record', async () => {
|
it('calls update record if there is no pending record', async () => {
|
||||||
const { result } = renderHook(
|
/**
|
||||||
() =>
|
* {
|
||||||
useUpsertRecord({
|
|
||||||
objectNameSingular: 'person',
|
objectNameSingular: 'person',
|
||||||
recordTableId: 'recordTableId',
|
recordTableId: 'recordTableId',
|
||||||
}),
|
}
|
||||||
|
*/
|
||||||
|
const { result } = renderHook(
|
||||||
|
() => useUpsertTableRecordInGroup(recordGroupId),
|
||||||
{
|
{
|
||||||
wrapper: ({ children }) =>
|
wrapper: ({ children }) =>
|
||||||
Wrapper({
|
Wrapper({
|
||||||
@ -111,7 +136,7 @@ describe('useUpsertRecord', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.upsertRecord(
|
await result.current.upsertTableRecordInGroup(
|
||||||
updateOneRecordMock,
|
updateOneRecordMock,
|
||||||
'recordId',
|
'recordId',
|
||||||
'name',
|
'name',
|
||||||
@ -124,11 +149,7 @@ describe('useUpsertRecord', () => {
|
|||||||
|
|
||||||
it('calls update record if pending record is empty', async () => {
|
it('calls update record if pending record is empty', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() => useUpsertTableRecordInGroup(recordGroupId),
|
||||||
useUpsertRecord({
|
|
||||||
objectNameSingular: 'person',
|
|
||||||
recordTableId: 'recordTableId',
|
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
wrapper: ({ children }) =>
|
wrapper: ({ children }) =>
|
||||||
Wrapper({
|
Wrapper({
|
||||||
@ -140,7 +161,7 @@ describe('useUpsertRecord', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.upsertRecord(
|
await result.current.upsertTableRecordInGroup(
|
||||||
updateOneRecordMock,
|
updateOneRecordMock,
|
||||||
'recordId',
|
'recordId',
|
||||||
'name',
|
'name',
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode, act } from 'react';
|
||||||
|
import { RecoilRoot } from 'recoil';
|
||||||
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
|
import { useUpsertTableRecordNoGroup } from '@/object-record/record-table/hooks/internal/useUpsertTableRecordNoGroup';
|
||||||
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
|
const draftValue = 'updated Name';
|
||||||
|
|
||||||
|
// Todo refactor this test to inject the states in a cleaner way instead of mocking hooks
|
||||||
|
// (this is not easy to maintain while refactoring)
|
||||||
|
jest.mock('@/object-record/hooks/useCreateOneRecord', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
useCreateOneRecord: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const draftValueState = createState<string | null>({
|
||||||
|
key: 'draftValueState',
|
||||||
|
defaultValue: null,
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'@/object-record/record-field/hooks/internal/useRecordFieldInputStates',
|
||||||
|
() => ({
|
||||||
|
__esModule: true,
|
||||||
|
useRecordFieldInputStates: jest.fn(() => ({
|
||||||
|
getDraftValueSelector: () => draftValueState,
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const pendingRecordIdState = createState<string | null>({
|
||||||
|
key: 'pendingRecordIdState',
|
||||||
|
defaultValue: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createOneRecordMock = jest.fn();
|
||||||
|
const updateOneRecordMock = jest.fn();
|
||||||
|
(useCreateOneRecord as jest.Mock).mockReturnValue({
|
||||||
|
createOneRecord: createOneRecordMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Wrapper = ({
|
||||||
|
children,
|
||||||
|
pendingRecordIdMockedValue,
|
||||||
|
draftValueMockedValue,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
pendingRecordIdMockedValue: string | null;
|
||||||
|
draftValueMockedValue: string | null;
|
||||||
|
}) => (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={(snapshot) => {
|
||||||
|
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||||
|
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
|
||||||
|
snapshot.set(draftValueState, draftValueMockedValue);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecordTableContextProvider
|
||||||
|
recordTableId="recordTableId"
|
||||||
|
objectNameSingular={CoreObjectNameSingular.Person}
|
||||||
|
viewBarId="viewBarId"
|
||||||
|
>
|
||||||
|
<RecordTableComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: CoreObjectNamePlural.Person,
|
||||||
|
onColumnsChange: jest.fn(),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ViewComponentInstanceContext.Provider
|
||||||
|
value={{ instanceId: CoreObjectNamePlural.Person }}
|
||||||
|
>
|
||||||
|
<FieldContext.Provider
|
||||||
|
value={{
|
||||||
|
recordId: 'recordId',
|
||||||
|
fieldDefinition: {
|
||||||
|
...textfieldDefinition,
|
||||||
|
metadata: {
|
||||||
|
...textfieldDefinition.metadata,
|
||||||
|
objectMetadataNameSingular: CoreObjectNameSingular.Person,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hotkeyScope: TableHotkeyScope.Table,
|
||||||
|
isLabelIdentifier: false,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordTableComponentInstanceContext.Provider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
|
</RecoilRoot>
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('useUpsertTableRecordNoGroup', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
createOneRecordMock.mockClear();
|
||||||
|
updateOneRecordMock.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls update record if there is no pending record', async () => {
|
||||||
|
/**
|
||||||
|
* {
|
||||||
|
objectNameSingular: 'person',
|
||||||
|
recordTableId: 'recordTableId',
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const { result } = renderHook(() => useUpsertTableRecordNoGroup(), {
|
||||||
|
wrapper: ({ children }) =>
|
||||||
|
Wrapper({
|
||||||
|
pendingRecordIdMockedValue: null,
|
||||||
|
draftValueMockedValue: null,
|
||||||
|
children,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await result.current.upsertTableRecordNoGroup(
|
||||||
|
updateOneRecordMock,
|
||||||
|
'recordId',
|
||||||
|
'name',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createOneRecordMock).not.toHaveBeenCalled();
|
||||||
|
expect(updateOneRecordMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls update record if pending record is empty', async () => {
|
||||||
|
const { result } = renderHook(() => useUpsertTableRecordNoGroup(), {
|
||||||
|
wrapper: ({ children }) =>
|
||||||
|
Wrapper({
|
||||||
|
pendingRecordIdMockedValue: null,
|
||||||
|
draftValueMockedValue: draftValue,
|
||||||
|
children,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await result.current.upsertTableRecordNoGroup(
|
||||||
|
updateOneRecordMock,
|
||||||
|
'recordId',
|
||||||
|
'name',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createOneRecordMock).not.toHaveBeenCalled();
|
||||||
|
expect(updateOneRecordMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||||
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
|
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
||||||
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||||
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
export const useUpsertTableRecordInGroup = (recordGroupId: string) => {
|
||||||
|
const { objectMetadataItem, objectNameSingular } =
|
||||||
|
useRecordTableContextOrThrow();
|
||||||
|
|
||||||
|
const { createOneRecord } = useCreateOneRecord({
|
||||||
|
objectNameSingular,
|
||||||
|
shouldMatchRootQueryFilter: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const recordTablePendingRecordIdByGroupFamilyState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const upsertTableRecordInGroup = useRecoilCallback(
|
||||||
|
({ snapshot }) =>
|
||||||
|
(persistField: () => void, recordId: string, fieldName: string) => {
|
||||||
|
const labelIdentifierFieldMetadataItem =
|
||||||
|
getLabelIdentifierFieldMetadataItem(objectMetadataItem);
|
||||||
|
|
||||||
|
const fieldScopeId = getScopeIdFromComponentId(
|
||||||
|
`${recordId}-${fieldName}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const draftValueSelector = extractComponentSelector(
|
||||||
|
recordFieldInputDraftValueComponentSelector,
|
||||||
|
fieldScopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
||||||
|
|
||||||
|
// We're in a record group
|
||||||
|
const recordTablePendingRecordId = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState(recordGroupId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordGroupDefinition = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
recordGroupDefinitionFamilyState(recordGroupId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordGroupFieldMetadataItem = objectMetadataItem.fields.find(
|
||||||
|
(fieldMetadata) =>
|
||||||
|
fieldMetadata.id === recordGroupDefinition?.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
isDefined(recordTablePendingRecordId) &&
|
||||||
|
isDefined(recordGroupDefinition) &&
|
||||||
|
isDefined(recordGroupFieldMetadataItem) &&
|
||||||
|
isDefined(draftValue)
|
||||||
|
) {
|
||||||
|
createOneRecord({
|
||||||
|
id: recordTablePendingRecordId,
|
||||||
|
[labelIdentifierFieldMetadataItem?.name ?? 'name']: draftValue,
|
||||||
|
[recordGroupFieldMetadataItem.name]: recordGroupDefinition.value,
|
||||||
|
position: 'first',
|
||||||
|
});
|
||||||
|
} else if (!recordTablePendingRecordId) {
|
||||||
|
persistField();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createOneRecord,
|
||||||
|
objectMetadataItem,
|
||||||
|
recordGroupId,
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { upsertTableRecordInGroup };
|
||||||
|
};
|
||||||
@ -1,32 +1,22 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
|
||||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
||||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useUpsertRecord = ({
|
export const useUpsertTableRecordNoGroup = () => {
|
||||||
objectNameSingular,
|
const { objectMetadataItem, objectNameSingular, recordTableId } =
|
||||||
recordTableId,
|
useRecordTableContextOrThrow();
|
||||||
}: {
|
|
||||||
objectNameSingular: string;
|
|
||||||
recordTableId: string;
|
|
||||||
}) => {
|
|
||||||
const hasRecordGroups = useRecoilComponentValueV2(
|
|
||||||
hasRecordGroupsComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { createOneRecord } = useCreateOneRecord({
|
const { createOneRecord } = useCreateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
shouldMatchRootQueryFilter: hasRecordGroups,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const recordTablePendingRecordIdState = useRecoilComponentCallbackStateV2(
|
const recordTablePendingRecordIdState = useRecoilComponentCallbackStateV2(
|
||||||
@ -34,28 +24,12 @@ export const useUpsertRecord = ({
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const upsertRecord = useRecoilCallback(
|
const upsertTableRecordNoGroup = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(persistField: () => void, recordId: string, fieldName: string) => {
|
(persistField: () => void, recordId: string, fieldName: string) => {
|
||||||
const objectMetadataItems = snapshot
|
|
||||||
.getLoadable(objectMetadataItemsState)
|
|
||||||
.getValue();
|
|
||||||
|
|
||||||
const foundObjectMetadataItem = objectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === objectNameSingular,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!foundObjectMetadataItem) {
|
|
||||||
throw new Error('Object metadata item cannot be found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const labelIdentifierFieldMetadataItem =
|
const labelIdentifierFieldMetadataItem =
|
||||||
getLabelIdentifierFieldMetadataItem(foundObjectMetadataItem);
|
getLabelIdentifierFieldMetadataItem(objectMetadataItem);
|
||||||
|
|
||||||
const recordTablePendingRecordId = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
recordTablePendingRecordIdState,
|
|
||||||
);
|
|
||||||
const fieldScopeId = getScopeIdFromComponentId(
|
const fieldScopeId = getScopeIdFromComponentId(
|
||||||
`${recordId}-${fieldName}`,
|
`${recordId}-${fieldName}`,
|
||||||
);
|
);
|
||||||
@ -67,6 +41,11 @@ export const useUpsertRecord = ({
|
|||||||
|
|
||||||
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
||||||
|
|
||||||
|
const recordTablePendingRecordId = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
recordTablePendingRecordIdState,
|
||||||
|
);
|
||||||
|
|
||||||
if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) {
|
if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) {
|
||||||
createOneRecord({
|
createOneRecord({
|
||||||
id: recordTablePendingRecordId,
|
id: recordTablePendingRecordId,
|
||||||
@ -77,8 +56,8 @@ export const useUpsertRecord = ({
|
|||||||
persistField();
|
persistField();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[createOneRecord, objectNameSingular, recordTablePendingRecordIdState],
|
[createOneRecord, objectMetadataItem, recordTablePendingRecordIdState],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { upsertRecord };
|
return { upsertTableRecordNoGroup };
|
||||||
};
|
};
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useSelectedTableCellEditMode } from '@/object-record/record-table/record-table-cell/hooks/useSelectedTableCellEditMode';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
export const useCreateNewTableRecordInGroup = () => {
|
||||||
|
const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const { setSelectedTableCellEditMode } = useSelectedTableCellEditMode({
|
||||||
|
scopeId: recordIndexId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
|
const recordTablePendingRecordIdByGroupFamilyState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
recordIndexId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||||
|
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||||
|
|
||||||
|
const createNewTableRecordInGroup = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(recordGroupId: string) => {
|
||||||
|
const recordId = v4();
|
||||||
|
|
||||||
|
set(
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState(recordGroupId),
|
||||||
|
recordId,
|
||||||
|
);
|
||||||
|
setSelectedTableCellEditMode(-1, 0);
|
||||||
|
setHotkeyScope(
|
||||||
|
DEFAULT_CELL_SCOPE.scope,
|
||||||
|
DEFAULT_CELL_SCOPE.customScopes,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDefined(objectMetadataItem.labelIdentifierFieldMetadataId)) {
|
||||||
|
setActiveDropdownFocusIdAndMemorizePrevious(
|
||||||
|
getDropdownFocusIdForRecordField(
|
||||||
|
recordId,
|
||||||
|
objectMetadataItem.labelIdentifierFieldMetadataId,
|
||||||
|
'table-cell',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
objectMetadataItem,
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState,
|
||||||
|
setActiveDropdownFocusIdAndMemorizePrevious,
|
||||||
|
setHotkeyScope,
|
||||||
|
setSelectedTableCellEditMode,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
createNewTableRecordInGroup,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,33 +1,94 @@
|
|||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { useSelectedTableCellEditMode } from '@/object-record/record-table/record-table-cell/hooks/useSelectedTableCellEditMode';
|
import { useSelectedTableCellEditMode } from '@/object-record/record-table/record-table-cell/hooks/useSelectedTableCellEditMode';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||||
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { useContext } from 'react';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useCreateNewTableRecord = (recordTableIdFromProps?: string) => {
|
export const useCreateNewTableRecord = (recordTableId: string) => {
|
||||||
const { recordTableId } = useContext(RecordTableContext);
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const recordTableIdToUse = recordTableIdFromProps ?? recordTableId;
|
|
||||||
|
|
||||||
const { setSelectedTableCellEditMode } = useSelectedTableCellEditMode({
|
const { setSelectedTableCellEditMode } = useSelectedTableCellEditMode({
|
||||||
scopeId: recordTableIdToUse,
|
scopeId: recordTableId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
const { setPendingRecordId } = useRecordTable({
|
const setPendingRecordId = useSetRecoilComponentStateV2(
|
||||||
recordTableId: recordTableIdToUse,
|
recordTablePendingRecordIdComponentState,
|
||||||
});
|
recordTableId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordTablePendingRecordIdByGroupFamilyState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
recordTableId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||||
|
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||||
|
|
||||||
const createNewTableRecord = () => {
|
const createNewTableRecord = () => {
|
||||||
setPendingRecordId(v4());
|
const recordId = v4();
|
||||||
|
|
||||||
|
setPendingRecordId(recordId);
|
||||||
setSelectedTableCellEditMode(-1, 0);
|
setSelectedTableCellEditMode(-1, 0);
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope, DEFAULT_CELL_SCOPE.customScopes);
|
setHotkeyScope(DEFAULT_CELL_SCOPE.scope, DEFAULT_CELL_SCOPE.customScopes);
|
||||||
|
|
||||||
|
if (isDefined(objectMetadataItem.labelIdentifierFieldMetadataId)) {
|
||||||
|
setActiveDropdownFocusIdAndMemorizePrevious(
|
||||||
|
getDropdownFocusIdForRecordField(
|
||||||
|
recordId,
|
||||||
|
objectMetadataItem.labelIdentifierFieldMetadataId,
|
||||||
|
'table-cell',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createNewTableRecordInGroup = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(recordGroupId: string) => {
|
||||||
|
const recordId = v4();
|
||||||
|
|
||||||
|
set(
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState(recordGroupId),
|
||||||
|
recordId,
|
||||||
|
);
|
||||||
|
setSelectedTableCellEditMode(-1, 0);
|
||||||
|
setHotkeyScope(
|
||||||
|
DEFAULT_CELL_SCOPE.scope,
|
||||||
|
DEFAULT_CELL_SCOPE.customScopes,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDefined(objectMetadataItem.labelIdentifierFieldMetadataId)) {
|
||||||
|
setActiveDropdownFocusIdAndMemorizePrevious(
|
||||||
|
getDropdownFocusIdForRecordField(
|
||||||
|
recordId,
|
||||||
|
objectMetadataItem.labelIdentifierFieldMetadataId,
|
||||||
|
'table-cell',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
objectMetadataItem,
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState,
|
||||||
|
setActiveDropdownFocusIdAndMemorizePrevious,
|
||||||
|
setHotkeyScope,
|
||||||
|
setSelectedTableCellEditMode,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createNewTableRecord,
|
createNewTableRecord,
|
||||||
|
createNewTableRecordInGroup,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import { onColumnsChangeComponentState } from '@/object-record/record-table/stat
|
|||||||
import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState';
|
import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState';
|
||||||
import { onToggleColumnFilterComponentState } from '@/object-record/record-table/states/onToggleColumnFilterComponentState';
|
import { onToggleColumnFilterComponentState } from '@/object-record/record-table/states/onToggleColumnFilterComponentState';
|
||||||
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
|
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
|
||||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
|
||||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||||
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
||||||
@ -240,11 +239,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
|||||||
const isSomeCellInEditModeState =
|
const isSomeCellInEditModeState =
|
||||||
useGetIsSomeCellInEditModeState(recordTableId);
|
useGetIsSomeCellInEditModeState(recordTableId);
|
||||||
|
|
||||||
const setPendingRecordId = useSetRecoilComponentStateV2(
|
|
||||||
recordTablePendingRecordIdComponentState,
|
|
||||||
recordTableId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onColumnsChange,
|
onColumnsChange,
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
@ -272,6 +266,5 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
|||||||
setHasUserSelectedAllRows,
|
setHasUserSelectedAllRows,
|
||||||
setOnToggleColumnFilter,
|
setOnToggleColumnFilter,
|
||||||
setOnToggleColumnSort,
|
setOnToggleColumnSort,
|
||||||
setPendingRecordId,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { DragDropContext, DropResult } from '@hello-pangea/dnd';
|
import { DragDropContext, DropResult } from '@hello-pangea/dnd';
|
||||||
import { ReactNode, useContext } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
|
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
@ -18,7 +18,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
|||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { objectNameSingular, recordTableId } = useContext(RecordTableContext);
|
const { objectNameSingular, recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
|
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { DragDropContext, DropResult } from '@hello-pangea/dnd';
|
import { DragDropContext, DropResult } from '@hello-pangea/dnd';
|
||||||
import { ReactNode, useContext } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
@ -7,7 +7,7 @@ import { getDraggedRecordPosition } from '@/object-record/record-board/utils/get
|
|||||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
@ -20,7 +20,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { objectNameSingular, recordTableId, objectMetadataItem } =
|
const { objectNameSingular, recordTableId, objectMetadataItem } =
|
||||||
useContext(RecordTableContext);
|
useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
|
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
@ -9,13 +10,13 @@ import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useLis
|
|||||||
|
|
||||||
type RecordTableBodyUnselectEffectProps = {
|
type RecordTableBodyUnselectEffectProps = {
|
||||||
tableBodyRef: React.RefObject<HTMLDivElement>;
|
tableBodyRef: React.RefObject<HTMLDivElement>;
|
||||||
recordTableId: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableBodyUnselectEffect = ({
|
export const RecordTableBodyUnselectEffect = ({
|
||||||
tableBodyRef,
|
tableBodyRef,
|
||||||
recordTableId,
|
|
||||||
}: RecordTableBodyUnselectEffectProps) => {
|
}: RecordTableBodyUnselectEffectProps) => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const leaveTableFocus = useLeaveTableFocus(recordTableId);
|
const leaveTableFocus = useLeaveTableFocus(recordTableId);
|
||||||
|
|
||||||
const { resetTableRowSelection, useMapKeyboardToSoftFocus } = useRecordTable({
|
const { resetTableRowSelection, useMapKeyboardToSoftFocus } = useRecordTable({
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
|
import { RecordTableNoRecordGroupBodyContextProvider } from '@/object-record/record-table/components/RecordTableNoRecordGroupBodyContextProvider';
|
||||||
import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/components/RecordTableNoRecordGroupRows';
|
import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/components/RecordTableNoRecordGroupRows';
|
||||||
import { RecordTableBodyDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider';
|
import { RecordTableBodyDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider';
|
||||||
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
||||||
@ -21,11 +22,13 @@ export const RecordTableNoRecordGroupBody = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableBodyDragDropContextProvider>
|
<RecordTableNoRecordGroupBodyContextProvider>
|
||||||
<RecordTableBodyDroppable>
|
<RecordTableBodyDragDropContextProvider>
|
||||||
<RecordTablePendingRow />
|
<RecordTableBodyDroppable>
|
||||||
<RecordTableNoRecordGroupRows />
|
<RecordTablePendingRow />
|
||||||
</RecordTableBodyDroppable>
|
<RecordTableNoRecordGroupRows />
|
||||||
</RecordTableBodyDragDropContextProvider>
|
</RecordTableBodyDroppable>
|
||||||
|
</RecordTableBodyDragDropContextProvider>
|
||||||
|
</RecordTableNoRecordGroupBodyContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
|
|||||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||||
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
|
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
|
||||||
import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState';
|
import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState';
|
||||||
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
||||||
@ -18,7 +18,7 @@ import { isNonEmptyString, isNull } from '@sniptt/guards';
|
|||||||
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
||||||
|
|
||||||
export const RecordTableNoRecordGroupBodyEffect = () => {
|
export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||||
const { objectNameSingular } = useContext(RecordTableContext);
|
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
@ -7,13 +7,13 @@ import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useC
|
|||||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||||
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
||||||
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||||
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
||||||
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
||||||
|
|
||||||
export const RecordTableRecordGroupBodyEffect = () => {
|
export const RecordTableRecordGroupBodyEffect = () => {
|
||||||
const { objectNameSingular } = useContext(RecordTableContext);
|
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
||||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
|
import { RecordTableRecordGroupBodyContextProvider } from '@/object-record/record-table/components/RecordTableRecordGroupBodyContextProvider';
|
||||||
import { RecordTableRecordGroupRows } from '@/object-record/record-table/components/RecordTableRecordGroupRows';
|
import { RecordTableRecordGroupRows } from '@/object-record/record-table/components/RecordTableRecordGroupRows';
|
||||||
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
||||||
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
|
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
|
||||||
import { RecordTableBodyRecordGroupDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider';
|
import { RecordTableBodyRecordGroupDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider';
|
||||||
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
|
import { RecordTableRecordGroupEmptyRow } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupEmptyRow';
|
||||||
import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection';
|
import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection';
|
||||||
import { RecordTableRecordGroupSectionLoadMore } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore';
|
|
||||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
@ -30,20 +30,19 @@ export const RecordTableRecordGroupsBody = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableBodyRecordGroupDragDropContextProvider>
|
<RecordTableBodyRecordGroupDragDropContextProvider>
|
||||||
<RecordTableBodyDroppable isDropDisabled>
|
{visibleRecordGroupIds.map((recordGroupId, index) => (
|
||||||
<RecordTablePendingRow />
|
<RecordTableRecordGroupBodyContextProvider
|
||||||
</RecordTableBodyDroppable>
|
|
||||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
|
||||||
<RecordGroupContext.Provider
|
|
||||||
key={recordGroupId}
|
key={recordGroupId}
|
||||||
value={{ recordGroupId }}
|
recordGroupId={recordGroupId}
|
||||||
>
|
>
|
||||||
<RecordTableBodyDroppable recordGroupId={recordGroupId}>
|
{index > 0 && <RecordTableRecordGroupEmptyRow />}
|
||||||
<RecordTableRecordGroupSection />
|
<RecordGroupContext.Provider value={{ recordGroupId }}>
|
||||||
<RecordTableRecordGroupRows />
|
<RecordTableBodyDroppable recordGroupId={recordGroupId}>
|
||||||
<RecordTableRecordGroupSectionLoadMore />
|
<RecordTableRecordGroupSection />
|
||||||
</RecordTableBodyDroppable>
|
<RecordTableRecordGroupRows />
|
||||||
</RecordGroupContext.Provider>
|
</RecordTableBodyDroppable>
|
||||||
|
</RecordGroupContext.Provider>
|
||||||
|
</RecordTableRecordGroupBodyContextProvider>
|
||||||
))}
|
))}
|
||||||
</RecordTableBodyRecordGroupDragDropContextProvider>
|
</RecordTableBodyRecordGroupDragDropContextProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import { BORDER_COMMON, ThemeContext } from 'twenty-ui';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
|
import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
|
||||||
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
||||||
|
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_CELL_SCOPE,
|
DEFAULT_CELL_SCOPE,
|
||||||
useOpenRecordTableCellFromCell,
|
useOpenRecordTableCellFromCell,
|
||||||
@ -47,7 +47,7 @@ export const RecordTableCellBaseContainer = ({
|
|||||||
const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext);
|
const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext);
|
||||||
|
|
||||||
const { onMoveSoftFocusToCell, onCellMouseEnter } =
|
const { onMoveSoftFocusToCell, onCellMouseEnter } =
|
||||||
useContext(RecordTableContext);
|
useRecordTableBodyContextOrThrow();
|
||||||
|
|
||||||
const handleContainerMouseMove = () => {
|
const handleContainerMouseMove = () => {
|
||||||
setIsFocused(true);
|
setIsFocused(true);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
||||||
|
|
||||||
@ -7,9 +7,10 @@ export const RecordTableCellDisplayMode = ({
|
|||||||
children,
|
children,
|
||||||
softFocus,
|
softFocus,
|
||||||
}: React.PropsWithChildren<{ softFocus?: boolean }>) => {
|
}: React.PropsWithChildren<{ softFocus?: boolean }>) => {
|
||||||
const { onActionMenuDropdownOpened } = useContext(RecordTableContext);
|
|
||||||
const { recordId } = useContext(FieldContext);
|
const { recordId } = useContext(FieldContext);
|
||||||
|
|
||||||
|
const { onActionMenuDropdownOpened } = useRecordTableBodyContextOrThrow();
|
||||||
|
|
||||||
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
||||||
onActionMenuDropdownOpened(event, recordId);
|
onActionMenuDropdownOpened(event, recordId);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { isFieldRelation } from '@/object-record/record-field/types/guards/isFie
|
|||||||
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
|
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
|
||||||
import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext';
|
import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
@ -18,8 +18,10 @@ export const RecordTableCellFieldContextWrapper = ({
|
|||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { columnDefinition } = useContext(RecordTableCellContext);
|
const { columnDefinition } = useContext(RecordTableCellContext);
|
||||||
|
|
||||||
const { recordId, pathToShowPage } = useContext(RecordTableRowContext);
|
const { recordId, pathToShowPage } = useContext(RecordTableRowContext);
|
||||||
|
|
||||||
const updateRecord = useContext(RecordUpdateContext);
|
const updateRecord = useContext(RecordUpdateContext);
|
||||||
|
|||||||
@ -4,17 +4,18 @@ import { FieldInput } from '@/object-record/record-field/components/FieldInput';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
export const RecordTableCellFieldInput = () => {
|
export const RecordTableCellFieldInput = () => {
|
||||||
const { onUpsertRecord, onMoveFocus, onCloseTableCell } =
|
|
||||||
useContext(RecordTableContext);
|
|
||||||
|
|
||||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
|
const { onUpsertRecord, onMoveFocus, onCloseTableCell } =
|
||||||
|
useRecordTableBodyContextOrThrow();
|
||||||
|
|
||||||
const isFieldReadOnly = useIsFieldValueReadOnly();
|
const isFieldReadOnly = useIsFieldValueReadOnly();
|
||||||
|
|
||||||
const handleEnter: FieldInputEvent = (persistField) => {
|
const handleEnter: FieldInputEvent = (persistField) => {
|
||||||
|
|||||||
@ -3,19 +3,25 @@ import { useContext } from 'react';
|
|||||||
|
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
import { IconListViewGrip } from 'twenty-ui';
|
import { IconListViewGrip } from 'twenty-ui';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div<{ isPendingRow?: boolean }>`
|
||||||
cursor: grab;
|
|
||||||
width: 16px;
|
|
||||||
height: 32px;
|
|
||||||
z-index: 200;
|
|
||||||
display: flex;
|
|
||||||
&:hover .icon {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
|
cursor: grab;
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
width: 16px;
|
||||||
|
${({ isPendingRow }) =>
|
||||||
|
!isPendingRow
|
||||||
|
? css`
|
||||||
|
&:hover .icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
: ''};
|
||||||
|
|
||||||
|
z-index: 200;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIconWrapper = styled.div<{ isDragging: boolean }>`
|
const StyledIconWrapper = styled.div<{ isDragging: boolean }>`
|
||||||
@ -24,7 +30,9 @@ const StyledIconWrapper = styled.div<{ isDragging: boolean }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordTableCellGrip = () => {
|
export const RecordTableCellGrip = () => {
|
||||||
const { dragHandleProps, isDragging } = useContext(RecordTableRowContext);
|
const { dragHandleProps, isDragging, isPendingRow } = useContext(
|
||||||
|
RecordTableRowContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableTd
|
<RecordTableTd
|
||||||
@ -34,7 +42,7 @@ export const RecordTableCellGrip = () => {
|
|||||||
hasRightBorder={false}
|
hasRightBorder={false}
|
||||||
hasBottomBorder={false}
|
hasBottomBorder={false}
|
||||||
>
|
>
|
||||||
<StyledContainer>
|
<StyledContainer isPendingRow={isPendingRow}>
|
||||||
<StyledIconWrapper className="icon" isDragging={isDragging}>
|
<StyledIconWrapper className="icon" isDragging={isDragging}>
|
||||||
<IconListViewGrip />
|
<IconListViewGrip />
|
||||||
</StyledIconWrapper>
|
</StyledIconWrapper>
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
|||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
||||||
|
|
||||||
type RecordTableCellSoftFocusModeProps = {
|
type RecordTableCellSoftFocusModeProps = {
|
||||||
@ -36,6 +36,8 @@ export const RecordTableCellSoftFocusMode = ({
|
|||||||
const { columnIndex } = useContext(RecordTableCellContext);
|
const { columnIndex } = useContext(RecordTableCellContext);
|
||||||
const { recordId } = useContext(FieldContext);
|
const { recordId } = useContext(FieldContext);
|
||||||
|
|
||||||
|
const { onActionMenuDropdownOpened } = useRecordTableBodyContextOrThrow();
|
||||||
|
|
||||||
const isFieldReadOnly = useIsFieldValueReadOnly();
|
const isFieldReadOnly = useIsFieldValueReadOnly();
|
||||||
|
|
||||||
const { openTableCell } = useOpenRecordTableCellFromCell();
|
const { openTableCell } = useOpenRecordTableCellFromCell();
|
||||||
@ -135,8 +137,6 @@ export const RecordTableCellSoftFocusMode = ({
|
|||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
const { onActionMenuDropdownOpened } = useContext(RecordTableContext);
|
|
||||||
|
|
||||||
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
||||||
onActionMenuDropdownOpened(event, recordId);
|
onActionMenuDropdownOpened(event, recordId);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,101 @@
|
|||||||
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
|
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
|
import {
|
||||||
|
recordTableCell,
|
||||||
|
recordTableRow,
|
||||||
|
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||||
|
import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup';
|
||||||
|
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
||||||
|
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
||||||
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
|
const setHotkeyScope = jest.fn();
|
||||||
|
|
||||||
|
jest.mock('@/ui/utilities/hotkey/hooks/useSetHotkeyScope', () => ({
|
||||||
|
useSetHotkeyScope: () => setHotkeyScope,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const onColumnsChange = jest.fn();
|
||||||
|
const recordTableId = 'scopeId';
|
||||||
|
const recordGroupId = 'recordGroupId';
|
||||||
|
|
||||||
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={(snapshot) => {
|
||||||
|
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecordTableComponentInstance
|
||||||
|
recordTableId={recordTableId}
|
||||||
|
onColumnsChange={onColumnsChange}
|
||||||
|
>
|
||||||
|
<RecordTableContextProvider
|
||||||
|
recordTableId={recordTableId}
|
||||||
|
viewBarId="viewBarId"
|
||||||
|
objectNameSingular={CoreObjectNameSingular.Person}
|
||||||
|
>
|
||||||
|
<FieldContext.Provider
|
||||||
|
value={{
|
||||||
|
fieldDefinition: textfieldDefinition,
|
||||||
|
recordId: 'recordId',
|
||||||
|
hotkeyScope: TableHotkeyScope.Table,
|
||||||
|
isLabelIdentifier: false,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||||
|
<RecordTableCellContext.Provider
|
||||||
|
value={{ ...recordTableCell, columnIndex: 0 }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RecordTableCellContext.Provider>
|
||||||
|
</RecordTableRowContext.Provider>
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
|
</RecordTableComponentInstance>
|
||||||
|
</RecoilRoot>
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('useCloseRecordTableCellInGroup', () => {
|
||||||
|
it('should work as expected', async () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() => {
|
||||||
|
const currentTableCellInEditModePosition = useRecoilComponentValueV2(
|
||||||
|
currentTableCellInEditModePositionComponentState,
|
||||||
|
);
|
||||||
|
const isTableCellInEditMode = useRecoilComponentFamilyValueV2(
|
||||||
|
isTableCellInEditModeComponentFamilyState,
|
||||||
|
currentTableCellInEditModePosition,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...useCloseRecordTableCellInGroup(recordGroupId),
|
||||||
|
...useDragSelect(),
|
||||||
|
isTableCellInEditMode,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapper: Wrapper,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
result.current.closeTableCellInGroup();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
|
||||||
|
expect(result.current.isTableCellInEditMode).toBe(false);
|
||||||
|
expect(setHotkeyScope).toHaveBeenCalledWith('table-soft-focus');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,22 +1,26 @@
|
|||||||
import { act, renderHook } from '@testing-library/react';
|
import { act, renderHook } from '@testing-library/react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import {
|
import {
|
||||||
recordTableCell,
|
recordTableCell,
|
||||||
recordTableRow,
|
recordTableRow,
|
||||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||||
import { useCloseRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCell';
|
import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup';
|
||||||
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
||||||
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
const setHotkeyScope = jest.fn();
|
const setHotkeyScope = jest.fn();
|
||||||
|
|
||||||
@ -28,32 +32,42 @@ const onColumnsChange = jest.fn();
|
|||||||
const recordTableId = 'scopeId';
|
const recordTableId = 'scopeId';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot
|
||||||
|
initializeState={(snapshot) => {
|
||||||
|
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<RecordTableComponentInstance
|
<RecordTableComponentInstance
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
onColumnsChange={onColumnsChange}
|
onColumnsChange={onColumnsChange}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<RecordTableContextProvider
|
||||||
value={{
|
recordTableId={recordTableId}
|
||||||
fieldDefinition: textfieldDefinition,
|
viewBarId="viewBarId"
|
||||||
recordId: 'recordId',
|
objectNameSingular={CoreObjectNameSingular.Person}
|
||||||
hotkeyScope: TableHotkeyScope.Table,
|
|
||||||
isLabelIdentifier: false,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
<FieldContext.Provider
|
||||||
<RecordTableCellContext.Provider
|
value={{
|
||||||
value={{ ...recordTableCell, columnIndex: 0 }}
|
fieldDefinition: textfieldDefinition,
|
||||||
>
|
recordId: 'recordId',
|
||||||
{children}
|
hotkeyScope: TableHotkeyScope.Table,
|
||||||
</RecordTableCellContext.Provider>
|
isLabelIdentifier: false,
|
||||||
</RecordTableRowContext.Provider>
|
}}
|
||||||
</FieldContext.Provider>
|
>
|
||||||
|
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||||
|
<RecordTableCellContext.Provider
|
||||||
|
value={{ ...recordTableCell, columnIndex: 0 }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RecordTableCellContext.Provider>
|
||||||
|
</RecordTableRowContext.Provider>
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
</RecordTableComponentInstance>
|
</RecordTableComponentInstance>
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('useCloseRecordTableCell', () => {
|
describe('useCloseRecordTableCellNoGroup', () => {
|
||||||
it('should work as expected', async () => {
|
it('should work as expected', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
@ -65,7 +79,7 @@ describe('useCloseRecordTableCell', () => {
|
|||||||
currentTableCellInEditModePosition,
|
currentTableCellInEditModePosition,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
...useCloseRecordTableCell(),
|
...useCloseRecordTableCellNoGroup(),
|
||||||
...useDragSelect(),
|
...useDragSelect(),
|
||||||
isTableCellInEditMode,
|
isTableCellInEditMode,
|
||||||
};
|
};
|
||||||
@ -76,7 +90,7 @@ describe('useCloseRecordTableCell', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.closeTableCell();
|
result.current.closeTableCellNoGroup();
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
|
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
|
||||||
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
|
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { useCloseCurrentTableCellInEditMode } from '@/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
|
||||||
|
export const useCloseRecordTableCellInGroup = (recordGroupId: string) => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||||
|
|
||||||
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
|
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
const closeCurrentTableCellInEditMode =
|
||||||
|
useCloseCurrentTableCellInEditMode(recordTableId);
|
||||||
|
|
||||||
|
const recordTablePendingRecordIdByGroupFamilyState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
recordTableId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const closeTableCellInGroup = useRecoilCallback(
|
||||||
|
({ reset }) =>
|
||||||
|
() => {
|
||||||
|
toggleClickOutsideListener(true);
|
||||||
|
setDragSelectionStartEnabled(true);
|
||||||
|
closeCurrentTableCellInEditMode();
|
||||||
|
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||||
|
|
||||||
|
reset(recordTablePendingRecordIdByGroupFamilyState(recordGroupId));
|
||||||
|
},
|
||||||
|
[
|
||||||
|
closeCurrentTableCellInEditMode,
|
||||||
|
recordGroupId,
|
||||||
|
recordTablePendingRecordIdByGroupFamilyState,
|
||||||
|
setDragSelectionStartEnabled,
|
||||||
|
setHotkeyScope,
|
||||||
|
toggleClickOutsideListener,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
closeTableCellInGroup,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -5,13 +5,18 @@ import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
|||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
|
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { useCloseCurrentTableCellInEditMode } from '@/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||||
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
import { useCallback } from 'react';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
|
||||||
|
export const useCloseRecordTableCellNoGroup = () => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
export const useCloseRecordTableCellV2 = (recordTableId: string) => {
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||||
|
|
||||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
@ -25,18 +30,25 @@ export const useCloseRecordTableCellV2 = (recordTableId: string) => {
|
|||||||
recordTablePendingRecordIdComponentState,
|
recordTablePendingRecordIdComponentState,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetRecordTablePendingRecordId =
|
const resetRecordTablePendingRecordId =
|
||||||
useResetRecoilState(pendingRecordIdState);
|
useResetRecoilState(pendingRecordIdState);
|
||||||
|
|
||||||
const closeTableCell = async () => {
|
const closeTableCellNoGroup = useCallback(() => {
|
||||||
toggleClickOutsideListener(true);
|
toggleClickOutsideListener(true);
|
||||||
setDragSelectionStartEnabled(true);
|
setDragSelectionStartEnabled(true);
|
||||||
closeCurrentTableCellInEditMode();
|
closeCurrentTableCellInEditMode();
|
||||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||||
resetRecordTablePendingRecordId();
|
resetRecordTablePendingRecordId();
|
||||||
};
|
}, [
|
||||||
|
closeCurrentTableCellInEditMode,
|
||||||
|
resetRecordTablePendingRecordId,
|
||||||
|
setDragSelectionStartEnabled,
|
||||||
|
setHotkeyScope,
|
||||||
|
toggleClickOutsideListener,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
closeTableCell,
|
closeTableCellNoGroup,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
|
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
|
||||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
|
||||||
|
|
||||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
|
||||||
import { useResetRecoilState } from 'recoil';
|
|
||||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
|
||||||
|
|
||||||
export const useCloseRecordTableCell = () => {
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
|
||||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
|
||||||
|
|
||||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
|
||||||
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
|
|
||||||
const pendingRecordIdState = useRecoilComponentCallbackStateV2(
|
|
||||||
recordTablePendingRecordIdComponentState,
|
|
||||||
);
|
|
||||||
const resetRecordTablePendingRecordId =
|
|
||||||
useResetRecoilState(pendingRecordIdState);
|
|
||||||
|
|
||||||
const closeTableCell = async () => {
|
|
||||||
toggleClickOutsideListener(true);
|
|
||||||
setDragSelectionStartEnabled(true);
|
|
||||||
closeCurrentTableCellInEditMode();
|
|
||||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
|
||||||
resetRecordTablePendingRecordId();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
closeTableCell,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -5,12 +5,12 @@ import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useI
|
|||||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
|
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
|
||||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
|
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||||
@ -28,13 +28,16 @@ export type OpenTableCellArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useOpenRecordTableCellFromCell = () => {
|
export const useOpenRecordTableCellFromCell = () => {
|
||||||
const { onOpenTableCell } = useContext(RecordTableContext);
|
|
||||||
const cellPosition = useCurrentTableCellPosition();
|
|
||||||
const customCellHotkeyScope = useContext(CellHotkeyScopeContext);
|
const customCellHotkeyScope = useContext(CellHotkeyScopeContext);
|
||||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
const { pathToShowPage, objectNameSingular } = useContext(
|
const { pathToShowPage, objectNameSingular } = useContext(
|
||||||
RecordTableRowContext,
|
RecordTableRowContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { onOpenTableCell } = useRecordTableBodyContextOrThrow();
|
||||||
|
|
||||||
|
const cellPosition = useCurrentTableCellPosition();
|
||||||
|
|
||||||
const isFieldReadOnly = useIsFieldValueReadOnly();
|
const isFieldReadOnly = useIsFieldValueReadOnly();
|
||||||
|
|
||||||
const openTableCell = (
|
const openTableCell = (
|
||||||
|
|||||||
@ -20,12 +20,11 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC
|
|||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||||
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
|||||||
const { getClickOutsideListenerIsActivatedState } =
|
const { getClickOutsideListenerIsActivatedState } =
|
||||||
useClickOustideListenerStates(RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID);
|
useClickOustideListenerStates(RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID);
|
||||||
|
|
||||||
const { indexIdentifierUrl } = useContext(RecordIndexRootPropsContext);
|
const { indexIdentifierUrl } = useRecordIndexContextOrThrow();
|
||||||
const moveEditModeToTableCellPosition =
|
const moveEditModeToTableCellPosition =
|
||||||
useMoveEditModeToTableCellPosition(tableScopeId);
|
useMoveEditModeToTableCellPosition(tableScopeId);
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableHeaderCell } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCell';
|
import { RecordTableHeaderCell } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCell';
|
||||||
import { RecordTableHeaderCheckboxColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn';
|
import { RecordTableHeaderCheckboxColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn';
|
||||||
import { RecordTableHeaderDragDropColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn';
|
import { RecordTableHeaderDragDropColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn';
|
||||||
import { RecordTableHeaderLastColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn';
|
import { RecordTableHeaderLastColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
|
|
||||||
const StyledTableHead = styled.thead`
|
const StyledTableHead = styled.thead`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -77,14 +76,8 @@ const StyledTableHead = styled.thead`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordTableHeader = ({
|
export const RecordTableHeader = () => {
|
||||||
objectNameSingular,
|
const { visibleTableColumns } = useRecordTableContextOrThrow();
|
||||||
}: {
|
|
||||||
objectNameSingular: string;
|
|
||||||
}) => {
|
|
||||||
const visibleTableColumns = useRecoilComponentValueV2(
|
|
||||||
visibleTableColumnsComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTableHead id="record-table-header" data-select-disable>
|
<StyledTableHead id="record-table-header" data-select-disable>
|
||||||
@ -92,11 +85,7 @@ export const RecordTableHeader = ({
|
|||||||
<RecordTableHeaderDragDropColumn />
|
<RecordTableHeaderDragDropColumn />
|
||||||
<RecordTableHeaderCheckboxColumn />
|
<RecordTableHeaderCheckboxColumn />
|
||||||
{visibleTableColumns.map((column) => (
|
{visibleTableColumns.map((column) => (
|
||||||
<RecordTableHeaderCell
|
<RecordTableHeaderCell key={column.fieldMetadataId} column={column} />
|
||||||
key={column.fieldMetadataId}
|
|
||||||
column={column}
|
|
||||||
objectNameSingular={objectNameSingular}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
<RecordTableHeaderLastColumn />
|
<RecordTableHeaderLastColumn />
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import { useCallback, useMemo, useState } from 'react';
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { IconPlus, LightIconButton } from 'twenty-ui';
|
import { IconPlus, LightIconButton } from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||||
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
||||||
import { RecordTableColumnHeadWithDropdown } from '@/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown';
|
import { RecordTableColumnHeadWithDropdown } from '@/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown';
|
||||||
@ -95,16 +95,14 @@ const StyledHeaderIcon = styled.div`
|
|||||||
margin: ${({ theme }) => theme.spacing(1, 1, 1, 1.5)};
|
margin: ${({ theme }) => theme.spacing(1, 1, 1, 1.5)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
type RecordTableHeaderCellProps = {
|
||||||
|
column: ColumnDefinition<FieldMetadata>;
|
||||||
|
};
|
||||||
|
|
||||||
export const RecordTableHeaderCell = ({
|
export const RecordTableHeaderCell = ({
|
||||||
column,
|
column,
|
||||||
objectNameSingular,
|
}: RecordTableHeaderCellProps) => {
|
||||||
}: {
|
const { recordTableId, objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
column: ColumnDefinition<FieldMetadata>;
|
|
||||||
objectNameSingular: string;
|
|
||||||
}) => {
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const resizeFieldOffsetState = useRecoilComponentCallbackStateV2(
|
const resizeFieldOffsetState = useRecoilComponentCallbackStateV2(
|
||||||
resizeFieldOffsetComponentState,
|
resizeFieldOffsetComponentState,
|
||||||
@ -199,7 +197,7 @@ export const RecordTableHeaderCell = ({
|
|||||||
const disableColumnResize =
|
const disableColumnResize =
|
||||||
column.isLabelIdentifier && isMobile && !isRecordTableScrolledLeft;
|
column.isLabelIdentifier && isMobile && !isRecordTableScrolledLeft;
|
||||||
|
|
||||||
const { createNewTableRecord } = useCreateNewTableRecord();
|
const { createNewTableRecord } = useCreateNewTableRecord(recordTableId);
|
||||||
|
|
||||||
const handlePlusButtonClick = () => {
|
const handlePlusButtonClick = () => {
|
||||||
createNewTableRecord();
|
createNewTableRecord();
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { useCallback, useContext } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { IconSettings, MenuItem, UndecoratedLink, useIcons } from 'twenty-ui';
|
import { IconSettings, MenuItem, UndecoratedLink, useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
@ -16,7 +16,8 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMe
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
export const RecordTableHeaderPlusButtonContent = () => {
|
export const RecordTableHeaderPlusButtonContent = () => {
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown();
|
const { closeDropdown } = useDropdown();
|
||||||
|
|
||||||
const hiddenTableColumns = useRecoilComponentValueV2(
|
const hiddenTableColumns = useRecoilComponentValueV2(
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||||
|
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
|
|
||||||
|
export const RecordTablePendingRecordGroupRow = () => {
|
||||||
|
const currentRecordGroupId = useCurrentRecordGroupId();
|
||||||
|
|
||||||
|
const pendingRecordId = useRecoilComponentFamilyValueV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
currentRecordGroupId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!pendingRecordId) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableRow
|
||||||
|
key={pendingRecordId}
|
||||||
|
recordId={pendingRecordId}
|
||||||
|
rowIndexForDrag={-1}
|
||||||
|
rowIndexForFocus={-1}
|
||||||
|
isPendingRow
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -4,8 +4,8 @@ import { ReactNode, useContext, useEffect, useRef } from 'react';
|
|||||||
import { useInView } from 'react-intersection-observer';
|
import { useInView } from 'react-intersection-observer';
|
||||||
|
|
||||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
||||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||||
@ -31,8 +31,8 @@ export const RecordTableRowWrapper = ({
|
|||||||
}: RecordTableRowWrapperProps) => {
|
}: RecordTableRowWrapperProps) => {
|
||||||
const trRef = useRef<HTMLTableRowElement>(null);
|
const trRef = useRef<HTMLTableRowElement>(null);
|
||||||
|
|
||||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
const { onIndexRecordsLoaded } = useContext(RecordIndexRootPropsContext);
|
const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -78,7 +78,12 @@ export const RecordTableRowWrapper = ({
|
|||||||
}, [inView, onIndexRecordsLoaded]);
|
}, [inView, onIndexRecordsLoaded]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable key={recordId} draggableId={recordId} index={rowIndexForDrag}>
|
<Draggable
|
||||||
|
key={recordId}
|
||||||
|
draggableId={recordId}
|
||||||
|
index={rowIndexForDrag}
|
||||||
|
isDragDisabled={isPendingRow}
|
||||||
|
>
|
||||||
{(draggableProvided, draggableSnapshot) => (
|
{(draggableProvided, draggableSnapshot) => (
|
||||||
<RecordTableTr
|
<RecordTableTr
|
||||||
ref={(node) => {
|
ref={(node) => {
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledTrContainer = styled.tr`
|
||||||
|
height: 32px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RecordTableRecordGroupEmptyRow = StyledTrContainer;
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||||
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||||
|
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
||||||
|
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||||
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
|
import { IconPlus } from 'twenty-ui';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
export const RecordTableRecordGroupSectionAddNew = () => {
|
||||||
|
const { recordTableId } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
|
const currentRecordGroupId = useCurrentRecordGroupId();
|
||||||
|
|
||||||
|
const pendingRecordId = useRecoilComponentFamilyValueV2(
|
||||||
|
recordTablePendingRecordIdByGroupComponentFamilyState,
|
||||||
|
currentRecordGroupId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { createNewTableRecordInGroup } =
|
||||||
|
useCreateNewTableRecord(recordTableId);
|
||||||
|
|
||||||
|
const handleAddNewRecord = () => {
|
||||||
|
createNewTableRecordInGroup(currentRecordGroupId);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isDefined(pendingRecordId)) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableActionRow
|
||||||
|
LeftIcon={IconPlus}
|
||||||
|
text="Add new"
|
||||||
|
onClick={handleAddNewRecord}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,14 +1,13 @@
|
|||||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||||
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { IconArrowDown } from 'twenty-ui';
|
import { IconArrowDown } from 'twenty-ui';
|
||||||
|
|
||||||
export const RecordTableRecordGroupSectionLoadMore = () => {
|
export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||||
const { objectNameSingular } = useContext(RecordTableContext);
|
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||||
|
|
||||||
const currentRecordGroupId = useCurrentRecordGroupId();
|
const currentRecordGroupId = useCurrentRecordGroupId();
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||||
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
|
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||||
|
|
||||||
|
export const recordTablePendingRecordIdByGroupComponentFamilyState =
|
||||||
|
createComponentFamilyStateV2<string | null, RecordGroupDefinition['id']>({
|
||||||
|
key: 'recordTablePendingRecordIdByGroupComponentFamilyState',
|
||||||
|
defaultValue: null,
|
||||||
|
componentInstanceContext: RecordTableComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -4,7 +4,7 @@ import { createComponentStateV2 } from '@/ui/utilities/state/component-state/uti
|
|||||||
export const recordTablePendingRecordIdComponentState = createComponentStateV2<
|
export const recordTablePendingRecordIdComponentState = createComponentStateV2<
|
||||||
string | null
|
string | null
|
||||||
>({
|
>({
|
||||||
key: 'recordTablePendingRecordIdState',
|
key: 'recordTablePendingRecordIdComponentState',
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
componentInstanceContext: RecordTableComponentInstanceContext,
|
componentInstanceContext: RecordTableComponentInstanceContext,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||||
import { ViewBar } from '@/views/components/ViewBar';
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
@ -28,7 +28,7 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<RecordIndexRootPropsContext.Provider
|
<RecordIndexContextProvider
|
||||||
value={{
|
value={{
|
||||||
recordIndexId,
|
recordIndexId,
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
@ -36,7 +36,6 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
onIndexRecordsLoaded: () => {},
|
onIndexRecordsLoaded: () => {},
|
||||||
indexIdentifierUrl: () => '',
|
indexIdentifierUrl: () => '',
|
||||||
onCreateRecord: () => {},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<ViewComponentInstanceContext.Provider
|
||||||
@ -69,7 +68,7 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
</ActionMenuComponentInstanceContext.Provider>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
</ViewComponentInstanceContext.Provider>
|
</ViewComponentInstanceContext.Provider>
|
||||||
</RecordIndexRootPropsContext.Provider>
|
</RecordIndexContextProvider>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
||||||
@ -18,7 +18,6 @@ import { GraphQLView } from '@/views/types/GraphQLView';
|
|||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
@ -57,7 +56,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
|||||||
|
|
||||||
const { createViewFilterGroupRecords } = usePersistViewFilterGroupRecords();
|
const { createViewFilterGroupRecords } = usePersistViewFilterGroupRecords();
|
||||||
|
|
||||||
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const createViewFromCurrentView = useRecoilCallback(
|
const createViewFromCurrentView = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
|
|||||||
@ -12,9 +12,8 @@ import { RecordIndexContainer } from '@/object-record/record-index/components/Re
|
|||||||
import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect';
|
import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect';
|
||||||
import { RecordIndexContainerContextStoreObjectMetadataEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect';
|
import { RecordIndexContainerContextStoreObjectMetadataEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect';
|
||||||
import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader';
|
import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader';
|
||||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||||
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
|
||||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||||
@ -41,12 +40,6 @@ export const RecordIndexPage = () => {
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { createNewTableRecord } = useCreateNewTableRecord(recordIndexId);
|
|
||||||
|
|
||||||
const handleCreateRecord = () => {
|
|
||||||
createNewTableRecord();
|
|
||||||
};
|
|
||||||
|
|
||||||
const { indexIdentifierUrl } = useHandleIndexIdentifierClick({
|
const { indexIdentifierUrl } = useHandleIndexIdentifierClick({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
recordIndexId,
|
recordIndexId,
|
||||||
@ -63,7 +56,7 @@ export const RecordIndexPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<RecordIndexRootPropsContext.Provider
|
<RecordIndexContextProvider
|
||||||
value={{
|
value={{
|
||||||
recordIndexId,
|
recordIndexId,
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
@ -71,7 +64,6 @@ export const RecordIndexPage = () => {
|
|||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
onIndexRecordsLoaded: handleIndexRecordsLoaded,
|
onIndexRecordsLoaded: handleIndexRecordsLoaded,
|
||||||
indexIdentifierUrl,
|
indexIdentifierUrl,
|
||||||
onCreateRecord: handleCreateRecord,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<ViewComponentInstanceContext.Provider
|
||||||
@ -100,7 +92,7 @@ export const RecordIndexPage = () => {
|
|||||||
</ActionMenuComponentInstanceContext.Provider>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
</ViewComponentInstanceContext.Provider>
|
</ViewComponentInstanceContext.Provider>
|
||||||
</RecordIndexRootPropsContext.Provider>
|
</RecordIndexContextProvider>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,8 @@ import { Decorator } from '@storybook/react';
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
export const RecordTableDecorator: Decorator = (Story) => {
|
export const RecordTableDecorator: Decorator = (Story) => {
|
||||||
@ -17,23 +18,28 @@ export const RecordTableDecorator: Decorator = (Story) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableContext.Provider
|
<RecordTableContextProvider
|
||||||
value={{
|
value={{
|
||||||
objectNameSingular: personObjectMetadataItem?.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
objectMetadataItem: personObjectMetadataItem,
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
onCellMouseEnter: () => {},
|
|
||||||
onCloseTableCell: () => {},
|
|
||||||
onOpenTableCell: () => {},
|
|
||||||
onActionMenuDropdownOpened: () => {},
|
|
||||||
onMoveFocus: () => {},
|
|
||||||
onMoveSoftFocusToCell: () => {},
|
|
||||||
onUpsertRecord: () => {},
|
|
||||||
recordTableId: 'persons',
|
recordTableId: 'persons',
|
||||||
viewBarId: 'view-bar',
|
viewBarId: 'view-bar',
|
||||||
visibleTableColumns: [],
|
visibleTableColumns: [],
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Story />
|
<RecordTableBodyContextProvider
|
||||||
</RecordTableContext.Provider>
|
value={{
|
||||||
|
onCellMouseEnter: () => {},
|
||||||
|
onCloseTableCell: () => {},
|
||||||
|
onOpenTableCell: () => {},
|
||||||
|
onActionMenuDropdownOpened: () => {},
|
||||||
|
onMoveFocus: () => {},
|
||||||
|
onMoveSoftFocusToCell: () => {},
|
||||||
|
onUpsertRecord: () => {},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</RecordTableBodyContextProvider>
|
||||||
|
</RecordTableContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
20
packages/twenty-front/src/utils/createRequiredContext.ts
Normal file
20
packages/twenty-front/src/utils/createRequiredContext.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
|
||||||
|
export const createRequiredContext = <TContext>(debugName: string) => {
|
||||||
|
const Context = React.createContext<TContext | undefined>(undefined);
|
||||||
|
Context.displayName = `${debugName}Provider`;
|
||||||
|
|
||||||
|
const useRequiredContextOrThrow = (): TContext => {
|
||||||
|
const context = useContext(Context);
|
||||||
|
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`${debugName} Context not found. Please wrap your component tree with <${Context.displayName}> before using use${debugName}OrThrow().`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
return [Context.Provider, useRequiredContextOrThrow] as const;
|
||||||
|
};
|
||||||
@ -1,11 +0,0 @@
|
|||||||
import { Context, createContext } from 'react';
|
|
||||||
|
|
||||||
type RootProps = Record<string, any>;
|
|
||||||
|
|
||||||
export type RootPropsContext<T extends RootProps> = T extends RootProps
|
|
||||||
? T
|
|
||||||
: never;
|
|
||||||
|
|
||||||
export const createRootPropsContext = <T extends RootProps>(): Context<
|
|
||||||
RootPropsContext<T>
|
|
||||||
> => createContext<RootPropsContext<T>>({} as RootPropsContext<T>);
|
|
||||||
Reference in New Issue
Block a user