Refacto views (#10272)
In this huge (sorry!) PR: - introducing objectMetadataItem in contextStore instead of objectMetadataId which is more convenient - splitting some big hooks into smaller parts to avoid re-renders - removing Effects to avoid re-renders (especially onViewChange) - making the view prefetch separate from favorites to avoid re-renders - making the view prefetch load a state and add selectors on top of it to avoir re-renders As a result, the performance is WAY better (I suspect the favorite implementation to trigger a lot of re-renders unfortunately). However, we are still facing a random app freeze on view creation. I could not investigate the root cause. As this seems to be already there in the precedent release, we can move forward but this seems a urgent follow up to me ==> EDIT: I've found the root cause after a few ours of deep dive... an infinite loop in RecordTableNoRecordGroupBodyEffect... prastoin edit: close https://github.com/twentyhq/twenty/issues/10253 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
@ -2,25 +2,17 @@ import { RegisterRecordActionEffect } from '@/action-menu/actions/record-actions
|
|||||||
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
|
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
|
||||||
import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig';
|
import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig';
|
||||||
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordActionMenuEntriesSetter = () => {
|
export const RecordActionMenuEntriesSetter = () => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
|
||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
|
||||||
(item) => item.id === contextStoreCurrentObjectMetadataId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||||
@ -39,10 +31,7 @@ export const RecordActionMenuEntriesSetter = () => {
|
|||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (!isDefined(contextStoreCurrentObjectMetadataItem)) {
|
||||||
!isDefined(contextStoreCurrentObjectMetadataId) ||
|
|
||||||
!isDefined(objectMetadataItem)
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +41,7 @@ export const RecordActionMenuEntriesSetter = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const actionConfig = getActionConfig(
|
const actionConfig = getActionConfig(
|
||||||
objectMetadataItem,
|
contextStoreCurrentObjectMetadataItem,
|
||||||
isCommandMenuV2Enabled,
|
isCommandMenuV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -68,7 +57,7 @@ export const RecordActionMenuEntriesSetter = () => {
|
|||||||
<RegisterRecordActionEffect
|
<RegisterRecordActionEffect
|
||||||
key={action.key}
|
key={action.key}
|
||||||
action={action}
|
action={action}
|
||||||
objectMetadataItem={objectMetadataItem}
|
objectMetadataItem={contextStoreCurrentObjectMetadataItem}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
@ -76,7 +65,7 @@ export const RecordActionMenuEntriesSetter = () => {
|
|||||||
contextStoreTargetedRecordsRule?.mode === 'selection' &&
|
contextStoreTargetedRecordsRule?.mode === 'selection' &&
|
||||||
contextStoreTargetedRecordsRule?.selectedRecordIds.length === 1 && (
|
contextStoreTargetedRecordsRule?.selectedRecordIds.length === 1 && (
|
||||||
<WorkflowRunRecordActionMenuEntrySetterEffect
|
<WorkflowRunRecordActionMenuEntrySetterEffect
|
||||||
objectMetadataItem={objectMetadataItem}
|
objectMetadataItem={contextStoreCurrentObjectMetadataItem}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -8,8 +8,7 @@ import { RecordIndexActionMenuButtons } from '@/action-menu/components/RecordInd
|
|||||||
import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown';
|
import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown';
|
||||||
import { RecordIndexActionMenuEffect } from '@/action-menu/components/RecordIndexActionMenuEffect';
|
import { RecordIndexActionMenuEffect } from '@/action-menu/components/RecordIndexActionMenuEffect';
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState';
|
import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState';
|
||||||
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';
|
||||||
@ -18,8 +17,8 @@ import { useIsMobile } from 'twenty-ui';
|
|||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordIndexActionMenu = ({ indexId }: { indexId: string }) => {
|
export const RecordIndexActionMenu = ({ indexId }: { indexId: string }) => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
@ -39,7 +38,7 @@ export const RecordIndexActionMenu = ({ indexId }: { indexId: string }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextStoreCurrentObjectMetadataId && (
|
{contextStoreCurrentObjectMetadataItem && (
|
||||||
<ActionMenuContext.Provider
|
<ActionMenuContext.Provider
|
||||||
value={{
|
value={{
|
||||||
isInRightDrawer: false,
|
isInRightDrawer: false,
|
||||||
|
|||||||
@ -4,8 +4,7 @@ import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/
|
|||||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||||
import { RecordShowActionMenuButtons } from '@/action-menu/components/RecordShowActionMenuButtons';
|
import { RecordShowActionMenuButtons } from '@/action-menu/components/RecordShowActionMenuButtons';
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -26,8 +25,8 @@ export const RecordShowActionMenu = ({
|
|||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
handleFavoriteButtonClick: () => void;
|
handleFavoriteButtonClick: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
@ -42,7 +41,7 @@ export const RecordShowActionMenu = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextStoreCurrentObjectMetadataId && (
|
{contextStoreCurrentObjectMetadataItem && (
|
||||||
<ActionMenuContext.Provider
|
<ActionMenuContext.Provider
|
||||||
value={{
|
value={{
|
||||||
isInRightDrawer: false,
|
isInRightDrawer: false,
|
||||||
|
|||||||
@ -4,15 +4,14 @@ import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/
|
|||||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||||
import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown';
|
import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown';
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const RecordShowRightDrawerActionMenu = () => {
|
export const RecordShowRightDrawerActionMenu = () => {
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled(
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
@ -21,7 +20,7 @@ export const RecordShowRightDrawerActionMenu = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextStoreCurrentObjectMetadataId && (
|
{contextStoreCurrentObjectMetadataItem && (
|
||||||
<ActionMenuContext.Provider value={{ isInRightDrawer: true }}>
|
<ActionMenuContext.Provider value={{ isInRightDrawer: true }}>
|
||||||
<RightDrawerActionMenuDropdown />
|
<RightDrawerActionMenuDropdown />
|
||||||
<ActionMenuConfirmationModals />
|
<ActionMenuConfirmationModals />
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export const triggerCreateRecordsOptimisticEffect = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
cache.modify<StoreObject>({
|
cache.modify<StoreObject>({
|
||||||
|
broadcast: false,
|
||||||
fields: {
|
fields: {
|
||||||
[objectMetadataItem.namePlural]: (
|
[objectMetadataItem.namePlural]: (
|
||||||
rootQueryCachedResponse,
|
rootQueryCachedResponse,
|
||||||
|
|||||||
@ -59,10 +59,10 @@ export const AppRouterProviders = () => {
|
|||||||
</DialogManager>
|
</DialogManager>
|
||||||
</DialogManagerScope>
|
</DialogManagerScope>
|
||||||
</SnackBarProvider>
|
</SnackBarProvider>
|
||||||
|
<MainContextStoreProvider />
|
||||||
</PrefetchDataProvider>
|
</PrefetchDataProvider>
|
||||||
</ObjectMetadataItemsGater>
|
</ObjectMetadataItemsGater>
|
||||||
<PageChangeEffect />
|
<PageChangeEffect />
|
||||||
<MainContextStoreProvider />
|
|
||||||
</ObjectMetadataItemsProvider>
|
</ObjectMetadataItemsProvider>
|
||||||
</ApolloMetadataClientProvider>
|
</ApolloMetadataClientProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
|||||||
@ -5,12 +5,10 @@ import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContex
|
|||||||
import { useMatchingCommandMenuCommands } from '@/command-menu/hooks/useMatchingCommandMenuCommands';
|
import { useMatchingCommandMenuCommands } from '@/command-menu/hooks/useMatchingCommandMenuCommands';
|
||||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||||
import { Command } from '@/command-menu/types/Command';
|
import { Command } from '@/command-menu/types/Command';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
|
||||||
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
@ -50,23 +48,19 @@ export const CommandMenu = () => {
|
|||||||
)
|
)
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
const previousContextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const previousContextStoreCurrentObjectMetadataItem =
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
useRecoilComponentValueV2(
|
||||||
'command-menu-previous',
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
'command-menu-previous',
|
||||||
|
);
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const currentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
const currentObjectMetadataId = useRecoilComponentValueV2(
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentObjectMetadataItem = objectMetadataItems.find(
|
|
||||||
(objectMetadataItem) => objectMetadataItem.id === currentObjectMetadataId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectableItemIds = selectableItems.map((item) => item.id);
|
const selectableItemIds = selectableItems.map((item) => item.id);
|
||||||
|
|
||||||
if (isNonEmptyString(previousContextStoreCurrentObjectMetadataId)) {
|
if (isDefined(previousContextStoreCurrentObjectMetadataItem)) {
|
||||||
selectableItemIds.unshift(RESET_CONTEXT_TO_SELECTION);
|
selectableItemIds.unshift(RESET_CONTEXT_TO_SELECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +97,7 @@ export const CommandMenu = () => {
|
|||||||
selectableItemIds={selectableItemIds}
|
selectableItemIds={selectableItemIds}
|
||||||
noResults={noResults}
|
noResults={noResults}
|
||||||
>
|
>
|
||||||
{isNonEmptyString(previousContextStoreCurrentObjectMetadataId) && (
|
{isDefined(previousContextStoreCurrentObjectMetadataItem) && (
|
||||||
<CommandGroup heading={t`Context`}>
|
<CommandGroup heading={t`Context`}>
|
||||||
<SelectableItem itemId={RESET_CONTEXT_TO_SELECTION}>
|
<SelectableItem itemId={RESET_CONTEXT_TO_SELECTION}>
|
||||||
<ResetContextToSelectionCommandButton />
|
<ResetContextToSelectionCommandButton />
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe
|
|||||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
@ -96,8 +96,8 @@ export const CommandMenuTopBar = () => {
|
|||||||
|
|
||||||
const { closeCommandMenu, goBackFromCommandMenu } = useCommandMenu();
|
const { closeCommandMenu, goBackFromCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||||
@ -137,11 +137,11 @@ export const CommandMenuTopBar = () => {
|
|||||||
testId="command-menu-go-back-button"
|
testId="command-menu-go-back-button"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isDefined(contextStoreCurrentObjectMetadataId) &&
|
{isDefined(contextStoreCurrentObjectMetadataItem) &&
|
||||||
commandMenuPage !== CommandMenuPages.SearchRecords ? (
|
commandMenuPage !== CommandMenuPages.SearchRecords ? (
|
||||||
<CommandMenuContextChipGroupsWithRecordSelection
|
<CommandMenuContextChipGroupsWithRecordSelection
|
||||||
contextChips={contextChips}
|
contextChips={contextChips}
|
||||||
objectMetadataItemId={contextStoreCurrentObjectMetadataId}
|
objectMetadataItemId={contextStoreCurrentObjectMetadataItem.id}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CommandMenuContextChipGroups contextChips={contextChips} />
|
<CommandMenuContextChipGroups contextChips={contextChips} />
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { CommandMenuContextRecordChip } from '@/command-menu/components/CommandM
|
|||||||
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
|
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
|
||||||
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
||||||
import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
|
import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -17,8 +17,8 @@ export const ResetContextToSelectionCommandButton = () => {
|
|||||||
'command-menu-previous',
|
'command-menu-previous',
|
||||||
);
|
);
|
||||||
|
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
'command-menu-previous',
|
'command-menu-previous',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ export const ResetContextToSelectionCommandButton = () => {
|
|||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
objectMetadataItem.id === contextStoreCurrentObjectMetadataId,
|
objectMetadataItem.id === contextStoreCurrentObjectMetadataItem?.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { resetPreviousCommandMenuContext } =
|
const { resetPreviousCommandMenuContext } =
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
@ -17,19 +17,19 @@ export const useCopyContextStoreStates = () => {
|
|||||||
instanceIdToCopyFrom: string;
|
instanceIdToCopyFrom: string;
|
||||||
instanceIdToCopyTo: string;
|
instanceIdToCopyTo: string;
|
||||||
}) => {
|
}) => {
|
||||||
const contextStoreCurrentObjectMetadataId = snapshot
|
const contextStoreCurrentObjectMetadataItem = snapshot
|
||||||
.getLoadable(
|
.getLoadable(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState.atomFamily({
|
contextStoreCurrentObjectMetadataItemComponentState.atomFamily({
|
||||||
instanceId: instanceIdToCopyFrom,
|
instanceId: instanceIdToCopyFrom,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.getValue();
|
.getValue();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState.atomFamily({
|
contextStoreCurrentObjectMetadataItemComponentState.atomFamily({
|
||||||
instanceId: instanceIdToCopyTo,
|
instanceId: instanceIdToCopyTo,
|
||||||
}),
|
}),
|
||||||
contextStoreCurrentObjectMetadataId,
|
contextStoreCurrentObjectMetadataItem,
|
||||||
);
|
);
|
||||||
|
|
||||||
const contextStoreTargetedRecordsRule = snapshot
|
const contextStoreTargetedRecordsRule = snapshot
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
@ -11,10 +11,10 @@ export const useResetContextStoreStates = () => {
|
|||||||
const resetContextStoreStates = useRecoilCallback(({ set }) => {
|
const resetContextStoreStates = useRecoilCallback(({ set }) => {
|
||||||
return (instanceId: string) => {
|
return (instanceId: string) => {
|
||||||
set(
|
set(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState.atomFamily({
|
contextStoreCurrentObjectMetadataItemComponentState.atomFamily({
|
||||||
instanceId,
|
instanceId,
|
||||||
}),
|
}),
|
||||||
null,
|
undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
set(
|
set(
|
||||||
@ -45,7 +45,7 @@ export const useResetContextStoreStates = () => {
|
|||||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||||
instanceId,
|
instanceId,
|
||||||
}),
|
}),
|
||||||
null,
|
undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
set(
|
set(
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
export const ContextStoreCurrentViewTypeEffect = ({
|
|
||||||
viewType,
|
|
||||||
}: {
|
|
||||||
viewType: ContextStoreViewType | null;
|
|
||||||
}) => {
|
|
||||||
const setContextStoreCurrentViewType = useSetRecoilComponentStateV2(
|
|
||||||
contextStoreCurrentViewTypeComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setContextStoreCurrentViewType(viewType);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
setContextStoreCurrentViewType(null);
|
|
||||||
};
|
|
||||||
}, [setContextStoreCurrentViewType, viewType]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@ -1,20 +1,16 @@
|
|||||||
import { MainContextStoreProviderEffect } from '@/context-store/components/MainContextStoreProviderEffect';
|
import { MainContextStoreProviderEffect } from '@/context-store/components/MainContextStoreProviderEffect';
|
||||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
|
||||||
import { useParams, useSearchParams } from 'react-router-dom';
|
import { useParams, useSearchParams } from 'react-router-dom';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { undefined } from 'zod';
|
|
||||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||||
|
|
||||||
const getViewId = (
|
const getViewId = (
|
||||||
viewIdFromQueryParams: string | null,
|
viewIdFromQueryParams: string | null,
|
||||||
indexView?: View,
|
indexViewId?: string,
|
||||||
lastVisitedViewId?: string,
|
lastVisitedViewId?: string,
|
||||||
) => {
|
) => {
|
||||||
if (isDefined(viewIdFromQueryParams)) {
|
if (isDefined(viewIdFromQueryParams)) {
|
||||||
@ -25,8 +21,8 @@ const getViewId = (
|
|||||||
return lastVisitedViewId;
|
return lastVisitedViewId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDefined(indexView)) {
|
if (isDefined(indexViewId)) {
|
||||||
return indexView.id;
|
return indexViewId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -44,17 +40,17 @@ export const MainContextStoreProvider = () => {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const objectNamePlural = useParams().objectNamePlural ?? '';
|
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||||
|
const objectNameSingular = useParams().objectNameSingular ?? '';
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const viewIdQueryParam = searchParams.get('viewId');
|
const viewIdQueryParam = searchParams.get('viewId');
|
||||||
|
|
||||||
// Todo: this is triggering a lot of re-renders as we update the viewFields, we should introduce a state here
|
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
(objectMetadataItem) => objectMetadataItem.namePlural === objectNamePlural,
|
(objectMetadataItem) =>
|
||||||
|
objectMetadataItem.namePlural === objectNamePlural ||
|
||||||
|
objectMetadataItem.nameSingular === objectNameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getLastVisitedViewIdFromObjectNamePlural } = useLastVisitedView();
|
const { getLastVisitedViewIdFromObjectNamePlural } = useLastVisitedView();
|
||||||
@ -63,30 +59,24 @@ export const MainContextStoreProvider = () => {
|
|||||||
objectMetadataItem?.namePlural ?? '',
|
objectMetadataItem?.namePlural ?? '',
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewsOnCurrentObject = views.filter(
|
const indexViewId = useRecoilValue(
|
||||||
(view) => view.objectMetadataId === objectMetadataItem?.id,
|
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem?.id,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
const indexView = viewsOnCurrentObject.find((view) => view.key === 'INDEX');
|
|
||||||
|
|
||||||
const viewId = getViewId(viewIdQueryParam, indexView, lastVisitedViewId);
|
const viewId = getViewId(viewIdQueryParam, indexViewId, lastVisitedViewId);
|
||||||
|
|
||||||
const mainContextStoreComponentInstanceId = `${pageName}-${objectMetadataItem?.namePlural}-${viewId}`;
|
if (!isDefined(pageName) || !isDefined(objectMetadataItem)) {
|
||||||
|
|
||||||
if (
|
|
||||||
!isDefined(pageName) ||
|
|
||||||
!isDefined(objectMetadataItem) ||
|
|
||||||
!isNonEmptyString(viewId)
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainContextStoreProviderEffect
|
<MainContextStoreProviderEffect
|
||||||
mainContextStoreComponentInstanceIdToSet={
|
mainContextStoreComponentInstanceIdToSet={'main-context-store'}
|
||||||
mainContextStoreComponentInstanceId
|
|
||||||
}
|
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
objectMetadataItem={objectMetadataItem}
|
objectMetadataItem={objectMetadataItem}
|
||||||
|
pageName={pageName}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,21 +1,27 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||||
|
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||||
import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId';
|
import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId';
|
||||||
import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural';
|
import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
export const MainContextStoreProviderEffect = ({
|
export const MainContextStoreProviderEffect = ({
|
||||||
mainContextStoreComponentInstanceIdToSet,
|
mainContextStoreComponentInstanceIdToSet,
|
||||||
viewId,
|
viewId,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
pageName,
|
||||||
}: {
|
}: {
|
||||||
mainContextStoreComponentInstanceIdToSet: string;
|
mainContextStoreComponentInstanceIdToSet: string;
|
||||||
viewId: string;
|
viewId?: string;
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
pageName: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [
|
const [
|
||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
@ -34,17 +40,29 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [contextStoreCurrentViewType, setContextStoreCurrentViewType] =
|
||||||
|
useRecoilComponentStateV2(
|
||||||
|
contextStoreCurrentViewTypeComponentState,
|
||||||
|
mainContextStoreComponentInstanceId,
|
||||||
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
contextStoreCurrentObjectMetadataId,
|
contextStoreCurrentObjectMetadataItem,
|
||||||
setContextStoreCurrentObjectMetadataId,
|
setContextStoreCurrentObjectMetadataItem,
|
||||||
] = useRecoilComponentStateV2(
|
] = useRecoilComponentStateV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const view = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: viewId ?? '',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (contextStoreCurrentObjectMetadataId !== objectMetadataItem.id) {
|
if (contextStoreCurrentObjectMetadataItem?.id !== objectMetadataItem.id) {
|
||||||
setContextStoreCurrentObjectMetadataId(objectMetadataItem.id);
|
setContextStoreCurrentObjectMetadataItem(objectMetadataItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -58,7 +76,7 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
|
|
||||||
setLastVisitedViewForObjectMetadataNamePlural({
|
setLastVisitedViewForObjectMetadataNamePlural({
|
||||||
objectNamePlural: objectMetadataItem.namePlural,
|
objectNamePlural: objectMetadataItem.namePlural,
|
||||||
viewId: viewId,
|
viewId: viewId ?? '',
|
||||||
});
|
});
|
||||||
|
|
||||||
setLastVisitedObjectMetadataId({
|
setLastVisitedObjectMetadataId({
|
||||||
@ -69,13 +87,13 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
setContextStoreCurrentViewId(viewId);
|
setContextStoreCurrentViewId(viewId);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
contextStoreCurrentObjectMetadataId,
|
contextStoreCurrentObjectMetadataItem,
|
||||||
contextStoreCurrentViewId,
|
contextStoreCurrentViewId,
|
||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
mainContextStoreComponentInstanceIdToSet,
|
mainContextStoreComponentInstanceIdToSet,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
objectMetadataItem.namePlural,
|
objectMetadataItem.namePlural,
|
||||||
setContextStoreCurrentObjectMetadataId,
|
setContextStoreCurrentObjectMetadataItem,
|
||||||
setContextStoreCurrentViewId,
|
setContextStoreCurrentViewId,
|
||||||
setLastVisitedObjectMetadataId,
|
setLastVisitedObjectMetadataId,
|
||||||
setLastVisitedViewForObjectMetadataNamePlural,
|
setLastVisitedViewForObjectMetadataNamePlural,
|
||||||
@ -83,5 +101,23 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
viewId,
|
viewId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const viewType =
|
||||||
|
pageName === 'record-show'
|
||||||
|
? ContextStoreViewType.ShowPage
|
||||||
|
: view && view.type === ViewType.Kanban
|
||||||
|
? ContextStoreViewType.Kanban
|
||||||
|
: ContextStoreViewType.Table;
|
||||||
|
|
||||||
|
if (contextStoreCurrentViewType !== viewType) {
|
||||||
|
setContextStoreCurrentViewType(viewType);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
contextStoreCurrentViewType,
|
||||||
|
pageName,
|
||||||
|
setContextStoreCurrentViewType,
|
||||||
|
view,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
|
|
||||||
export const useContextStoreCurrentObjectMetadataIdOrThrow = (
|
|
||||||
instanceId?: string,
|
|
||||||
) => {
|
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
|
||||||
instanceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!contextStoreCurrentObjectMetadataId) {
|
|
||||||
throw new Error('contextStoreCurrentObjectMetadataIdComponent is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
return contextStoreCurrentObjectMetadataId;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
|
export const useContextStoreObjectMetadataItemOrThrow = (
|
||||||
|
contextStoreInstanceId?: string,
|
||||||
|
) => {
|
||||||
|
const objectMetadataItem = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
|
contextStoreInstanceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!objectMetadataItem) {
|
||||||
|
throw new Error('Object metadata item is not set in context store');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { objectMetadataItem };
|
||||||
|
};
|
||||||
@ -1,8 +1,7 @@
|
|||||||
import { useContextStoreCurrentObjectMetadataIdOrThrow } from '@/context-store/hooks/useContextStoreCurrentObjectMetadataIdOrThrow';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
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 { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -14,12 +13,10 @@ export const useFindManyRecordsSelectedInContextStore = ({
|
|||||||
instanceId?: string;
|
instanceId?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const objectMetadataId =
|
const objectMetadataItem = useRecoilComponentValueV2(
|
||||||
useContextStoreCurrentObjectMetadataIdOrThrow(instanceId);
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
|
instanceId,
|
||||||
const { objectMetadataItem } = useObjectMetadataItemById({
|
);
|
||||||
objectId: objectMetadataId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
@ -36,12 +33,13 @@ export const useFindManyRecordsSelectedInContextStore = ({
|
|||||||
const queryFilter = computeContextStoreFilters(
|
const queryFilter = computeContextStoreFilters(
|
||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem,
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
objectMetadataItem!,
|
||||||
filterValueDependencies,
|
filterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { records, loading, totalCount } = useFindManyRecords({
|
const { records, loading, totalCount } = useFindManyRecords({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: objectMetadataItem?.nameSingular ?? '',
|
||||||
filter: queryFilter,
|
filter: queryFilter,
|
||||||
withSoftDeleted: true,
|
withSoftDeleted: true,
|
||||||
orderBy: [
|
orderBy: [
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const contextStoreCurrentObjectMetadataIdComponentState =
|
export const contextStoreCurrentObjectMetadataItemComponentState =
|
||||||
createComponentStateV2<string | null>({
|
createComponentStateV2<ObjectMetadataItem | undefined>({
|
||||||
key: 'contextStoreCurrentObjectMetadataIdComponentState',
|
key: 'contextStoreCurrentObjectMetadataItemComponentState',
|
||||||
defaultValue: null,
|
defaultValue: undefined,
|
||||||
componentInstanceContext: ContextStoreComponentInstanceContext,
|
componentInstanceContext: ContextStoreComponentInstanceContext,
|
||||||
});
|
});
|
||||||
@ -2,9 +2,9 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con
|
|||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const contextStoreCurrentViewIdComponentState = createComponentStateV2<
|
export const contextStoreCurrentViewIdComponentState = createComponentStateV2<
|
||||||
string | null
|
string | undefined
|
||||||
>({
|
>({
|
||||||
key: 'contextStoreCurrentViewIdComponentState',
|
key: 'contextStoreCurrentViewIdComponentState',
|
||||||
defaultValue: null,
|
defaultValue: undefined,
|
||||||
componentInstanceContext: ContextStoreComponentInstanceContext,
|
componentInstanceContext: ContextStoreComponentInstanceContext,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,47 +1,13 @@
|
|||||||
import { Favorite } from '@/favorites/types/Favorite';
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useReadFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache';
|
|
||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
|
||||||
import { useUpsertRecordsInCacheForPrefetchKey } from '@/prefetch/hooks/internal/useUpsertRecordsInCacheForPrefetchKey';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
|
|
||||||
export const useDeleteFavoriteFolder = () => {
|
export const useDeleteFavoriteFolder = () => {
|
||||||
const { deleteOneRecord } = useDeleteOneRecord({
|
const { deleteOneRecord } = useDeleteOneRecord({
|
||||||
objectNameSingular: CoreObjectNameSingular.FavoriteFolder,
|
objectNameSingular: CoreObjectNameSingular.FavoriteFolder,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { upsertRecordsInCache } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<Favorite>({
|
|
||||||
prefetchKey: PrefetchKey.AllFavorites,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular:
|
|
||||||
PREFETCH_CONFIG[PrefetchKey.AllFavorites].objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { readFindManyRecordsQueryInCache } =
|
|
||||||
useReadFindManyRecordsQueryInCache({
|
|
||||||
objectMetadataItem,
|
|
||||||
});
|
|
||||||
|
|
||||||
const deleteFavoriteFolder = async (folderId: string): Promise<void> => {
|
const deleteFavoriteFolder = async (folderId: string): Promise<void> => {
|
||||||
await deleteOneRecord(folderId);
|
await deleteOneRecord(folderId);
|
||||||
|
|
||||||
const allFavorites = readFindManyRecordsQueryInCache<Favorite>({
|
|
||||||
queryVariables: {},
|
|
||||||
recordGqlFields: PREFETCH_CONFIG[
|
|
||||||
PrefetchKey.AllFavorites
|
|
||||||
].operationSignatureFactory({ objectMetadataItem }).fields,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedFavorites = allFavorites.filter(
|
|
||||||
(favorite) => favorite.favoriteFolderId !== folderId,
|
|
||||||
);
|
|
||||||
|
|
||||||
upsertRecordsInCache(updatedFavorites);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
|
import { favoriteViewsWithMinimalDataSelector } from '@/favorites/states/selectors/favoriteViewsWithMinimalDataSelector';
|
||||||
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
||||||
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
@ -13,7 +11,9 @@ import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
|||||||
|
|
||||||
export const useFavorites = () => {
|
export const useFavorites = () => {
|
||||||
const { favorites } = usePrefetchedFavoritesData();
|
const { favorites } = usePrefetchedFavoritesData();
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const favoriteViewsWithMinimalData = useRecoilValue(
|
||||||
|
favoriteViewsWithMinimalDataSelector,
|
||||||
|
);
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
||||||
useObjectMetadataItem({
|
useObjectMetadataItem({
|
||||||
@ -40,14 +40,14 @@ export const useFavorites = () => {
|
|||||||
favoriteRelationFieldMetadataItems,
|
favoriteRelationFieldMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
true,
|
true,
|
||||||
views,
|
favoriteViewsWithMinimalData,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
favorites,
|
favorites,
|
||||||
favoriteRelationFieldMetadataItems,
|
favoriteRelationFieldMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
views,
|
favoriteViewsWithMinimalData,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useFavoritesMetadata } from './useFavoritesMetadata';
|
import { useFavoritesMetadata } from './useFavoritesMetadata';
|
||||||
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
||||||
import { usePrefetchedFavoritesFoldersData } from './usePrefetchedFavoritesFoldersData';
|
import { usePrefetchedFavoritesFoldersData } from './usePrefetchedFavoritesFoldersData';
|
||||||
@ -7,12 +9,13 @@ export const useFavoritesByFolder = () => {
|
|||||||
const { favorites } = usePrefetchedFavoritesData();
|
const { favorites } = usePrefetchedFavoritesData();
|
||||||
const { favoriteFolders } = usePrefetchedFavoritesFoldersData();
|
const { favoriteFolders } = usePrefetchedFavoritesFoldersData();
|
||||||
const {
|
const {
|
||||||
views,
|
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
} = useFavoritesMetadata();
|
} = useFavoritesMetadata();
|
||||||
|
|
||||||
|
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||||
|
|
||||||
const favoritesByFolder = favoriteFolders.map((folder) => ({
|
const favoritesByFolder = favoriteFolders.map((folder) => ({
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
folderName: folder.name,
|
folderName: folder.name,
|
||||||
@ -21,7 +24,7 @@ export const useFavoritesByFolder = () => {
|
|||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
true,
|
true,
|
||||||
views,
|
prefetchViews,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -2,14 +2,10 @@ import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/ho
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const useFavoritesMetadata = () => {
|
export const useFavoritesMetadata = () => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
const getObjectRecordIdentifierByNameSingular =
|
const getObjectRecordIdentifierByNameSingular =
|
||||||
useGetObjectRecordIdentifierByNameSingular();
|
useGetObjectRecordIdentifierByNameSingular();
|
||||||
@ -27,7 +23,6 @@ export const useFavoritesMetadata = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
views,
|
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
|
|||||||
@ -1,46 +1,30 @@
|
|||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { Favorite } from '@/favorites/types/Favorite';
|
import { Favorite } from '@/favorites/types/Favorite';
|
||||||
import { useUpsertRecordsInCacheForPrefetchKey } from '@/prefetch/hooks/internal/useUpsertRecordsInCacheForPrefetchKey';
|
import { prefetchFavoritesState } from '@/prefetch/states/prefetchFavoritesState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
type PrefetchedFavoritesData = {
|
type PrefetchedFavoritesData = {
|
||||||
favorites: Favorite[];
|
favorites: Favorite[];
|
||||||
workspaceFavorites: Favorite[];
|
workspaceFavorites: Favorite[];
|
||||||
upsertFavorites: (records: Favorite[]) => void;
|
|
||||||
currentWorkspaceMemberId: string | undefined;
|
currentWorkspaceMemberId: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const usePrefetchedFavoritesData = (): PrefetchedFavoritesData => {
|
export const usePrefetchedFavoritesData = (): PrefetchedFavoritesData => {
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
const currentWorkspaceMemberId = currentWorkspaceMember?.id;
|
const currentWorkspaceMemberId = currentWorkspaceMember?.id;
|
||||||
const { records: _favorites } = usePrefetchedData<Favorite>(
|
const prefetchFavorites = useRecoilValue(prefetchFavoritesState);
|
||||||
PrefetchKey.AllFavorites,
|
|
||||||
{
|
|
||||||
workspaceMemberId: {
|
|
||||||
eq: currentWorkspaceMemberId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const favorites = _favorites.filter(
|
const favorites = prefetchFavorites.filter(
|
||||||
(favorite) => favorite.workspaceMemberId === currentWorkspaceMemberId,
|
(favorite) => favorite.workspaceMemberId === currentWorkspaceMemberId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const workspaceFavorites = _favorites.filter(
|
const workspaceFavorites = prefetchFavorites.filter(
|
||||||
(favorite) => favorite.workspaceMemberId === null,
|
(favorite) => favorite.workspaceMemberId === null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { upsertRecordsInCache: upsertFavorites } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<Favorite>({
|
|
||||||
prefetchKey: PrefetchKey.AllFavorites,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
favorites,
|
favorites,
|
||||||
workspaceFavorites,
|
workspaceFavorites,
|
||||||
upsertFavorites,
|
|
||||||
currentWorkspaceMemberId,
|
currentWorkspaceMemberId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
import { FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
||||||
import { useUpsertRecordsInCacheForPrefetchKey } from '@/prefetch/hooks/internal/useUpsertRecordsInCacheForPrefetchKey';
|
import { prefetchFavoriteFoldersState } from '@/prefetch/states/prefetchFavoriteFoldersState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
type PrefetchedFavoritesFoldersData = {
|
type PrefetchedFavoritesFoldersData = {
|
||||||
favoriteFolders: FavoriteFolder[];
|
favoriteFolders: FavoriteFolder[];
|
||||||
upsertFavoriteFolders: (records: FavoriteFolder[]) => void;
|
|
||||||
currentWorkspaceMemberId: string | undefined;
|
currentWorkspaceMemberId: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -16,23 +13,12 @@ export const usePrefetchedFavoritesFoldersData =
|
|||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
const currentWorkspaceMemberId = currentWorkspaceMember?.id;
|
const currentWorkspaceMemberId = currentWorkspaceMember?.id;
|
||||||
|
|
||||||
const { records: favoriteFolders } = usePrefetchedData<FavoriteFolder>(
|
const prefetchFavoriteFolders = useRecoilValue(
|
||||||
PrefetchKey.AllFavoritesFolders,
|
prefetchFavoriteFoldersState,
|
||||||
{
|
|
||||||
workspaceMemberId: {
|
|
||||||
eq: currentWorkspaceMemberId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { upsertRecordsInCache: upsertFavoriteFolders } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<FavoriteFolder>({
|
|
||||||
prefetchKey: PrefetchKey.AllFavoritesFolders,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
favoriteFolders,
|
favoriteFolders: prefetchFavoriteFolders,
|
||||||
upsertFavoriteFolders,
|
|
||||||
currentWorkspaceMemberId,
|
currentWorkspaceMemberId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,32 +1,35 @@
|
|||||||
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useFavoritesMetadata } from './useFavoritesMetadata';
|
import { useFavoritesMetadata } from './useFavoritesMetadata';
|
||||||
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
||||||
|
|
||||||
export const useSortedFavorites = () => {
|
export const useSortedFavorites = () => {
|
||||||
const { favorites, workspaceFavorites } = usePrefetchedFavoritesData();
|
const { favorites, workspaceFavorites } = usePrefetchedFavoritesData();
|
||||||
const {
|
const {
|
||||||
views,
|
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
} = useFavoritesMetadata();
|
} = useFavoritesMetadata();
|
||||||
|
|
||||||
|
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||||
|
|
||||||
const favoritesSorted = useMemo(() => {
|
const favoritesSorted = useMemo(() => {
|
||||||
return sortFavorites(
|
return sortFavorites(
|
||||||
favorites,
|
favorites,
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
true,
|
true,
|
||||||
views,
|
prefetchViews,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
favorites,
|
favorites,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
views,
|
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
|
prefetchViews,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const workspaceFavoritesSorted = useMemo(() => {
|
const workspaceFavoritesSorted = useMemo(() => {
|
||||||
@ -35,14 +38,14 @@ export const useSortedFavorites = () => {
|
|||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
false,
|
false,
|
||||||
views,
|
prefetchViews,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
|
workspaceFavorites,
|
||||||
favoriteRelationFields,
|
favoriteRelationFields,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
workspaceFavorites,
|
prefetchViews,
|
||||||
views,
|
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,7 @@ import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/ho
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
@ -14,8 +12,7 @@ import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
|||||||
|
|
||||||
export const useWorkspaceFavorites = () => {
|
export const useWorkspaceFavorites = () => {
|
||||||
const { workspaceFavorites } = usePrefetchedFavoritesData();
|
const { workspaceFavorites } = usePrefetchedFavoritesData();
|
||||||
|
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
||||||
useObjectMetadataItem({
|
useObjectMetadataItem({
|
||||||
@ -42,14 +39,14 @@ export const useWorkspaceFavorites = () => {
|
|||||||
favoriteRelationFieldMetadataItems,
|
favoriteRelationFieldMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
false,
|
false,
|
||||||
views,
|
prefetchViews,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
workspaceFavorites,
|
workspaceFavorites,
|
||||||
favoriteRelationFieldMetadataItems,
|
favoriteRelationFieldMetadataItems,
|
||||||
getObjectRecordIdentifierByNameSingular,
|
getObjectRecordIdentifierByNameSingular,
|
||||||
views,
|
prefetchViews,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -59,7 +56,7 @@ export const useWorkspaceFavorites = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const favoriteViewObjectMetadataIds = new Set(
|
const favoriteViewObjectMetadataIds = new Set(
|
||||||
views.reduce<string[]>((acc, view) => {
|
prefetchViews.reduce<string[]>((acc, view) => {
|
||||||
if (workspaceFavoriteIds.has(view.id)) {
|
if (workspaceFavoriteIds.has(view.id)) {
|
||||||
acc.push(view.objectMetadataId);
|
acc.push(view.objectMetadataId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { selector } from 'recoil';
|
||||||
|
|
||||||
|
export const favoriteViewsWithMinimalDataSelector = selector<
|
||||||
|
Pick<View, 'id' | 'name' | 'objectMetadataId' | 'icon'>[]
|
||||||
|
>({
|
||||||
|
key: 'favoriteViewsWithMinimalDataSelector',
|
||||||
|
get: ({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views.map((view) => ({
|
||||||
|
id: view.id,
|
||||||
|
name: view.name,
|
||||||
|
objectMetadataId: view.objectMetadataId,
|
||||||
|
icon: view.icon,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -4,23 +4,13 @@ import { isDefined } from 'twenty-shared';
|
|||||||
|
|
||||||
type ReturnType = {
|
type ReturnType = {
|
||||||
labelPlural: string;
|
labelPlural: string;
|
||||||
view: View | null;
|
view: Pick<View, 'id' | 'name' | 'objectMetadataId'>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getObjectMetadataLabelPluralFromViewId = (
|
export const getObjectMetadataLabelPluralFromViewId = (
|
||||||
views: View[],
|
view: Pick<View, 'id' | 'name' | 'objectMetadataId'>,
|
||||||
objectMetadataItems: ObjectMetadataItem[],
|
objectMetadataItems: ObjectMetadataItem[],
|
||||||
viewId: string,
|
|
||||||
): ReturnType => {
|
): ReturnType => {
|
||||||
const view = views.find((view) => view.id === viewId);
|
|
||||||
|
|
||||||
if (!view) {
|
|
||||||
return {
|
|
||||||
labelPlural: '',
|
|
||||||
view: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
(objectMetadataItem) => objectMetadataItem.id === view.objectMetadataId,
|
(objectMetadataItem) => objectMetadataItem.id === view.objectMetadataId,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -22,16 +22,23 @@ export const sortFavorites = (
|
|||||||
objectNameSingular: string,
|
objectNameSingular: string,
|
||||||
) => ObjectRecordIdentifier,
|
) => ObjectRecordIdentifier,
|
||||||
hasLinkToShowPage: boolean,
|
hasLinkToShowPage: boolean,
|
||||||
views: View[],
|
views: Pick<View, 'id' | 'name' | 'objectMetadataId' | 'icon'>[],
|
||||||
objectMetadataItems: ObjectMetadataItem[],
|
objectMetadataItems: ObjectMetadataItem[],
|
||||||
) => {
|
) => {
|
||||||
return favorites
|
return favorites
|
||||||
.map((favorite) => {
|
.map((favorite) => {
|
||||||
if (isDefined(favorite.viewId) && isDefined(favorite.workspaceMemberId)) {
|
if (isDefined(favorite.viewId) && isDefined(favorite.workspaceMemberId)) {
|
||||||
const { labelPlural, view } = getObjectMetadataLabelPluralFromViewId(
|
const view = views.find((view) => view.id === favorite.viewId);
|
||||||
views,
|
|
||||||
|
if (!isDefined(view)) {
|
||||||
|
return {
|
||||||
|
...favorite,
|
||||||
|
} as ProcessedFavorite;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { labelPlural } = getObjectMetadataLabelPluralFromViewId(
|
||||||
|
view,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
favorite.viewId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -4,41 +4,54 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
import { getCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { mockedUserData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
const renderHooks = ({
|
||||||
const setupMockPrefetchedData = (viewId?: string) => {
|
withCurrentUser,
|
||||||
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
|
withExistingView,
|
||||||
(item) => item.nameSingular === 'company',
|
}: {
|
||||||
);
|
withCurrentUser: boolean;
|
||||||
|
withExistingView: boolean;
|
||||||
jest.mocked(usePrefetchedData).mockReturnValue({
|
}) => {
|
||||||
isDataPrefetched: true,
|
|
||||||
records: viewId
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
id: viewId,
|
|
||||||
__typename: 'object',
|
|
||||||
objectMetadataId: companyObjectMetadata?.id,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderHooks = (withCurrentUser: boolean) => {
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
const setObjectMetadataItems = useSetRecoilState(
|
const setObjectMetadataItems = useSetRecoilState(
|
||||||
objectMetadataItemsState,
|
objectMetadataItemsState,
|
||||||
);
|
);
|
||||||
|
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
|
||||||
|
|
||||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
|
if (withExistingView) {
|
||||||
|
setPrefetchViews([
|
||||||
|
{
|
||||||
|
id: 'viewId',
|
||||||
|
name: 'Test View',
|
||||||
|
objectMetadataId: getCompanyObjectMetadataItem().id,
|
||||||
|
type: ViewType.Table,
|
||||||
|
key: null,
|
||||||
|
isCompact: false,
|
||||||
|
viewFields: [],
|
||||||
|
viewGroups: [],
|
||||||
|
viewSorts: [],
|
||||||
|
kanbanFieldMetadataId: '',
|
||||||
|
kanbanAggregateOperation: AGGREGATE_OPERATIONS.count,
|
||||||
|
icon: '',
|
||||||
|
kanbanAggregateOperationFieldMetadataId: '',
|
||||||
|
position: 0,
|
||||||
|
viewFilters: [],
|
||||||
|
__typename: 'View',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (withCurrentUser) {
|
if (withCurrentUser) {
|
||||||
setCurrentUser(mockedUserData);
|
setCurrentUser(mockedUserData);
|
||||||
}
|
}
|
||||||
@ -52,23 +65,31 @@ const renderHooks = (withCurrentUser: boolean) => {
|
|||||||
};
|
};
|
||||||
describe('useDefaultHomePagePath', () => {
|
describe('useDefaultHomePagePath', () => {
|
||||||
it('should return proper path when no currentUser', () => {
|
it('should return proper path when no currentUser', () => {
|
||||||
setupMockPrefetchedData();
|
const { result } = renderHooks({
|
||||||
const { result } = renderHooks(false);
|
withCurrentUser: false,
|
||||||
|
withExistingView: false,
|
||||||
|
});
|
||||||
expect(result.current.defaultHomePagePath).toEqual(AppPath.SignInUp);
|
expect(result.current.defaultHomePagePath).toEqual(AppPath.SignInUp);
|
||||||
});
|
});
|
||||||
it('should return proper path when no currentUser and existing view', () => {
|
it('should return proper path when no currentUser and existing view', () => {
|
||||||
setupMockPrefetchedData('viewId');
|
const { result } = renderHooks({
|
||||||
const { result } = renderHooks(false);
|
withCurrentUser: false,
|
||||||
|
withExistingView: true,
|
||||||
|
});
|
||||||
expect(result.current.defaultHomePagePath).toEqual(AppPath.SignInUp);
|
expect(result.current.defaultHomePagePath).toEqual(AppPath.SignInUp);
|
||||||
});
|
});
|
||||||
it('should return proper path when currentUser is defined', () => {
|
it('should return proper path when currentUser is defined', () => {
|
||||||
setupMockPrefetchedData();
|
const { result } = renderHooks({
|
||||||
const { result } = renderHooks(true);
|
withCurrentUser: true,
|
||||||
|
withExistingView: false,
|
||||||
|
});
|
||||||
expect(result.current.defaultHomePagePath).toEqual('/objects/companies');
|
expect(result.current.defaultHomePagePath).toEqual('/objects/companies');
|
||||||
});
|
});
|
||||||
it('should return proper path when currentUser is defined and view exists', () => {
|
it('should return proper path when currentUser is defined and view exists', () => {
|
||||||
setupMockPrefetchedData('viewId');
|
const { result } = renderHooks({
|
||||||
const { result } = renderHooks(true);
|
withCurrentUser: true,
|
||||||
|
withExistingView: true,
|
||||||
|
});
|
||||||
expect(result.current.defaultHomePagePath).toEqual(
|
expect(result.current.defaultHomePagePath).toEqual(
|
||||||
'/objects/companies?viewId=viewId',
|
'/objects/companies?viewId=viewId',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,10 +2,8 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
|||||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||||
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
@ -15,7 +13,7 @@ export const useDefaultHomePagePath = () => {
|
|||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
const { activeObjectMetadataItems, alphaSortedActiveObjectMetadataItems } =
|
const { activeObjectMetadataItems, alphaSortedActiveObjectMetadataItems } =
|
||||||
useFilteredObjectMetadataItems();
|
useFilteredObjectMetadataItems();
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||||
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
||||||
lastVisitedObjectMetadataItemIdState,
|
lastVisitedObjectMetadataItemIdState,
|
||||||
);
|
);
|
||||||
@ -31,8 +29,10 @@ export const useDefaultHomePagePath = () => {
|
|||||||
|
|
||||||
const getFirstView = useCallback(
|
const getFirstView = useCallback(
|
||||||
(objectMetadataItemId: string | undefined | null) =>
|
(objectMetadataItemId: string | undefined | null) =>
|
||||||
views.find((view) => view.objectMetadataId === objectMetadataItemId),
|
prefetchViews.find(
|
||||||
[views],
|
(view) => view.objectMetadataId === objectMetadataItemId,
|
||||||
|
),
|
||||||
|
[prefetchViews],
|
||||||
);
|
);
|
||||||
|
|
||||||
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
||||||
|
|||||||
@ -1,16 +1,11 @@
|
|||||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { useLazyPrefetchedData } from '@/prefetch/hooks/useLazyPrefetchData';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||||
const { records: views, findManyRecords } = useLazyPrefetchedData<View>(
|
|
||||||
PrefetchKey.AllViews,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setLastVisitedViewForObjectMetadataNamePlural = useRecoilCallback(
|
const setLastVisitedViewForObjectMetadataNamePlural = useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
async ({
|
async ({
|
||||||
@ -20,7 +15,7 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
|||||||
objectNamePlural: string;
|
objectNamePlural: string;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
}) => {
|
}) => {
|
||||||
await findManyRecords();
|
const views = snapshot.getLoadable(prefetchViewsState).getValue();
|
||||||
|
|
||||||
const view = views.find((view: View) => view.id === viewId);
|
const view = views.find((view: View) => view.id === viewId);
|
||||||
|
|
||||||
@ -54,7 +49,7 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[findManyRecords, views],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -2,16 +2,13 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
|
|||||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||||
import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer';
|
import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer';
|
||||||
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
||||||
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { AnimatedExpandableContainer, useIcons } from 'twenty-ui';
|
import { AnimatedExpandableContainer, useIcons } from 'twenty-ui';
|
||||||
@ -24,11 +21,10 @@ export type NavigationDrawerItemForObjectMetadataItemProps = {
|
|||||||
export const NavigationDrawerItemForObjectMetadataItem = ({
|
export const NavigationDrawerItemForObjectMetadataItem = ({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
}: NavigationDrawerItemForObjectMetadataItemProps) => {
|
}: NavigationDrawerItemForObjectMetadataItemProps) => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const views = useRecoilValue(
|
||||||
|
prefetchViewsFromObjectMetadataItemFamilySelector({
|
||||||
const objectMetadataViews = getObjectMetadataItemViews(
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
objectMetadataItem.id,
|
}),
|
||||||
views,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||||
@ -68,9 +64,9 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
|
|||||||
}) + '/',
|
}) + '/',
|
||||||
);
|
);
|
||||||
|
|
||||||
const shouldSubItemsBeDisplayed = isActive && objectMetadataViews.length > 1;
|
const shouldSubItemsBeDisplayed = isActive && views.length > 1;
|
||||||
|
|
||||||
const sortedObjectMetadataViews = [...objectMetadataViews].sort(
|
const sortedObjectMetadataViews = [...views].sort(
|
||||||
(viewA, viewB) => viewA.position - viewB.position,
|
(viewA, viewB) => viewA.position - viewB.position,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { useMemo } 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 { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
@ -13,14 +11,8 @@ import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldM
|
|||||||
export const useColumnDefinitionsFromFieldMetadata = (
|
export const useColumnDefinitionsFromFieldMetadata = (
|
||||||
objectMetadataItem: ObjectMetadataItem,
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
) => {
|
) => {
|
||||||
const activeFieldMetadataItems = useMemo(
|
const activeFieldMetadataItems = objectMetadataItem.fields.filter(
|
||||||
() =>
|
({ isActive, isSystem }) => isActive && !isSystem,
|
||||||
objectMetadataItem
|
|
||||||
? objectMetadataItem.fields.filter(
|
|
||||||
({ isActive, isSystem }) => isActive && !isSystem,
|
|
||||||
)
|
|
||||||
: [],
|
|
||||||
[objectMetadataItem],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterableFieldMetadataItems = useRecoilValue(
|
const filterableFieldMetadataItems = useRecoilValue(
|
||||||
@ -33,43 +25,30 @@ export const useColumnDefinitionsFromFieldMetadata = (
|
|||||||
fields: activeFieldMetadataItems,
|
fields: activeFieldMetadataItems,
|
||||||
});
|
});
|
||||||
|
|
||||||
const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo(
|
const columnDefinitions: ColumnDefinition<FieldMetadata>[] =
|
||||||
() =>
|
activeFieldMetadataItems
|
||||||
objectMetadataItem
|
.map((field, index) =>
|
||||||
? activeFieldMetadataItems
|
formatFieldMetadataItemAsColumnDefinition({
|
||||||
.map((field, index) =>
|
position: index,
|
||||||
formatFieldMetadataItemAsColumnDefinition({
|
field,
|
||||||
position: index,
|
objectMetadataItem,
|
||||||
field,
|
}),
|
||||||
objectMetadataItem,
|
)
|
||||||
}),
|
.filter(filterAvailableTableColumns)
|
||||||
)
|
.map((column) => {
|
||||||
.filter(filterAvailableTableColumns)
|
const existsInFilterDefinitions = filterableFieldMetadataItems.some(
|
||||||
.map((column) => {
|
(fieldMetadataItem) =>
|
||||||
const existsInFilterDefinitions =
|
fieldMetadataItem.id === column.fieldMetadataId,
|
||||||
filterableFieldMetadataItems.some(
|
);
|
||||||
(fieldMetadataItem) =>
|
const existsInSortDefinitions = sortDefinitions.some(
|
||||||
fieldMetadataItem.id === column.fieldMetadataId,
|
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
return {
|
||||||
const existsInSortDefinitions = sortDefinitions.some(
|
...column,
|
||||||
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
isFilterable: existsInFilterDefinitions,
|
||||||
);
|
isSortable: existsInSortDefinitions,
|
||||||
|
};
|
||||||
return {
|
});
|
||||||
...column,
|
|
||||||
isFilterable: existsInFilterDefinitions,
|
|
||||||
isSortable: existsInSortDefinitions,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
: [],
|
|
||||||
[
|
|
||||||
filterableFieldMetadataItems,
|
|
||||||
activeFieldMetadataItems,
|
|
||||||
objectMetadataItem,
|
|
||||||
sortDefinitions,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
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 { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
@ -24,11 +24,10 @@ export const useDeleteCombinedViewFilterGroup = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
viewBarComponentId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getViewFromCache } = useGetViewFromCache();
|
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||||
|
|
||||||
const deleteCombinedViewFilterGroup = useRecoilCallback(
|
const deleteCombinedViewFilterGroup = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
@ -56,7 +55,7 @@ export const useDeleteCombinedViewFilterGroup = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentView = await getViewFromCache(currentViewId);
|
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||||
|
|
||||||
if (!currentView) {
|
if (!currentView) {
|
||||||
return;
|
return;
|
||||||
@ -99,7 +98,7 @@ export const useDeleteCombinedViewFilterGroup = (
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
currentViewIdCallbackState,
|
currentViewIdCallbackState,
|
||||||
getViewFromCache,
|
getViewFromPrefetchState,
|
||||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -116,6 +116,7 @@ export const useCreateOneRecord = <
|
|||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
objectMetadataItems,
|
objectMetadataItems,
|
||||||
record: recordCreatedInCache,
|
record: recordCreatedInCache,
|
||||||
|
recordGqlFields: computedRecordGqlFields,
|
||||||
computeReferences: false,
|
computeReferences: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
ComponentDecorator,
|
ComponentDecorator,
|
||||||
getCanvasElementForDropdownTesting,
|
getCanvasElementForDropdownTesting,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
@ -79,6 +80,7 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
</RecordIndexContextProvider>
|
</RecordIndexContextProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ContextStoreDecorator,
|
||||||
ObjectMetadataItemsDecorator,
|
ObjectMetadataItemsDecorator,
|
||||||
SnackBarDecorator,
|
SnackBarDecorator,
|
||||||
ComponentDecorator,
|
ComponentDecorator,
|
||||||
|
|||||||
@ -36,7 +36,6 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
const {
|
const {
|
||||||
viewType,
|
viewType,
|
||||||
currentContentId,
|
currentContentId,
|
||||||
recordIndexId,
|
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
onContentChange,
|
onContentChange,
|
||||||
resetContent,
|
resetContent,
|
||||||
@ -64,9 +63,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
const {
|
const {
|
||||||
handleRecordGroupFieldChange: setRecordGroupField,
|
handleRecordGroupFieldChange: setRecordGroupField,
|
||||||
resetRecordGroupField,
|
resetRecordGroupField,
|
||||||
} = useHandleRecordGroupField({
|
} = useHandleRecordGroupField();
|
||||||
viewBarComponentId: recordIndexId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const newSelectFieldSettingsUrl = getSettingsPath(
|
const newSelectFieldSettingsUrl = getSettingsPath(
|
||||||
SettingsPath.ObjectNewFieldConfigure,
|
SettingsPath.ObjectNewFieldConfigure,
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { ComponentDecorator } from 'twenty-ui';
|
import { ComponentDecorator } from 'twenty-ui';
|
||||||
|
|
||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent';
|
import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent';
|
||||||
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';
|
||||||
@ -16,6 +15,7 @@ import { ViewType } from '@/views/types/ViewType';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||||
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';
|
||||||
@ -45,21 +45,18 @@ const meta: Meta<typeof ObjectOptionsDropdownContent> = {
|
|||||||
value={{ instanceId, onColumnsChange: () => {} }}
|
value={{ instanceId, onColumnsChange: () => {} }}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||||
<ContextStoreComponentInstanceContext.Provider
|
<MemoryRouter
|
||||||
value={{ instanceId }}
|
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||||
|
initialIndex={1}
|
||||||
>
|
>
|
||||||
<MemoryRouter
|
<Story />
|
||||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
</MemoryRouter>
|
||||||
initialIndex={1}
|
|
||||||
>
|
|
||||||
<Story />
|
|
||||||
</MemoryRouter>
|
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
|
||||||
</ViewComponentInstanceContext.Provider>
|
</ViewComponentInstanceContext.Provider>
|
||||||
</RecordTableComponentInstanceContext.Provider>
|
</RecordTableComponentInstanceContext.Provider>
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ContextStoreDecorator,
|
||||||
ObjectMetadataItemsDecorator,
|
ObjectMetadataItemsDecorator,
|
||||||
SnackBarDecorator,
|
SnackBarDecorator,
|
||||||
ComponentDecorator,
|
ComponentDecorator,
|
||||||
|
|||||||
@ -26,13 +26,12 @@ type useObjectOptionsForBoardParams = {
|
|||||||
export const useObjectOptionsForBoard = ({
|
export const useObjectOptionsForBoard = ({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
recordBoardId,
|
recordBoardId,
|
||||||
viewBarId,
|
|
||||||
}: useObjectOptionsForBoardParams) => {
|
}: useObjectOptionsForBoardParams) => {
|
||||||
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
||||||
useRecoilState(recordIndexFieldDefinitionsState);
|
useRecoilState(recordIndexFieldDefinitionsState);
|
||||||
|
|
||||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
const { saveViewFields } = useSaveCurrentViewFields();
|
||||||
const { updateCurrentView } = useUpdateCurrentView(viewBarId);
|
const { updateCurrentView } = useUpdateCurrentView();
|
||||||
|
|
||||||
const [isCompactModeActive, setIsCompactModeActive] =
|
const [isCompactModeActive, setIsCompactModeActive] =
|
||||||
useRecoilComponentStateV2(
|
useRecoilComponentStateV2(
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export const useRecordGroupReorder = ({
|
|||||||
viewBarId,
|
viewBarId,
|
||||||
viewType,
|
viewType,
|
||||||
}: UseRecordGroupHandlersParams) => {
|
}: UseRecordGroupHandlersParams) => {
|
||||||
const setRecordGroup = useSetRecordGroup(viewBarId);
|
const setRecordGroup = useSetRecordGroup();
|
||||||
|
|
||||||
const visibleRecordGroupIdsFamilySelector = useRecoilComponentCallbackStateV2(
|
const visibleRecordGroupIdsFamilySelector = useRecoilComponentCallbackStateV2(
|
||||||
visibleRecordGroupIdsComponentFamilySelector,
|
visibleRecordGroupIdsComponentFamilySelector,
|
||||||
@ -78,7 +78,7 @@ export const useRecordGroupReorder = ({
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
setRecordGroup(updatedRecordGroups);
|
setRecordGroup(updatedRecordGroups, viewBarId);
|
||||||
saveViewGroups(
|
saveViewGroups(
|
||||||
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups),
|
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups),
|
||||||
);
|
);
|
||||||
@ -86,6 +86,7 @@ export const useRecordGroupReorder = ({
|
|||||||
[
|
[
|
||||||
saveViewGroups,
|
saveViewGroups,
|
||||||
setRecordGroup,
|
setRecordGroup,
|
||||||
|
viewBarId,
|
||||||
viewType,
|
viewType,
|
||||||
visibleRecordGroupIdsFamilySelector,
|
visibleRecordGroupIdsFamilySelector,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,32 +1,33 @@
|
|||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
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 { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
|
||||||
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 { 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 = () => {
|
||||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
|
||||||
|
|
||||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
|
||||||
recordGroupIdsComponentState,
|
|
||||||
viewId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
|
|
||||||
recordGroupFieldMetadataComponentState,
|
|
||||||
viewId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return useRecoilCallback(
|
return useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
(recordGroups: RecordGroupDefinition[]) => {
|
(recordGroups: RecordGroupDefinition[], recordIndexId: string) => {
|
||||||
|
const objectMetadataItem = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
contextStoreCurrentObjectMetadataItemComponentState.atomFamily({
|
||||||
|
instanceId: 'main-context-store',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (!objectMetadataItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentRecordGroupIds = getSnapshotValue(
|
const currentRecordGroupIds = getSnapshotValue(
|
||||||
snapshot,
|
snapshot,
|
||||||
recordIndexRecordGroupIdsState,
|
recordGroupIdsComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
|
const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
|
||||||
const fieldMetadata = fieldMetadataId
|
const fieldMetadata = fieldMetadataId
|
||||||
@ -36,12 +37,19 @@ export const useSetRecordGroup = (viewId?: string) => {
|
|||||||
: undefined;
|
: undefined;
|
||||||
const currentFieldMetadata = getSnapshotValue(
|
const currentFieldMetadata = getSnapshotValue(
|
||||||
snapshot,
|
snapshot,
|
||||||
recordGroupFieldMetadataState,
|
recordGroupFieldMetadataComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set the field metadata linked to the record groups
|
// Set the field metadata linked to the record groups
|
||||||
if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) {
|
if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) {
|
||||||
set(recordGroupFieldMetadataState, fieldMetadata);
|
set(
|
||||||
|
recordGroupFieldMetadataComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
|
fieldMetadata,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the record groups by id
|
// Set the record groups by id
|
||||||
@ -75,12 +83,13 @@ export const useSetRecordGroup = (viewId?: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the record group ids
|
// Set the record group ids
|
||||||
set(recordIndexRecordGroupIdsState, recordGroupIds);
|
set(
|
||||||
|
recordGroupIdsComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
|
recordGroupIds,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[
|
[],
|
||||||
objectMetadataItem.fields,
|
|
||||||
recordGroupFieldMetadataState,
|
|
||||||
recordIndexRecordGroupIdsState,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,52 +1,26 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
|
||||||
import { ObjectOptionsDropdown } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdown';
|
import { ObjectOptionsDropdown } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdown';
|
||||||
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
|
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
|
||||||
import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader';
|
import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader';
|
||||||
import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect';
|
import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect';
|
||||||
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
||||||
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
||||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
|
||||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
|
||||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
|
||||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
|
||||||
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 { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
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 { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||||
|
|
||||||
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
||||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
|
||||||
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
|
||||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
|
||||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||||
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
|
||||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
|
||||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
|
||||||
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { ViewBar } from '@/views/components/ViewBar';
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
import { ViewField } from '@/views/types/ViewField';
|
|
||||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
|
||||||
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
|
||||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -64,9 +38,7 @@ const StyledContainerWithPadding = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordIndexContainer = () => {
|
export const RecordIndexContainer = () => {
|
||||||
const [recordIndexViewType, setRecordIndexViewType] = useRecoilState(
|
const [recordIndexViewType] = useRecoilState(recordIndexViewTypeState);
|
||||||
recordIndexViewTypeState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
@ -75,128 +47,12 @@ export const RecordIndexContainer = () => {
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
} = useRecordIndexContextOrThrow();
|
} = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
|
||||||
|
|
||||||
const { columnDefinitions, sortDefinitions } =
|
|
||||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
|
||||||
|
|
||||||
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
|
||||||
recordIndexViewFilterGroupsState,
|
|
||||||
);
|
|
||||||
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
|
||||||
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
|
||||||
const setRecordIndexIsCompactModeActive = useSetRecoilState(
|
|
||||||
recordIndexIsCompactModeActiveState,
|
|
||||||
);
|
|
||||||
const setRecordIndexViewKanbanFieldMetadataIdState = useSetRecoilState(
|
|
||||||
recordIndexKanbanFieldMetadataIdState,
|
|
||||||
);
|
|
||||||
const setRecordIndexViewKanbanAggregateOperationState = useSetRecoilState(
|
|
||||||
recordIndexKanbanAggregateOperationState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
setTableViewFilterGroups,
|
|
||||||
setTableFilters,
|
|
||||||
setTableSorts,
|
|
||||||
setTableColumns,
|
|
||||||
} = useRecordTable({
|
|
||||||
recordTableId: recordIndexId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onViewFieldsChange = useRecoilCallback(
|
|
||||||
({ set, snapshot }) =>
|
|
||||||
(viewFields: ViewField[]) => {
|
|
||||||
const newFieldDefinitions = mapViewFieldsToColumnDefinitions({
|
|
||||||
viewFields,
|
|
||||||
columnDefinitions,
|
|
||||||
});
|
|
||||||
|
|
||||||
setTableColumns(newFieldDefinitions);
|
|
||||||
|
|
||||||
const existingRecordIndexFieldDefinitions = snapshot
|
|
||||||
.getLoadable(recordIndexFieldDefinitionsState)
|
|
||||||
.getValue();
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isDeeplyEqual(
|
|
||||||
existingRecordIndexFieldDefinitions,
|
|
||||||
newFieldDefinitions,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
set(recordIndexFieldDefinitionsState, newFieldDefinitions);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const viewField of viewFields) {
|
|
||||||
const viewFieldMetadataType = objectMetadataItem.fields?.find(
|
|
||||||
(field) => field.id === viewField.fieldMetadataId,
|
|
||||||
)?.type;
|
|
||||||
const aggregateOperationForViewField = snapshot
|
|
||||||
.getLoadable(
|
|
||||||
viewFieldAggregateOperationState({
|
|
||||||
viewFieldId: viewField.id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.getValue();
|
|
||||||
|
|
||||||
const convertedViewFieldAggregateOperation = isDefined(
|
|
||||||
viewField.aggregateOperation,
|
|
||||||
)
|
|
||||||
? convertAggregateOperationToExtendedAggregateOperation(
|
|
||||||
viewField.aggregateOperation,
|
|
||||||
viewFieldMetadataType,
|
|
||||||
)
|
|
||||||
: viewField.aggregateOperation;
|
|
||||||
|
|
||||||
if (
|
|
||||||
aggregateOperationForViewField !==
|
|
||||||
convertedViewFieldAggregateOperation
|
|
||||||
) {
|
|
||||||
set(
|
|
||||||
viewFieldAggregateOperationState({
|
|
||||||
viewFieldId: viewField.id,
|
|
||||||
}),
|
|
||||||
convertedViewFieldAggregateOperation,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[columnDefinitions, objectMetadataItem.fields, setTableColumns],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onViewGroupsChange = useCallback(
|
|
||||||
(viewGroups: ViewGroup[]) => {
|
|
||||||
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
|
||||||
objectMetadataItem,
|
|
||||||
viewGroups,
|
|
||||||
});
|
|
||||||
|
|
||||||
setRecordGroup(newGroupDefinitions);
|
|
||||||
},
|
|
||||||
[objectMetadataItem, setRecordGroup],
|
|
||||||
);
|
|
||||||
|
|
||||||
const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2(
|
|
||||||
contextStoreTargetedRecordsRuleComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
|
||||||
objectMetadataItem.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ContextStoreCurrentViewTypeEffect
|
|
||||||
viewType={
|
|
||||||
recordIndexViewType === ViewType.Table
|
|
||||||
? ContextStoreViewType.Table
|
|
||||||
: ContextStoreViewType.Kanban
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<InformationBannerWrapper />
|
<InformationBannerWrapper />
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<RecordFieldValueSelectorContextProvider>
|
||||||
@ -210,60 +66,6 @@ export const RecordIndexContainer = () => {
|
|||||||
viewType={recordIndexViewType ?? ViewType.Table}
|
viewType={recordIndexViewType ?? ViewType.Table}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onCurrentViewChange={(view) => {
|
|
||||||
if (!view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onViewFieldsChange(view.viewFields);
|
|
||||||
onViewGroupsChange(view.viewGroups);
|
|
||||||
setTableViewFilterGroups(view.viewFilterGroups ?? []);
|
|
||||||
setTableFilters(
|
|
||||||
mapViewFiltersToFilters(
|
|
||||||
view.viewFilters,
|
|
||||||
filterableFieldMetadataItems,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
setRecordIndexFilters(
|
|
||||||
mapViewFiltersToFilters(
|
|
||||||
view.viewFilters,
|
|
||||||
filterableFieldMetadataItems,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
|
||||||
setContextStoreTargetedRecordsRule((prev) => ({
|
|
||||||
...prev,
|
|
||||||
filters: mapViewFiltersToFilters(
|
|
||||||
view.viewFilters,
|
|
||||||
filterableFieldMetadataItems,
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
setTableSorts(
|
|
||||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
|
||||||
);
|
|
||||||
setRecordIndexSorts(
|
|
||||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
|
||||||
);
|
|
||||||
setRecordIndexViewType(view.type);
|
|
||||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
|
||||||
view.kanbanFieldMetadataId,
|
|
||||||
);
|
|
||||||
const kanbanAggregateOperationFieldMetadataType =
|
|
||||||
objectMetadataItem.fields?.find(
|
|
||||||
(field) =>
|
|
||||||
field.id === view.kanbanAggregateOperationFieldMetadataId,
|
|
||||||
)?.type;
|
|
||||||
setRecordIndexViewKanbanAggregateOperationState({
|
|
||||||
operation: isDefined(view.kanbanAggregateOperation)
|
|
||||||
? convertAggregateOperationToExtendedAggregateOperation(
|
|
||||||
view.kanbanAggregateOperation,
|
|
||||||
kanbanAggregateOperationFieldMetadataType,
|
|
||||||
)
|
|
||||||
: view.kanbanAggregateOperation,
|
|
||||||
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
|
||||||
});
|
|
||||||
setRecordIndexIsCompactModeActive(view.isCompact);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<RecordIndexViewBarEffect
|
<RecordIndexViewBarEffect
|
||||||
objectNamePlural={objectNamePlural}
|
objectNamePlural={objectNamePlural}
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
export const RecordIndexContainerContextStoreObjectMetadataEffect = () => {
|
|
||||||
const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2(
|
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
|
||||||
);
|
|
||||||
const { objectNamePlural } = useRecordIndexContextOrThrow();
|
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
|
||||||
objectNamePlural,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setContextStoreCurrentObjectMetadataItem(objectMetadataItem.id);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
setContextStoreCurrentObjectMetadataItem(null);
|
|
||||||
};
|
|
||||||
}, [objectMetadataItem.id, setContextStoreCurrentObjectMetadataItem]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
|
||||||
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
|
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||||
|
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||||
|
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||||
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
|
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
||||||
|
import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect';
|
||||||
|
import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect';
|
||||||
|
import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader';
|
||||||
|
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||||
|
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||||
|
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
|
import { capitalize } from 'twenty-shared';
|
||||||
|
|
||||||
|
const StyledIndexContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RecordIndexContainerGater = () => {
|
||||||
|
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||||
|
mainContextStoreComponentInstanceIdState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
mainContextStoreComponentInstanceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||||
|
|
||||||
|
const recordIndexId = `${objectMetadataItem.namePlural}-${contextStoreCurrentViewId}`;
|
||||||
|
|
||||||
|
const handleIndexRecordsLoaded = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
() => {
|
||||||
|
// TODO: find a better way to reset this state ?
|
||||||
|
set(lastShowPageRecordIdState, null);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { indexIdentifierUrl } = useHandleIndexIdentifierClick({
|
||||||
|
objectMetadataItem,
|
||||||
|
recordIndexId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RecordIndexContextProvider
|
||||||
|
value={{
|
||||||
|
recordIndexId,
|
||||||
|
objectNamePlural: objectMetadataItem.namePlural,
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
objectMetadataItem,
|
||||||
|
onIndexRecordsLoaded: handleIndexRecordsLoaded,
|
||||||
|
indexIdentifierUrl,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ViewComponentInstanceContext.Provider
|
||||||
|
value={{ instanceId: recordIndexId }}
|
||||||
|
>
|
||||||
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
|
value={{ instanceId: recordIndexId }}
|
||||||
|
>
|
||||||
|
<ActionMenuComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PageTitle
|
||||||
|
title={`${capitalize(objectMetadataItem.namePlural)}`}
|
||||||
|
/>
|
||||||
|
<RecordIndexPageHeader />
|
||||||
|
<PageBody>
|
||||||
|
<StyledIndexContainer>
|
||||||
|
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||||
|
<RecordIndexContainer />
|
||||||
|
</StyledIndexContainer>
|
||||||
|
</PageBody>
|
||||||
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
|
<RecordIndexLoadBaseOnContextStoreEffect />
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordIndexContextProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||||
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const RecordIndexLoadBaseOnContextStoreEffect = () => {
|
||||||
|
const { loadRecordIndexStates } = useLoadRecordIndexStates();
|
||||||
|
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [loadedViewId, setLoadedViewId] = useState<string | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const view = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: contextStoreCurrentViewId ?? '',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectMetadataItem = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loadedViewId === contextStoreCurrentViewId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDefined(objectMetadataItem)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(view)) {
|
||||||
|
loadRecordIndexStates(view, objectMetadataItem);
|
||||||
|
setLoadedViewId(contextStoreCurrentViewId);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
contextStoreCurrentViewId,
|
||||||
|
loadRecordIndexStates,
|
||||||
|
loadedViewId,
|
||||||
|
objectMetadataItem,
|
||||||
|
view,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
@ -1,7 +1,7 @@
|
|||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||||
|
|
||||||
export const useHandleIndexIdentifierClick = ({
|
export const useHandleIndexIdentifierClick = ({
|
||||||
@ -12,7 +12,7 @@ export const useHandleIndexIdentifierClick = ({
|
|||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
}) => {
|
}) => {
|
||||||
const currentViewId = useRecoilComponentValueV2(
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
recordIndexId,
|
recordIndexId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,22 @@
|
|||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
||||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
type UseHandleRecordGroupFieldParams = {
|
export const useHandleRecordGroupField = () => {
|
||||||
viewBarComponentId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useHandleRecordGroupField = ({
|
|
||||||
viewBarComponentId,
|
|
||||||
}: UseHandleRecordGroupFieldParams) => {
|
|
||||||
const { createViewGroupRecords, deleteViewGroupRecords } =
|
const { createViewGroupRecords, deleteViewGroupRecords } =
|
||||||
usePersistViewGroupRecords();
|
usePersistViewGroupRecords();
|
||||||
|
|
||||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
viewBarComponentId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getViewFromCache } = useGetViewFromCache();
|
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||||
|
|
||||||
const handleRecordGroupFieldChange = useRecoilCallback(
|
const handleRecordGroupFieldChange = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
@ -36,7 +29,7 @@ export const useHandleRecordGroupField = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = await getViewFromCache(currentViewId);
|
const view = await getViewFromPrefetchState(currentViewId);
|
||||||
|
|
||||||
if (isUndefinedOrNull(view)) {
|
if (isUndefinedOrNull(view)) {
|
||||||
return;
|
return;
|
||||||
@ -105,7 +98,7 @@ export const useHandleRecordGroupField = ({
|
|||||||
createViewGroupRecords,
|
createViewGroupRecords,
|
||||||
deleteViewGroupRecords,
|
deleteViewGroupRecords,
|
||||||
currentViewIdCallbackState,
|
currentViewIdCallbackState,
|
||||||
getViewFromCache,
|
getViewFromPrefetchState,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -120,7 +113,7 @@ export const useHandleRecordGroupField = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = await getViewFromCache(currentViewId);
|
const view = await getViewFromPrefetchState(currentViewId);
|
||||||
|
|
||||||
if (isUndefinedOrNull(view)) {
|
if (isUndefinedOrNull(view)) {
|
||||||
return;
|
return;
|
||||||
@ -132,7 +125,11 @@ export const useHandleRecordGroupField = ({
|
|||||||
|
|
||||||
await deleteViewGroupRecords(view.viewGroups);
|
await deleteViewGroupRecords(view.viewGroups);
|
||||||
},
|
},
|
||||||
[deleteViewGroupRecords, currentViewIdCallbackState, getViewFromCache],
|
[
|
||||||
|
deleteViewGroupRecords,
|
||||||
|
currentViewIdCallbackState,
|
||||||
|
getViewFromPrefetchState,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { handleRecordGroupFieldChange, resetRecordGroupField };
|
return { handleRecordGroupFieldChange, resetRecordGroupField };
|
||||||
|
|||||||
@ -6,13 +6,14 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
|||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
||||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
|
||||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
type UseLoadRecordIndexBoardProps = {
|
type UseLoadRecordIndexBoardProps = {
|
||||||
@ -41,14 +42,16 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
const recordIndexViewFilterGroups = useRecoilValue(
|
const recordIndexViewFilterGroups = useRecoilValue(
|
||||||
recordIndexViewFilterGroupsState,
|
recordIndexViewFilterGroupsState,
|
||||||
);
|
);
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const currentRecordFilters = useRecoilComponentValueV2(
|
||||||
|
currentRecordFiltersComponentState,
|
||||||
|
);
|
||||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||||
|
|
||||||
const { filterValueDependencies } = useFilterValueDependencies();
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||||
filterValueDependencies,
|
filterValueDependencies,
|
||||||
recordIndexFilters,
|
currentRecordFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -0,0 +1,281 @@
|
|||||||
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
|
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||||
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||||
|
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||||
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
|
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||||
|
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||||
|
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||||
|
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||||
|
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||||
|
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||||
|
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||||
|
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||||
|
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||||
|
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
|
||||||
|
import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
|
||||||
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
|
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
||||||
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { ViewField } from '@/views/types/ViewField';
|
||||||
|
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||||
|
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||||
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
|
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
||||||
|
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const useLoadRecordIndexStates = () => {
|
||||||
|
const setContextStoreTargetedRecordsRuleComponentState =
|
||||||
|
useSetRecoilComponentStateV2(contextStoreTargetedRecordsRuleComponentState);
|
||||||
|
|
||||||
|
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
||||||
|
recordIndexViewFilterGroupsState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
||||||
|
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
||||||
|
const setRecordIndexIsCompactModeActive = useSetRecoilState(
|
||||||
|
recordIndexIsCompactModeActiveState,
|
||||||
|
);
|
||||||
|
const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState);
|
||||||
|
const setRecordIndexViewKanbanFieldMetadataIdState = useSetRecoilState(
|
||||||
|
recordIndexKanbanFieldMetadataIdState,
|
||||||
|
);
|
||||||
|
const setRecordIndexViewKanbanAggregateOperationState = useSetRecoilState(
|
||||||
|
recordIndexKanbanAggregateOperationState,
|
||||||
|
);
|
||||||
|
const setRecordGroup = useSetRecordGroup();
|
||||||
|
|
||||||
|
const { setTableColumns } = useSetTableColumns();
|
||||||
|
|
||||||
|
const onViewFieldsChange = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
(
|
||||||
|
viewFields: ViewField[],
|
||||||
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
|
recordIndexId: string,
|
||||||
|
) => {
|
||||||
|
const activeFieldMetadataItems = objectMetadataItem.fields.filter(
|
||||||
|
({ isActive, isSystem }) => isActive && !isSystem,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterableFieldMetadataItems = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||||
|
fields: activeFieldMetadataItems,
|
||||||
|
});
|
||||||
|
|
||||||
|
const columnDefinitions: ColumnDefinition<FieldMetadata>[] =
|
||||||
|
activeFieldMetadataItems
|
||||||
|
.map((field, index) =>
|
||||||
|
formatFieldMetadataItemAsColumnDefinition({
|
||||||
|
position: index,
|
||||||
|
field,
|
||||||
|
objectMetadataItem,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.filter(filterAvailableTableColumns)
|
||||||
|
.map((column) => {
|
||||||
|
const existsInFilterDefinitions =
|
||||||
|
filterableFieldMetadataItems.some(
|
||||||
|
(fieldMetadataItem) =>
|
||||||
|
fieldMetadataItem.id === column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
const existsInSortDefinitions = sortDefinitions.some(
|
||||||
|
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
isFilterable: existsInFilterDefinitions,
|
||||||
|
isSortable: existsInSortDefinitions,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const newFieldDefinitions = mapViewFieldsToColumnDefinitions({
|
||||||
|
viewFields,
|
||||||
|
columnDefinitions,
|
||||||
|
});
|
||||||
|
|
||||||
|
setTableColumns(newFieldDefinitions, recordIndexId);
|
||||||
|
|
||||||
|
const existingRecordIndexFieldDefinitions = snapshot
|
||||||
|
.getLoadable(recordIndexFieldDefinitionsState)
|
||||||
|
.getValue();
|
||||||
|
if (
|
||||||
|
!isDeeplyEqual(
|
||||||
|
existingRecordIndexFieldDefinitions,
|
||||||
|
newFieldDefinitions,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
set(recordIndexFieldDefinitionsState, newFieldDefinitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const viewField of viewFields) {
|
||||||
|
const viewFieldMetadataType = objectMetadataItem.fields?.find(
|
||||||
|
(field) => field.id === viewField.fieldMetadataId,
|
||||||
|
)?.type;
|
||||||
|
|
||||||
|
const aggregateOperationForViewField = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
viewFieldAggregateOperationState({
|
||||||
|
viewFieldId: viewField.id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
const convertedViewFieldAggregateOperation = isDefined(
|
||||||
|
viewField.aggregateOperation,
|
||||||
|
)
|
||||||
|
? convertAggregateOperationToExtendedAggregateOperation(
|
||||||
|
viewField.aggregateOperation,
|
||||||
|
viewFieldMetadataType,
|
||||||
|
)
|
||||||
|
: viewField.aggregateOperation;
|
||||||
|
|
||||||
|
if (
|
||||||
|
aggregateOperationForViewField !==
|
||||||
|
convertedViewFieldAggregateOperation
|
||||||
|
) {
|
||||||
|
set(
|
||||||
|
viewFieldAggregateOperationState({
|
||||||
|
viewFieldId: viewField.id,
|
||||||
|
}),
|
||||||
|
convertedViewFieldAggregateOperation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setTableColumns],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onViewGroupsChange = useCallback(
|
||||||
|
(
|
||||||
|
viewGroups: ViewGroup[],
|
||||||
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
|
recordIndexId: string,
|
||||||
|
) => {
|
||||||
|
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
||||||
|
objectMetadataItem,
|
||||||
|
viewGroups,
|
||||||
|
});
|
||||||
|
|
||||||
|
setRecordGroup(newGroupDefinitions, recordIndexId);
|
||||||
|
},
|
||||||
|
[setRecordGroup],
|
||||||
|
);
|
||||||
|
|
||||||
|
const loadRecordIndexStates = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (view: View, objectMetadataItem: ObjectMetadataItem) => {
|
||||||
|
const recordIndexId = `${objectMetadataItem.namePlural}-${view.id}`;
|
||||||
|
|
||||||
|
const filterableFieldMetadataItems = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
onViewFieldsChange(view.viewFields, objectMetadataItem, recordIndexId);
|
||||||
|
onViewGroupsChange(view.viewGroups, objectMetadataItem, recordIndexId);
|
||||||
|
set(
|
||||||
|
tableViewFilterGroupsComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
|
view.viewFilterGroups ?? [],
|
||||||
|
);
|
||||||
|
set(
|
||||||
|
tableFiltersComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
|
mapViewFiltersToFilters(
|
||||||
|
view.viewFilters,
|
||||||
|
filterableFieldMetadataItems,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setRecordIndexFilters(
|
||||||
|
mapViewFiltersToFilters(
|
||||||
|
view.viewFilters,
|
||||||
|
filterableFieldMetadataItems,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
||||||
|
setContextStoreTargetedRecordsRuleComponentState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
filters: mapViewFiltersToFilters(
|
||||||
|
view.viewFilters,
|
||||||
|
filterableFieldMetadataItems,
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const activeFieldMetadataItems = objectMetadataItem.fields.filter(
|
||||||
|
({ isActive, isSystem }) => isActive && !isSystem,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||||
|
fields: activeFieldMetadataItems,
|
||||||
|
});
|
||||||
|
|
||||||
|
set(
|
||||||
|
tableSortsComponentState.atomFamily({
|
||||||
|
instanceId: recordIndexId,
|
||||||
|
}),
|
||||||
|
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||||
|
);
|
||||||
|
setRecordIndexSorts(
|
||||||
|
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||||
|
);
|
||||||
|
setRecordIndexViewType(view.type);
|
||||||
|
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||||
|
view.kanbanFieldMetadataId,
|
||||||
|
);
|
||||||
|
const kanbanAggregateOperationFieldMetadataType =
|
||||||
|
objectMetadataItem.fields?.find(
|
||||||
|
(field) =>
|
||||||
|
field.id === view.kanbanAggregateOperationFieldMetadataId,
|
||||||
|
)?.type;
|
||||||
|
setRecordIndexViewKanbanAggregateOperationState({
|
||||||
|
operation: isDefined(view.kanbanAggregateOperation)
|
||||||
|
? convertAggregateOperationToExtendedAggregateOperation(
|
||||||
|
view.kanbanAggregateOperation,
|
||||||
|
kanbanAggregateOperationFieldMetadataType,
|
||||||
|
)
|
||||||
|
: view.kanbanAggregateOperation,
|
||||||
|
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
||||||
|
});
|
||||||
|
setRecordIndexIsCompactModeActive(view.isCompact);
|
||||||
|
},
|
||||||
|
[
|
||||||
|
onViewFieldsChange,
|
||||||
|
onViewGroupsChange,
|
||||||
|
setContextStoreTargetedRecordsRuleComponentState,
|
||||||
|
setRecordIndexFilters,
|
||||||
|
setRecordIndexIsCompactModeActive,
|
||||||
|
setRecordIndexSorts,
|
||||||
|
setRecordIndexViewFilterGroups,
|
||||||
|
setRecordIndexViewKanbanAggregateOperationState,
|
||||||
|
setRecordIndexViewKanbanFieldMetadataIdState,
|
||||||
|
setRecordIndexViewType,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadRecordIndexStates,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -3,9 +3,6 @@ import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer
|
|||||||
|
|
||||||
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
|
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
|
||||||
|
|
||||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
|
||||||
import { RecordShowContainerContextStoreObjectMetadataIdEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreObjectMetadataIdEffect';
|
|
||||||
import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect';
|
import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect';
|
||||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||||
import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs';
|
import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs';
|
||||||
@ -45,16 +42,9 @@ export const RecordShowContainer = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RecordShowContainerContextStoreObjectMetadataIdEffect
|
|
||||||
recordId={objectRecordId}
|
|
||||||
objectNameSingular={objectNameSingular}
|
|
||||||
/>
|
|
||||||
<RecordShowContainerContextStoreTargetedRecordsEffect
|
<RecordShowContainerContextStoreTargetedRecordsEffect
|
||||||
recordId={objectRecordId}
|
recordId={objectRecordId}
|
||||||
/>
|
/>
|
||||||
<ContextStoreCurrentViewTypeEffect
|
|
||||||
viewType={ContextStoreViewType.ShowPage}
|
|
||||||
/>
|
|
||||||
{recordFromStore && recordFromStore.deletedAt && (
|
{recordFromStore && recordFromStore.deletedAt && (
|
||||||
<InformationBannerDeletedRecord
|
<InformationBannerDeletedRecord
|
||||||
recordId={objectRecordId}
|
recordId={objectRecordId}
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
export const RecordShowContainerContextStoreObjectMetadataIdEffect = ({
|
|
||||||
recordId,
|
|
||||||
objectNameSingular,
|
|
||||||
}: {
|
|
||||||
recordId: string;
|
|
||||||
objectNameSingular: string;
|
|
||||||
}) => {
|
|
||||||
const setContextStoreCurrentObjectMetadataId = useSetRecoilComponentStateV2(
|
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular: objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
setContextStoreCurrentObjectMetadataId(null);
|
|
||||||
};
|
|
||||||
}, [recordId, setContextStoreCurrentObjectMetadataId, objectMetadataItem.id]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@ -39,7 +39,6 @@ export const useRecordShowPagePagination = (
|
|||||||
const { filter, orderBy } =
|
const { filter, orderBy } =
|
||||||
useQueryVariablesFromActiveFieldsOfViewOrDefaultView({
|
useQueryVariablesFromActiveFieldsOfViewOrDefaultView({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
viewId: viewIdQueryParam,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { loading: loadingCursor, pageInfo: currentRecordsPageInfo } =
|
const { loading: loadingCursor, pageInfo: currentRecordsPageInfo } =
|
||||||
|
|||||||
@ -23,14 +23,12 @@ import { useRecordPicker } from '@/object-record/relation-picker/hooks/useRecord
|
|||||||
import { RecordPickerComponentInstanceContext } from '@/object-record/relation-picker/states/contexts/RecordPickerComponentInstanceContext';
|
import { RecordPickerComponentInstanceContext } from '@/object-record/relation-picker/states/contexts/RecordPickerComponentInstanceContext';
|
||||||
import { RecordForSelect } from '@/object-record/relation-picker/types/RecordForSelect';
|
import { RecordForSelect } from '@/object-record/relation-picker/types/RecordForSelect';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
||||||
@ -123,12 +121,10 @@ export const RecordDetailRelationSection = ({
|
|||||||
scopeId: dropdownId,
|
scopeId: dropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const indexViewId = useRecoilValue(
|
||||||
|
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||||
const indexView = views.find(
|
objectMetadataItemId: relationObjectMetadataItem.id,
|
||||||
(view) =>
|
}),
|
||||||
view.key === 'INDEX' &&
|
|
||||||
view.objectMetadataId === relationObjectMetadataItem.id,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterQueryParams = {
|
const filterQueryParams = {
|
||||||
@ -139,7 +135,7 @@ export const RecordDetailRelationSection = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
view: indexView?.id,
|
view: indexViewId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterLinkHref = getAppPath(
|
const filterLinkHref = getAppPath(
|
||||||
|
|||||||
@ -75,7 +75,7 @@ export const RecordTableWithWrappers = ({
|
|||||||
ActionBarHotkeyScope.ActionBar,
|
ActionBarHotkeyScope.ActionBar,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
const { saveViewFields } = useSaveCurrentViewFields();
|
||||||
|
|
||||||
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
||||||
|
|
||||||
|
|||||||
@ -22,11 +22,9 @@ 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 { 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';
|
||||||
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
|
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
|
||||||
import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
|
|
||||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
@ -53,11 +51,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableColumnsState = useRecoilComponentCallbackStateV2(
|
|
||||||
tableColumnsComponentState,
|
|
||||||
recordTableId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setAvailableTableColumns = useRecoilCallback(
|
const setAvailableTableColumns = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
(columns: ColumnDefinition<FieldMetadata>[]) => {
|
(columns: ColumnDefinition<FieldMetadata>[]) => {
|
||||||
@ -74,29 +67,11 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
|||||||
[availableTableColumnsState],
|
[availableTableColumnsState],
|
||||||
);
|
);
|
||||||
|
|
||||||
const setTableColumns = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
(columns: ColumnDefinition<FieldMetadata>[]) => {
|
|
||||||
const tableColumns = getSnapshotValue(snapshot, tableColumnsState);
|
|
||||||
|
|
||||||
if (isDeeplyEqual(tableColumns, columns)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
set(tableColumnsState, columns);
|
|
||||||
},
|
|
||||||
[tableColumnsState],
|
|
||||||
);
|
|
||||||
|
|
||||||
const setOnEntityCountChange = useSetRecoilComponentStateV2(
|
const setOnEntityCountChange = useSetRecoilComponentStateV2(
|
||||||
onEntityCountChangeComponentState,
|
onEntityCountChangeComponentState,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setTableViewFilterGroups = useSetRecoilComponentStateV2(
|
|
||||||
tableViewFilterGroupsComponentState,
|
|
||||||
recordTableId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setTableFilters = useSetRecoilComponentStateV2(
|
const setTableFilters = useSetRecoilComponentStateV2(
|
||||||
tableFiltersComponentState,
|
tableFiltersComponentState,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
@ -255,12 +230,10 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
|||||||
return {
|
return {
|
||||||
onColumnsChange,
|
onColumnsChange,
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setTableViewFilterGroups,
|
|
||||||
setTableFilters,
|
setTableFilters,
|
||||||
setTableSorts,
|
setTableSorts,
|
||||||
setOnEntityCountChange,
|
setOnEntityCountChange,
|
||||||
setRecordTableData,
|
setRecordTableData,
|
||||||
setTableColumns,
|
|
||||||
leaveTableFocus,
|
leaveTableFocus,
|
||||||
setRowSelected,
|
setRowSelected,
|
||||||
resetTableRowSelection,
|
resetTableRowSelection,
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const useSetTableColumns = () => {
|
||||||
|
const setTableColumns = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
(columns: ColumnDefinition<FieldMetadata>[], recordTableId: string) => {
|
||||||
|
const tableColumns = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
tableColumnsComponentState.atomFamily({
|
||||||
|
instanceId: recordTableId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDeeplyEqual(tableColumns, columns)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set(
|
||||||
|
tableColumnsComponentState.atomFamily({
|
||||||
|
instanceId: recordTableId,
|
||||||
|
}),
|
||||||
|
columns,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { setTableColumns };
|
||||||
|
};
|
||||||
@ -4,9 +4,12 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
|
|||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
||||||
|
|
||||||
|
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||||
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
|
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
|
||||||
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ColumnDefinition } from '../types/ColumnDefinition';
|
import { ColumnDefinition } from '../types/ColumnDefinition';
|
||||||
|
|
||||||
@ -15,10 +18,12 @@ type useRecordTableProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useTableColumns = (props?: useRecordTableProps) => {
|
export const useTableColumns = (props?: useRecordTableProps) => {
|
||||||
const { onColumnsChange, setTableColumns } = useRecordTable({
|
const { onColumnsChange } = useRecordTable({
|
||||||
recordTableId: props?.recordTableId,
|
recordTableId: props?.recordTableId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { setTableColumns } = useSetTableColumns();
|
||||||
|
|
||||||
const availableTableColumns = useRecoilComponentValueV2(
|
const availableTableColumns = useRecoilComponentValueV2(
|
||||||
availableTableColumnsComponentState,
|
availableTableColumnsComponentState,
|
||||||
props?.recordTableId,
|
props?.recordTableId,
|
||||||
@ -35,13 +40,18 @@ export const useTableColumns = (props?: useRecordTableProps) => {
|
|||||||
|
|
||||||
const { handleColumnMove } = useMoveViewColumns();
|
const { handleColumnMove } = useMoveViewColumns();
|
||||||
|
|
||||||
|
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordTableComponentInstanceContext,
|
||||||
|
props?.recordTableId,
|
||||||
|
);
|
||||||
|
|
||||||
const handleColumnsChange = useCallback(
|
const handleColumnsChange = useCallback(
|
||||||
async (columns: ColumnDefinition<FieldMetadata>[]) => {
|
async (columns: ColumnDefinition<FieldMetadata>[]) => {
|
||||||
setTableColumns(columns);
|
setTableColumns(columns, instanceId);
|
||||||
|
|
||||||
await onColumnsChange?.(columns);
|
await onColumnsChange?.(columns);
|
||||||
},
|
},
|
||||||
[onColumnsChange, setTableColumns],
|
[setTableColumns, instanceId, onColumnsChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleColumnVisibilityChange = useCallback(
|
const handleColumnVisibilityChange = useCallback(
|
||||||
|
|||||||
@ -55,6 +55,8 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
|||||||
lastShowPageRecordIdState,
|
lastShowPageRecordIdState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [hasInitialized, setHasInitialized] = useState(false);
|
||||||
|
|
||||||
const { scrollToPosition } = useScrollToPosition();
|
const { scrollToPosition } = useScrollToPosition();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -141,8 +143,11 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
findManyRecords();
|
if (!hasInitialized) {
|
||||||
}, [currentWorkspaceMember, findManyRecords]);
|
findManyRecords();
|
||||||
|
setHasInitialized(true);
|
||||||
|
}
|
||||||
|
}, [currentWorkspaceMember, findManyRecords, hasInitialized]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { PrefetchRunQueriesEffect } from '@/prefetch/components/PrefetchRunQueriesEffect';
|
import { PrefetchRunFavoriteQueriesEffect } from '@/prefetch/components/PrefetchRunFavoriteQueriesEffect';
|
||||||
|
import { PrefetchRunViewQueryEffect } from '@/prefetch/components/PrefetchRunViewQueryEffect';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const PrefetchDataProvider = ({ children }: React.PropsWithChildren) => {
|
export const PrefetchDataProvider = ({ children }: React.PropsWithChildren) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PrefetchRunQueriesEffect />
|
<PrefetchRunFavoriteQueriesEffect />
|
||||||
|
<PrefetchRunViewQueryEffect />
|
||||||
{children}
|
{children}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -0,0 +1,110 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { Favorite } from '@/favorites/types/Favorite';
|
||||||
|
import { FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
||||||
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { findAllFavoritesFolderOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesFolderOperationSignatureFactory';
|
||||||
|
import { findAllFavoritesOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory';
|
||||||
|
import { prefetchFavoriteFoldersState } from '@/prefetch/states/prefetchFavoriteFoldersState';
|
||||||
|
import { prefetchFavoritesState } from '@/prefetch/states/prefetchFavoritesState';
|
||||||
|
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
|
||||||
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
|
import { useIsWorkspaceActivationStatusSuspended } from '@/workspace/hooks/useIsWorkspaceActivationStatusSuspended';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const PrefetchRunFavoriteQueriesEffect = () => {
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
|
const isWorkspaceSuspended = useIsWorkspaceActivationStatusSuspended();
|
||||||
|
|
||||||
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
|
|
||||||
|
const setIsPrefetchFavoritesLoaded = useSetRecoilState(
|
||||||
|
prefetchIsLoadedFamilyState(PrefetchKey.AllFavorites),
|
||||||
|
);
|
||||||
|
|
||||||
|
const setIsPrefetchFavoritesFoldersLoaded = useSetRecoilState(
|
||||||
|
prefetchIsLoadedFamilyState(PrefetchKey.AllFavoritesFolders),
|
||||||
|
);
|
||||||
|
|
||||||
|
const findAllFavoritesOperationSignature =
|
||||||
|
findAllFavoritesOperationSignatureFactory({
|
||||||
|
objectMetadataItem: objectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === CoreObjectNameSingular.Favorite,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const findAllFavoriteFoldersOperationSignature =
|
||||||
|
findAllFavoritesFolderOperationSignatureFactory({
|
||||||
|
objectMetadataItem: objectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === CoreObjectNameSingular.FavoriteFolder,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { records: favorites } = useFindManyRecords({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||||
|
filter: findAllFavoritesOperationSignature.variables.filter,
|
||||||
|
recordGqlFields: findAllFavoritesOperationSignature.fields,
|
||||||
|
skip: !currentUser || isWorkspaceSuspended,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { records: favoriteFolders } = useFindManyRecords({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.FavoriteFolder,
|
||||||
|
filter: findAllFavoriteFoldersOperationSignature.variables.filter,
|
||||||
|
recordGqlFields: findAllFavoriteFoldersOperationSignature.fields,
|
||||||
|
skip: !currentUser || isWorkspaceSuspended,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setPrefetchFavoritesState = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
(favorites: Favorite[]) => {
|
||||||
|
const existingFavorites = snapshot
|
||||||
|
.getLoadable(prefetchFavoritesState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(existingFavorites, favorites)) {
|
||||||
|
set(prefetchFavoritesState, favorites);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const setPrefetchFavoriteFoldersState = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
(favoriteFolders: FavoriteFolder[]) => {
|
||||||
|
const existingFavoriteFolders = snapshot
|
||||||
|
.getLoadable(prefetchFavoriteFoldersState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(existingFavoriteFolders, favoriteFolders)) {
|
||||||
|
set(prefetchFavoriteFoldersState, favoriteFolders);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isDefined(favorites)) {
|
||||||
|
setPrefetchFavoritesState(favorites as Favorite[]);
|
||||||
|
setIsPrefetchFavoritesLoaded(true);
|
||||||
|
}
|
||||||
|
}, [favorites, setPrefetchFavoritesState, setIsPrefetchFavoritesLoaded]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isDefined(favoriteFolders)) {
|
||||||
|
setPrefetchFavoriteFoldersState(favoriteFolders as FavoriteFolder[]);
|
||||||
|
setIsPrefetchFavoritesFoldersLoaded(true);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
favoriteFolders,
|
||||||
|
setPrefetchFavoriteFoldersState,
|
||||||
|
setIsPrefetchFavoritesFoldersLoaded,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import { useEffect } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { Favorite } from '@/favorites/types/Favorite';
|
|
||||||
import { FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
|
||||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
|
||||||
import { useCombinedFindManyRecords } from '@/object-record/multiple-objects/hooks/useCombinedFindManyRecords';
|
|
||||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
|
||||||
import { useUpsertRecordsInCacheForPrefetchKey } from '@/prefetch/hooks/internal/useUpsertRecordsInCacheForPrefetchKey';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useIsWorkspaceActivationStatusSuspended } from '@/workspace/hooks/useIsWorkspaceActivationStatusSuspended';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
export const PrefetchRunQueriesEffect = () => {
|
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
|
||||||
|
|
||||||
const isWorkspaceSuspended = useIsWorkspaceActivationStatusSuspended();
|
|
||||||
|
|
||||||
const { upsertRecordsInCache: upsertViewsInCache } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<View>({
|
|
||||||
prefetchKey: PrefetchKey.AllViews,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { upsertRecordsInCache: upsertFavoritesInCache } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<Favorite>({
|
|
||||||
prefetchKey: PrefetchKey.AllFavorites,
|
|
||||||
});
|
|
||||||
const { upsertRecordsInCache: upsertFavoritesFoldersInCache } =
|
|
||||||
useUpsertRecordsInCacheForPrefetchKey<FavoriteFolder>({
|
|
||||||
prefetchKey: PrefetchKey.AllFavoritesFolders,
|
|
||||||
});
|
|
||||||
const { objectMetadataItems } = useObjectMetadataItems();
|
|
||||||
|
|
||||||
const operationSignatures = Object.values(PREFETCH_CONFIG)
|
|
||||||
|
|
||||||
.map(({ objectNameSingular, operationSignatureFactory }) => {
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === objectNameSingular,
|
|
||||||
);
|
|
||||||
|
|
||||||
return operationSignatureFactory({ objectMetadataItem });
|
|
||||||
});
|
|
||||||
|
|
||||||
const { result } = useCombinedFindManyRecords({
|
|
||||||
operationSignatures,
|
|
||||||
skip: !currentUser || isWorkspaceSuspended,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isDefined(result.views)) {
|
|
||||||
upsertViewsInCache(result.views as View[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(result.favorites)) {
|
|
||||||
upsertFavoritesInCache(result.favorites as Favorite[]);
|
|
||||||
}
|
|
||||||
if (isDefined(result.favoriteFolders)) {
|
|
||||||
upsertFavoritesFoldersInCache(result.favoriteFolders as FavoriteFolder[]);
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
result,
|
|
||||||
upsertViewsInCache,
|
|
||||||
upsertFavoritesInCache,
|
|
||||||
upsertFavoritesFoldersInCache,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory';
|
||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { useIsWorkspaceActivationStatusSuspended } from '@/workspace/hooks/useIsWorkspaceActivationStatusSuspended';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const PrefetchRunViewQueryEffect = () => {
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
|
const isWorkspaceSuspended = useIsWorkspaceActivationStatusSuspended();
|
||||||
|
|
||||||
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
|
|
||||||
|
const findAllViewsOperationSignature = findAllViewsOperationSignatureFactory({
|
||||||
|
objectMetadataItem: objectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === CoreObjectNameSingular.View,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { records } = useFindManyRecords({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.View,
|
||||||
|
filter: findAllViewsOperationSignature.variables.filter,
|
||||||
|
recordGqlFields: findAllViewsOperationSignature.fields,
|
||||||
|
skip: !currentUser || isWorkspaceSuspended,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setPrefetchViewsState = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
(views: View[]) => {
|
||||||
|
const existingViews = snapshot
|
||||||
|
.getLoadable(prefetchViewsState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(existingViews, views)) {
|
||||||
|
set(prefetchViewsState, views);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const isPersistingViewFields = useRecoilValue(isPersistingViewFieldsState);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isDefined(records) && !isPersistingViewFields) {
|
||||||
|
setPrefetchViewsState(records as View[]);
|
||||||
|
}
|
||||||
|
}, [isPersistingViewFields, records, setPrefetchViewsState]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
@ -2,7 +2,6 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory';
|
import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory';
|
||||||
import { findAllFavoritesFolderOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesFolderOperationSignatureFactory';
|
import { findAllFavoritesFolderOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesFolderOperationSignatureFactory';
|
||||||
import { findAllFavoritesOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory';
|
import { findAllFavoritesOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory';
|
||||||
import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
|
|
||||||
export const PREFETCH_CONFIG: Record<
|
export const PREFETCH_CONFIG: Record<
|
||||||
@ -12,10 +11,6 @@ export const PREFETCH_CONFIG: Record<
|
|||||||
operationSignatureFactory: RecordGqlOperationSignatureFactory;
|
operationSignatureFactory: RecordGqlOperationSignatureFactory;
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
ALL_VIEWS: {
|
|
||||||
objectNameSingular: CoreObjectNameSingular.View,
|
|
||||||
operationSignatureFactory: findAllViewsOperationSignatureFactory,
|
|
||||||
},
|
|
||||||
ALL_FAVORITES: {
|
ALL_FAVORITES: {
|
||||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||||
operationSignatureFactory: findAllFavoritesOperationSignatureFactory,
|
operationSignatureFactory: findAllFavoritesOperationSignatureFactory,
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache';
|
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
|
||||||
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
|
|
||||||
export type UsePrefetchRunQuery = {
|
|
||||||
prefetchKey: PrefetchKey;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useUpsertRecordsInCacheForPrefetchKey = <T extends ObjectRecord>({
|
|
||||||
prefetchKey,
|
|
||||||
}: UsePrefetchRunQuery) => {
|
|
||||||
const setPrefetchDataIsLoaded = useSetRecoilState(
|
|
||||||
prefetchIsLoadedFamilyState(prefetchKey),
|
|
||||||
);
|
|
||||||
|
|
||||||
const { operationSignatureFactory, objectNameSingular } =
|
|
||||||
PREFETCH_CONFIG[prefetchKey];
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const operationSignature = operationSignatureFactory({ objectMetadataItem });
|
|
||||||
|
|
||||||
const { upsertFindManyRecordsQueryInCache } =
|
|
||||||
useUpsertFindManyRecordsQueryInCache({
|
|
||||||
objectMetadataItem: objectMetadataItem,
|
|
||||||
});
|
|
||||||
|
|
||||||
const upsertRecordsInCache = (records: T[]) => {
|
|
||||||
setPrefetchDataIsLoaded(false);
|
|
||||||
|
|
||||||
upsertFindManyRecordsQueryInCache({
|
|
||||||
queryVariables: operationSignature.variables,
|
|
||||||
recordGqlFields: operationSignature.fields,
|
|
||||||
objectRecordsToOverwrite: records,
|
|
||||||
computeReferences: false,
|
|
||||||
});
|
|
||||||
setPrefetchDataIsLoaded(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
objectMetadataItem,
|
|
||||||
upsertRecordsInCache,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -9,17 +9,12 @@ export const useIsPrefetchLoading = () => {
|
|||||||
prefetchIsLoadedFamilyState(PrefetchKey.AllFavoritesFolders),
|
prefetchIsLoadedFamilyState(PrefetchKey.AllFavoritesFolders),
|
||||||
);
|
);
|
||||||
|
|
||||||
const areViewsPrefetched = useRecoilValue(
|
|
||||||
prefetchIsLoadedFamilyState(PrefetchKey.AllViews),
|
|
||||||
);
|
|
||||||
const areFavoritesPrefetched = useRecoilValue(
|
const areFavoritesPrefetched = useRecoilValue(
|
||||||
prefetchIsLoadedFamilyState(PrefetchKey.AllFavorites),
|
prefetchIsLoadedFamilyState(PrefetchKey.AllFavorites),
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!isWorkspaceSuspended &&
|
!isWorkspaceSuspended &&
|
||||||
(!areViewsPrefetched ||
|
(!areFavoritesPrefetched || !isFavoriteFoldersPrefetched)
|
||||||
!areFavoritesPrefetched ||
|
|
||||||
!isFavoriteFoldersPrefetched)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
|
||||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
|
|
||||||
export const useLazyPrefetchedData = <T extends ObjectRecord>(
|
|
||||||
prefetchKey: PrefetchKey,
|
|
||||||
filter?: RecordGqlOperationFilter,
|
|
||||||
) => {
|
|
||||||
const { operationSignatureFactory, objectNameSingular } =
|
|
||||||
PREFETCH_CONFIG[prefetchKey];
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const recordGqlFields =
|
|
||||||
operationSignatureFactory({ objectMetadataItem }).fields ?? filter;
|
|
||||||
const { records, findManyRecords } = useLazyFindManyRecords<T>({
|
|
||||||
objectNameSingular: objectNameSingular,
|
|
||||||
recordGqlFields,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
findManyRecords,
|
|
||||||
records,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
|
||||||
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
|
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
|
|
||||||
export const usePrefetchedData = <T extends ObjectRecord>(
|
|
||||||
prefetchKey: PrefetchKey,
|
|
||||||
filter?: RecordGqlOperationFilter,
|
|
||||||
) => {
|
|
||||||
const isDataPrefetched = useRecoilValue(
|
|
||||||
prefetchIsLoadedFamilyState(prefetchKey),
|
|
||||||
);
|
|
||||||
|
|
||||||
const { operationSignatureFactory, objectNameSingular } =
|
|
||||||
PREFETCH_CONFIG[prefetchKey];
|
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const recordGqlFields =
|
|
||||||
operationSignatureFactory({ objectMetadataItem }).fields ?? filter;
|
|
||||||
const { records } = useFindManyRecords<T>({
|
|
||||||
skip: !isDataPrefetched,
|
|
||||||
objectNameSingular: objectNameSingular,
|
|
||||||
recordGqlFields,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
isDataPrefetched,
|
|
||||||
records,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
||||||
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const prefetchFavoriteFoldersState = createState<FavoriteFolder[]>({
|
||||||
|
key: 'prefetchFavoriteFoldersState',
|
||||||
|
defaultValue: [],
|
||||||
|
});
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { Favorite } from '@/favorites/types/Favorite';
|
||||||
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const prefetchFavoritesState = createState<Favorite[]>({
|
||||||
|
key: 'prefetchFavoritesState',
|
||||||
|
defaultValue: [],
|
||||||
|
});
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const prefetchViewsState = createState<View[]>({
|
||||||
|
key: 'prefetchViewsState',
|
||||||
|
defaultValue: [],
|
||||||
|
});
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { ViewKey } from '@/views/types/ViewKey';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const prefetchIndexViewIdFromObjectMetadataItemFamilySelector =
|
||||||
|
selectorFamily<string | undefined, { objectMetadataItemId: string }>({
|
||||||
|
key: 'prefetchIndexViewIdFromObjectMetadataItemFamilySelector',
|
||||||
|
get:
|
||||||
|
({ objectMetadataItemId }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views?.find(
|
||||||
|
(view) =>
|
||||||
|
view.objectMetadataId === objectMetadataItemId &&
|
||||||
|
view.key === ViewKey.Index,
|
||||||
|
)?.id;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const prefetchViewFromViewIdFamilySelector = selectorFamily<
|
||||||
|
View | undefined,
|
||||||
|
{ viewId: string }
|
||||||
|
>({
|
||||||
|
key: 'prefetchViewFromViewIdFamilySelector',
|
||||||
|
get:
|
||||||
|
({ viewId }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views?.find((view) => view.id === viewId);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const prefetchViewIdsFromObjectMetadataItemFamilySelector =
|
||||||
|
selectorFamily<string[], { objectMetadataItemId: string }>({
|
||||||
|
key: 'prefetchViewIdsFromObjectMetadataItemFamilySelector',
|
||||||
|
get:
|
||||||
|
({ objectMetadataItemId }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views
|
||||||
|
.filter((view) => view.objectMetadataId === objectMetadataItemId)
|
||||||
|
.map((view) => view.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { selector } from 'recoil';
|
||||||
|
|
||||||
|
export const prefetchViewLengthSelector = selector<number>({
|
||||||
|
key: 'prefetchViewLengthSelector',
|
||||||
|
get: ({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views?.length ?? 0;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const prefetchViewsFromObjectMetadataItemFamilySelector = selectorFamily<
|
||||||
|
View[],
|
||||||
|
{ objectMetadataItemId: string }
|
||||||
|
>({
|
||||||
|
key: 'prefetchViewsFromObjectMetadataItemFamilySelector',
|
||||||
|
get:
|
||||||
|
({ objectMetadataItemId }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const views = get(prefetchViewsState);
|
||||||
|
return views.filter(
|
||||||
|
(view) => view.objectMetadataId === objectMetadataItemId,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -1,5 +1,4 @@
|
|||||||
export enum PrefetchKey {
|
export enum PrefetchKey {
|
||||||
AllViews = 'ALL_VIEWS',
|
|
||||||
AllFavorites = 'ALL_FAVORITES',
|
AllFavorites = 'ALL_FAVORITES',
|
||||||
AllFavoritesFolders = 'ALL_FAVORITES_FOLDERS',
|
AllFavoritesFolders = 'ALL_FAVORITES_FOLDERS',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||||
import { useDeleteRecordFromCache } from '@/object-record/cache/hooks/useDeleteRecordFromCache';
|
import { useDeleteRecordFromCache } from '@/object-record/cache/hooks/useDeleteRecordFromCache';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown';
|
import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown';
|
||||||
import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
|
import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
|
||||||
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
|
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
|
||||||
@ -16,11 +15,10 @@ import { SettingsPath } from '@/types/SettingsPath';
|
|||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import {
|
import {
|
||||||
IconMinus,
|
IconMinus,
|
||||||
@ -121,8 +119,7 @@ export const SettingsObjectFieldItemTableRow = ({
|
|||||||
deleteMetadataField,
|
deleteMetadataField,
|
||||||
} = useFieldMetadataItem();
|
} = useFieldMetadataItem();
|
||||||
|
|
||||||
const { records: allViews } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||||
|
|
||||||
const deleteViewFromCache = useDeleteRecordFromCache({
|
const deleteViewFromCache = useDeleteRecordFromCache({
|
||||||
objectNameSingular: CoreObjectNameSingular.View,
|
objectNameSingular: CoreObjectNameSingular.View,
|
||||||
});
|
});
|
||||||
@ -135,7 +132,7 @@ export const SettingsObjectFieldItemTableRow = ({
|
|||||||
objectMetadataItem.id,
|
objectMetadataItem.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletedViewIds = allViews
|
const deletedViewIds = prefetchViews
|
||||||
.map((view) => {
|
.map((view) => {
|
||||||
if (view.kanbanFieldMetadataId === activeFieldMetadatItem.id) {
|
if (view.kanbanFieldMetadataId === activeFieldMetadatItem.id) {
|
||||||
deleteViewFromCache(view);
|
deleteViewFromCache(view);
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ViewBar } from '@/views/components/ViewBar';
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -23,9 +27,12 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
const recordIndexId = 'sign-up-mock-record-table-id';
|
const recordIndexId = 'sign-up-mock-record-table-id';
|
||||||
const viewBarId = 'companies-mock';
|
const viewBarId = 'companies-mock';
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
objectNameSingular,
|
|
||||||
});
|
const objectMetadataItem = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
|
'main-context-store',
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
@ -34,7 +41,7 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
recordIndexId,
|
recordIndexId,
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
objectMetadataItem,
|
objectMetadataItem: objectMetadataItem ?? objectMetadataItems[0],
|
||||||
onIndexRecordsLoaded: () => {},
|
onIndexRecordsLoaded: () => {},
|
||||||
indexIdentifierUrl: () => '',
|
indexIdentifierUrl: () => '',
|
||||||
}}
|
}}
|
||||||
@ -47,28 +54,32 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
>
|
>
|
||||||
<ContextStoreComponentInstanceContext.Provider
|
<ContextStoreComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: recordIndexId,
|
instanceId: 'main-context-store',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<SignInBackgroundMockContainerEffect
|
||||||
|
objectNamePlural={objectNamePlural}
|
||||||
|
recordTableId={recordIndexId}
|
||||||
|
viewId={viewBarId}
|
||||||
|
/>
|
||||||
<ActionMenuComponentInstanceContext.Provider
|
<ActionMenuComponentInstanceContext.Provider
|
||||||
value={{ instanceId: recordIndexId }}
|
value={{ instanceId: recordIndexId }}
|
||||||
>
|
>
|
||||||
<ViewBar
|
{isDefined(objectMetadataItem) && (
|
||||||
viewBarId={viewBarId}
|
<>
|
||||||
onCurrentViewChange={() => {}}
|
<ViewBar
|
||||||
optionsDropdownButton={<></>}
|
viewBarId={viewBarId}
|
||||||
/>
|
optionsDropdownButton={<></>}
|
||||||
<SignInBackgroundMockContainerEffect
|
/>
|
||||||
objectNamePlural={objectNamePlural}
|
|
||||||
recordTableId={recordIndexId}
|
<RecordTableWithWrappers
|
||||||
viewId={viewBarId}
|
objectNameSingular={objectNameSingular}
|
||||||
/>
|
recordTableId={recordIndexId}
|
||||||
<RecordTableWithWrappers
|
viewBarId={viewBarId}
|
||||||
objectNameSingular={objectNameSingular}
|
updateRecordMutation={() => {}}
|
||||||
recordTableId={recordIndexId}
|
/>
|
||||||
viewBarId={viewBarId}
|
</>
|
||||||
updateRecordMutation={() => {}}
|
)}
|
||||||
/>
|
|
||||||
</ActionMenuComponentInstanceContext.Provider>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
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 { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
import { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
|
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockSortDefinitions';
|
import { SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockSortDefinitions';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS } from '@/sign-in-background-mock/constants/SignInBackgroundMockViewFields';
|
import { SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS } from '@/sign-in-background-mock/constants/SignInBackgroundMockViewFields';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
|
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
|
||||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||||
|
|
||||||
@ -21,10 +24,16 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
viewId,
|
viewId,
|
||||||
}: SignInBackgroundMockContainerEffectProps) => {
|
}: SignInBackgroundMockContainerEffectProps) => {
|
||||||
const { setAvailableTableColumns, setOnEntityCountChange, setTableColumns } =
|
const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2(
|
||||||
useRecordTable({
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
recordTableId,
|
'main-context-store',
|
||||||
});
|
);
|
||||||
|
|
||||||
|
const { setAvailableTableColumns, setOnEntityCountChange } = useRecordTable({
|
||||||
|
recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setTableColumns } = useSetTableColumns();
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
@ -55,7 +64,10 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
viewFields: SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS,
|
viewFields: SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS,
|
||||||
columnDefinitions: SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS,
|
columnDefinitions: SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS,
|
||||||
}),
|
}),
|
||||||
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setContextStoreCurrentObjectMetadataItem(objectMetadataItem);
|
||||||
}, [
|
}, [
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
@ -63,6 +75,8 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setTableColumns,
|
setTableColumns,
|
||||||
|
recordTableId,
|
||||||
|
setContextStoreCurrentObjectMetadataItem,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { styled } from '@linaria/react';
|
import { styled } from '@linaria/react';
|
||||||
import { IconCheck, IconX, THEME_COMMON } from 'twenty-ui';
|
import { IconCheck, IconX, THEME_COMMON } from 'twenty-ui';
|
||||||
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
const spacing = THEME_COMMON.spacingMultiplicator * 1;
|
const spacing = THEME_COMMON.spacingMultiplicator * 1;
|
||||||
const iconSizeSm = THEME_COMMON.icon.size.sm;
|
const iconSizeSm = THEME_COMMON.icon.size.sm;
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ type BooleanDisplayProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const BooleanDisplay = ({ value }: BooleanDisplayProps) => {
|
export const BooleanDisplay = ({ value }: BooleanDisplayProps) => {
|
||||||
if (!isDefined(value)) {
|
if (value === null || value === undefined) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||||
import { useApplyViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyViewFiltersToCurrentRecordFilters';
|
import { useApplyViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyViewFiltersToCurrentRecordFilters';
|
||||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||||
|
|
||||||
export const QueryParamsFiltersEffect = () => {
|
export const QueryParamsFiltersEffect = () => {
|
||||||
const { hasFiltersQueryParams, getFiltersFromQueryParams, viewIdQueryParam } =
|
const { hasFiltersQueryParams, getFiltersFromQueryParams, viewIdQueryParam } =
|
||||||
useViewFromQueryParams();
|
useViewFromQueryParams();
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const setUnsavedViewFilter = useSetRecoilComponentFamilyStateV2(
|
const setUnsavedViewFilter = useSetRecoilComponentFamilyStateV2(
|
||||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
|
||||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
// TODO: This whole code should be removed. currentViewId should be used directly to set the mainContextStore
|
|
||||||
// and viewbar / view tooling should be updated to use that state contextStore state directly.
|
|
||||||
export const QueryParamsViewIdEffect = () => {
|
|
||||||
const [currentViewId, setCurrentViewId] = useRecoilComponentStateV2(
|
|
||||||
currentViewIdComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
|
||||||
mainContextStoreComponentInstanceIdState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
|
||||||
contextStoreCurrentViewIdComponentState,
|
|
||||||
mainContextStoreComponentInstanceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isDefined(contextStoreCurrentViewId)) {
|
|
||||||
if (currentViewId !== contextStoreCurrentViewId) {
|
|
||||||
setCurrentViewId(contextStoreCurrentViewId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [contextStoreCurrentViewId, currentViewId, setCurrentViewId]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
@ -7,6 +7,7 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
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';
|
||||||
@ -19,7 +20,6 @@ import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAr
|
|||||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||||
@ -44,7 +44,9 @@ export const UpdateViewButtonGroup = ({
|
|||||||
|
|
||||||
const { setViewPickerMode } = useViewPickerMode();
|
const { setViewPickerMode } = useViewPickerMode();
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const { closeDropdown: closeUpdateViewButtonDropdown } = useDropdown(
|
const { closeDropdown: closeUpdateViewButtonDropdown } = useDropdown(
|
||||||
UPDATE_VIEW_BUTTON_DROPDOWN_ID,
|
UPDATE_VIEW_BUTTON_DROPDOWN_ID,
|
||||||
|
|||||||
@ -7,13 +7,10 @@ import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/c
|
|||||||
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
||||||
import { TopBar } from '@/ui/layout/top-bar/components/TopBar';
|
import { TopBar } from '@/ui/layout/top-bar/components/TopBar';
|
||||||
import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect';
|
import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect';
|
||||||
import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect';
|
|
||||||
import { ViewBarEffect } from '@/views/components/ViewBarEffect';
|
|
||||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||||
import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle';
|
import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle';
|
||||||
import { ViewBarSkeletonLoader } from '@/views/components/ViewBarSkeletonLoader';
|
import { ViewBarSkeletonLoader } from '@/views/components/ViewBarSkeletonLoader';
|
||||||
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
|
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
|
||||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
|
||||||
import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDropdown';
|
import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDropdown';
|
||||||
|
|
||||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||||
@ -22,7 +19,6 @@ import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types
|
|||||||
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
|
||||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||||
import { ViewBarDetails } from './ViewBarDetails';
|
import { ViewBarDetails } from './ViewBarDetails';
|
||||||
|
|
||||||
@ -30,14 +26,12 @@ export type ViewBarProps = {
|
|||||||
viewBarId: string;
|
viewBarId: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
optionsDropdownButton: ReactNode;
|
optionsDropdownButton: ReactNode;
|
||||||
onCurrentViewChange: (view: GraphQLView | undefined) => void | Promise<void>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewBar = ({
|
export const ViewBar = ({
|
||||||
viewBarId,
|
viewBarId,
|
||||||
className,
|
className,
|
||||||
optionsDropdownButton,
|
optionsDropdownButton,
|
||||||
onCurrentViewChange,
|
|
||||||
}: ViewBarProps) => {
|
}: ViewBarProps) => {
|
||||||
const { objectNamePlural } = useParams();
|
const { objectNamePlural } = useParams();
|
||||||
|
|
||||||
@ -53,53 +47,49 @@ export const ViewBar = ({
|
|||||||
<ObjectSortDropdownComponentInstanceContext.Provider
|
<ObjectSortDropdownComponentInstanceContext.Provider
|
||||||
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
||||||
>
|
>
|
||||||
<ViewEventContext.Provider value={{ onCurrentViewChange }}>
|
<ViewBarRecordFilterEffect />
|
||||||
<ViewBarRecordFilterEffect />
|
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||||
<ViewBarEffect viewBarId={viewBarId} />
|
<ViewBarSortEffect />
|
||||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
<QueryParamsFiltersEffect />
|
||||||
<ViewBarSortEffect />
|
|
||||||
<QueryParamsFiltersEffect />
|
|
||||||
<QueryParamsViewIdEffect />
|
|
||||||
|
|
||||||
<ViewBarPageTitle viewBarId={viewBarId} />
|
<ViewBarPageTitle viewBarId={viewBarId} />
|
||||||
<TopBar
|
<TopBar
|
||||||
className={className}
|
className={className}
|
||||||
leftComponent={
|
leftComponent={
|
||||||
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
|
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
|
||||||
}
|
}
|
||||||
rightComponent={
|
rightComponent={
|
||||||
<>
|
<>
|
||||||
<ObjectFilterDropdownButton
|
<ObjectFilterDropdownButton
|
||||||
filterDropdownId={filterDropdownId}
|
|
||||||
hotkeyScope={{
|
|
||||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ObjectSortDropdownButton
|
|
||||||
hotkeyScope={{
|
|
||||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{optionsDropdownButton}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
bottomComponent={
|
|
||||||
<ViewBarDetails
|
|
||||||
filterDropdownId={filterDropdownId}
|
filterDropdownId={filterDropdownId}
|
||||||
hasFilterButton
|
hotkeyScope={{
|
||||||
viewBarId={viewBarId}
|
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||||
objectNamePlural={objectNamePlural}
|
}}
|
||||||
rightComponent={
|
|
||||||
<UpdateViewButtonGroup
|
|
||||||
hotkeyScope={{
|
|
||||||
scope: ViewsHotkeyScope.UpdateViewButtonDropdown,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
}
|
<ObjectSortDropdownButton
|
||||||
/>
|
hotkeyScope={{
|
||||||
</ViewEventContext.Provider>
|
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{optionsDropdownButton}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
bottomComponent={
|
||||||
|
<ViewBarDetails
|
||||||
|
filterDropdownId={filterDropdownId}
|
||||||
|
hasFilterButton
|
||||||
|
viewBarId={viewBarId}
|
||||||
|
objectNamePlural={objectNamePlural}
|
||||||
|
rightComponent={
|
||||||
|
<UpdateViewButtonGroup
|
||||||
|
hotkeyScope={{
|
||||||
|
scope: ViewsHotkeyScope.UpdateViewButtonDropdown,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</ObjectSortDropdownComponentInstanceContext.Provider>
|
</ObjectSortDropdownComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import { isUndefined } from '@sniptt/guards';
|
|
||||||
import { useContext, useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
|
||||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|
||||||
|
|
||||||
type ViewBarEffectProps = {
|
|
||||||
viewBarId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ViewBarEffect = ({ viewBarId }: ViewBarEffectProps) => {
|
|
||||||
const { currentViewWithCombinedFiltersAndSorts } =
|
|
||||||
useGetCurrentView(viewBarId);
|
|
||||||
|
|
||||||
const { onCurrentViewChange } = useContext(ViewEventContext);
|
|
||||||
|
|
||||||
const [currentViewSnapshot, setCurrentViewSnapshot] = useState<
|
|
||||||
View | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
const isPersistingViewFields = useRecoilComponentValueV2(
|
|
||||||
isPersistingViewFieldsComponentState,
|
|
||||||
viewBarId,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
!isDeeplyEqual(
|
|
||||||
currentViewWithCombinedFiltersAndSorts,
|
|
||||||
currentViewSnapshot,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (isUndefined(currentViewWithCombinedFiltersAndSorts)) {
|
|
||||||
setCurrentViewSnapshot(currentViewWithCombinedFiltersAndSorts);
|
|
||||||
onCurrentViewChange?.(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPersistingViewFields) {
|
|
||||||
setCurrentViewSnapshot(currentViewWithCombinedFiltersAndSorts);
|
|
||||||
onCurrentViewChange?.(currentViewWithCombinedFiltersAndSorts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
currentViewSnapshot,
|
|
||||||
currentViewWithCombinedFiltersAndSorts,
|
|
||||||
isPersistingViewFields,
|
|
||||||
onCurrentViewChange,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
@ -1,38 +1,24 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
|
||||||
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||||
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 { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const ViewBarRecordFilterEffect = () => {
|
export const ViewBarRecordFilterEffect = () => {
|
||||||
const { records: views, isDataPrefetched } = usePrefetchedData<View>(
|
|
||||||
PrefetchKey.AllViews,
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
|
||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
|
||||||
(objectMetadataItem) =>
|
|
||||||
objectMetadataItem.id === contextStoreCurrentObjectMetadataId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
@ -54,14 +40,21 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||||
objectMetadataItem?.id,
|
contextStoreCurrentObjectMetadataItem?.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentView = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId ?? '',
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDataPrefetched && !hasInitializedCurrentRecordFilters) {
|
if (isDefined(currentView) && !hasInitializedCurrentRecordFilters) {
|
||||||
const currentView = views.find((view) => view.id === currentViewId);
|
if (
|
||||||
|
currentView.objectMetadataId !==
|
||||||
if (currentView?.objectMetadataId !== objectMetadataItem?.id) {
|
contextStoreCurrentObjectMetadataItem?.id
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,15 +69,14 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isDataPrefetched,
|
|
||||||
views,
|
|
||||||
currentViewId,
|
currentViewId,
|
||||||
setCurrentRecordFilters,
|
setCurrentRecordFilters,
|
||||||
filterableFieldMetadataItems,
|
filterableFieldMetadataItems,
|
||||||
currentRecordFilters,
|
currentRecordFilters,
|
||||||
hasInitializedCurrentRecordFilters,
|
hasInitializedCurrentRecordFilters,
|
||||||
setHasInitializedCurrentRecordFilters,
|
setHasInitializedCurrentRecordFilters,
|
||||||
objectMetadataItem?.id,
|
contextStoreCurrentObjectMetadataItem?.id,
|
||||||
|
currentView,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
import { View } from '@/views/types/View';
|
|
||||||
import { createEventContext } from '~/utils/createEventContext';
|
|
||||||
|
|
||||||
type ViewEventContextType = {
|
|
||||||
onCurrentViewChange: (view: View | undefined) => void | Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ViewEventContext = createEventContext<ViewEventContextType>();
|
|
||||||
@ -1,20 +1,22 @@
|
|||||||
import { act, renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||||
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
import { View } from '@/views/types/View';
|
||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
import { act } from 'react';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||||
|
|
||||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
|
||||||
|
|
||||||
const mockObjectMetadataItemNameSingular = 'company';
|
const mockObjectMetadataItemNameSingular = 'company';
|
||||||
|
|
||||||
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||||
@ -41,18 +43,26 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
positionInViewFilterGroup: 0,
|
positionInViewFilterGroup: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockView = {
|
const mockView: View = {
|
||||||
id: 'view-1',
|
id: 'view-1',
|
||||||
name: 'Test View',
|
name: 'Test View',
|
||||||
objectMetadataId: mockObjectMetadataItem.id,
|
objectMetadataId: mockObjectMetadataItem.id,
|
||||||
viewFilters: [mockViewFilter],
|
viewFilters: [mockViewFilter],
|
||||||
|
type: ViewType.Table,
|
||||||
|
key: null,
|
||||||
|
isCompact: false,
|
||||||
|
viewFields: [],
|
||||||
|
viewGroups: [],
|
||||||
|
viewSorts: [],
|
||||||
|
kanbanFieldMetadataId: '',
|
||||||
|
kanbanAggregateOperation: AGGREGATE_OPERATIONS.count,
|
||||||
|
icon: '',
|
||||||
|
kanbanAggregateOperationFieldMetadataId: '',
|
||||||
|
position: 0,
|
||||||
|
__typename: 'View',
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should apply filters from current view', () => {
|
it('should apply filters from current view', () => {
|
||||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
|
||||||
records: [mockView],
|
|
||||||
});
|
|
||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||||
@ -75,11 +85,12 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
mockObjectMetadataItemNameSingular,
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||||
instanceId: 'instanceId',
|
instanceId: 'instanceId',
|
||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
|
snapshot.set(prefetchViewsState, [mockView]);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -105,10 +116,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not apply filters when current view is not found', () => {
|
it('should not apply filters when current view is not found', () => {
|
||||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
|
||||||
records: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||||
@ -131,11 +138,12 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
mockObjectMetadataItemNameSingular,
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||||
instanceId: 'instanceId',
|
instanceId: 'instanceId',
|
||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
|
snapshot.set(prefetchViewsState, []);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -149,15 +157,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle view with empty filters', () => {
|
it('should handle view with empty filters', () => {
|
||||||
const viewWithNoFilters = {
|
|
||||||
...mockView,
|
|
||||||
viewFilters: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
|
||||||
records: [viewWithNoFilters],
|
|
||||||
});
|
|
||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||||
@ -180,11 +179,14 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
mockObjectMetadataItemNameSingular,
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||||
instanceId: 'instanceId',
|
instanceId: 'instanceId',
|
||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
|
snapshot.set(prefetchViewsState, [
|
||||||
|
{ ...mockView, viewFilters: [] },
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
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 { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
);
|
||||||
|
|
||||||
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
@ -22,18 +21,28 @@ export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
|||||||
const { filterableFieldMetadataItems } =
|
const { filterableFieldMetadataItems } =
|
||||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
useFilterableFieldMetadataItemsInRecordIndexContext();
|
||||||
|
|
||||||
const applyCurrentViewFiltersToCurrentRecordFilters = () => {
|
const applyCurrentViewFiltersToCurrentRecordFilters = useRecoilCallback(
|
||||||
const currentView = views.find((view) => view.id === currentViewId);
|
({ snapshot }) =>
|
||||||
|
() => {
|
||||||
|
const currentView = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId ?? '',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
if (isDefined(currentView)) {
|
if (isDefined(currentView)) {
|
||||||
setCurrentRecordFilters(
|
setCurrentRecordFilters(
|
||||||
mapViewFiltersToFilters(
|
mapViewFiltersToFilters(
|
||||||
currentView.viewFilters,
|
currentView.viewFilters,
|
||||||
filterableFieldMetadataItems,
|
filterableFieldMetadataItems,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
[currentViewId, filterableFieldMetadataItems, setCurrentRecordFilters],
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
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 { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
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';
|
||||||
@ -11,9 +14,7 @@ import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistView
|
|||||||
import { useGetViewFilterGroupsCombined } from '@/views/hooks/useGetCombinedViewFilterGroups';
|
import { useGetViewFilterGroupsCombined } from '@/views/hooks/useGetCombinedViewFilterGroups';
|
||||||
import { useGetViewFiltersCombined } from '@/views/hooks/useGetCombinedViewFilters';
|
import { useGetViewFiltersCombined } from '@/views/hooks/useGetCombinedViewFilters';
|
||||||
import { useGetViewSortsCombined } from '@/views/hooks/useGetCombinedViewSorts';
|
import { useGetViewSortsCombined } from '@/views/hooks/useGetCombinedViewSorts';
|
||||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
|
||||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
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';
|
||||||
@ -25,17 +26,10 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
|||||||
|
|
||||||
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
viewBarComponentId,
|
viewBarComponentId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPersistingViewFieldsCallbackState = useRecoilComponentCallbackStateV2(
|
|
||||||
isPersistingViewFieldsComponentState,
|
|
||||||
viewBarComponentId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { getViewFromCache } = useGetViewFromCache();
|
|
||||||
|
|
||||||
const { createOneRecord } = useCreateOneRecord<View>({
|
const { createOneRecord } = useCreateOneRecord<View>({
|
||||||
objectNameSingular: CoreObjectNameSingular.View,
|
objectNameSingular: CoreObjectNameSingular.View,
|
||||||
});
|
});
|
||||||
@ -58,6 +52,11 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
|||||||
|
|
||||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const { findManyRecords } = useLazyFindManyRecords({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.View,
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
});
|
||||||
|
|
||||||
const createViewFromCurrentView = useRecoilCallback(
|
const createViewFromCurrentView = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (
|
async (
|
||||||
@ -84,14 +83,19 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we might instead want to get view from unsaved filters ?
|
const sourceView = snapshot
|
||||||
const sourceView = await getViewFromCache(currentViewId);
|
.getLoadable(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
if (!isDefined(sourceView)) {
|
if (!isDefined(sourceView)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set(isPersistingViewFieldsCallbackState, true);
|
set(isPersistingViewFieldsState, true);
|
||||||
|
|
||||||
const newView = await createOneRecord({
|
const newView = await createOneRecord({
|
||||||
id: id ?? v4(),
|
id: id ?? v4(),
|
||||||
@ -123,7 +127,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const viewGroupsToCreate =
|
const viewGroupsToCreate =
|
||||||
objectMetadataItem?.fields
|
objectMetadataItem.fields
|
||||||
?.find((field) => field.id === kanbanFieldMetadataId)
|
?.find((field) => field.id === kanbanFieldMetadataId)
|
||||||
?.options?.map(
|
?.options?.map(
|
||||||
(option, index) =>
|
(option, index) =>
|
||||||
@ -169,21 +173,21 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(isPersistingViewFieldsCallbackState, false);
|
await findManyRecords();
|
||||||
|
set(isPersistingViewFieldsState, false);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
objectMetadataItem,
|
currentViewIdCallbackState,
|
||||||
createViewSortRecords,
|
|
||||||
createViewFilterRecords,
|
|
||||||
createOneRecord,
|
createOneRecord,
|
||||||
createViewFieldRecords,
|
createViewFieldRecords,
|
||||||
getViewSortsCombined,
|
findManyRecords,
|
||||||
getViewFiltersCombined,
|
objectMetadataItem.fields,
|
||||||
getViewFilterGroupsCombined,
|
|
||||||
currentViewIdCallbackState,
|
|
||||||
getViewFromCache,
|
|
||||||
isPersistingViewFieldsCallbackState,
|
|
||||||
createViewGroupRecords,
|
createViewGroupRecords,
|
||||||
|
getViewFilterGroupsCombined,
|
||||||
|
getViewFiltersCombined,
|
||||||
|
getViewSortsCombined,
|
||||||
|
createViewSortRecords,
|
||||||
|
createViewFilterRecords,
|
||||||
createViewFilterGroupRecords,
|
createViewFilterGroupRecords,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
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 { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
@ -22,11 +22,11 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
viewBarComponentId,
|
viewBarComponentId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getViewFromCache } = useGetViewFromCache();
|
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||||
|
|
||||||
const deleteCombinedViewFilter = useRecoilCallback(
|
const deleteCombinedViewFilter = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
@ -50,7 +50,7 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentView = await getViewFromCache(currentViewId);
|
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||||
|
|
||||||
if (!currentView) {
|
if (!currentView) {
|
||||||
return;
|
return;
|
||||||
@ -89,7 +89,7 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
currentViewIdCallbackState,
|
currentViewIdCallbackState,
|
||||||
getViewFromCache,
|
getViewFromPrefetchState,
|
||||||
unsavedToDeleteViewFilterIdsCallbackState,
|
unsavedToDeleteViewFilterIdsCallbackState,
|
||||||
unsavedToUpsertViewFiltersCallbackState,
|
unsavedToUpsertViewFiltersCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
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 { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
viewBarComponentId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const unsavedToUpsertViewSortsCallbackState =
|
const unsavedToUpsertViewSortsCallbackState =
|
||||||
@ -26,7 +25,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
|||||||
viewBarComponentId,
|
viewBarComponentId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getViewFromCache } = useGetViewFromCache();
|
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||||
|
|
||||||
const deleteCombinedViewSort = useRecoilCallback(
|
const deleteCombinedViewSort = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
@ -50,7 +49,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
|||||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentView = await getViewFromCache(currentViewId);
|
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||||
|
|
||||||
if (!currentView) {
|
if (!currentView) {
|
||||||
return;
|
return;
|
||||||
@ -88,7 +87,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
currentViewIdCallbackState,
|
currentViewIdCallbackState,
|
||||||
getViewFromCache,
|
getViewFromPrefetchState,
|
||||||
unsavedToDeleteViewSortIdsCallbackState,
|
unsavedToDeleteViewSortIdsCallbackState,
|
||||||
unsavedToUpsertViewSortsCallbackState,
|
unsavedToUpsertViewSortsCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
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 { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
|
|
||||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||||
@ -28,7 +24,13 @@ export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
|||||||
const getViewFilterGroupsCombined = useRecoilCallback(
|
const getViewFilterGroupsCombined = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(viewId: string) => {
|
(viewId: string) => {
|
||||||
const view = views.find((view) => view.id === viewId);
|
const view = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
if (!isDefined(view)) {
|
if (!isDefined(view)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -55,7 +57,6 @@ export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
|||||||
return combinedViewFilterGroups;
|
return combinedViewFilterGroups;
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
views,
|
|
||||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
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 { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
|
|
||||||
const unsavedToUpsertViewFiltersCallbackState =
|
const unsavedToUpsertViewFiltersCallbackState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||||
@ -28,7 +24,13 @@ export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
|||||||
const getViewFiltersCombined = useRecoilCallback(
|
const getViewFiltersCombined = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(viewId: string) => {
|
(viewId: string) => {
|
||||||
const view = views.find((view) => view.id === viewId);
|
const view = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
if (!isDefined(view)) {
|
if (!isDefined(view)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -55,7 +57,6 @@ export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
|||||||
return combinedViewFilters;
|
return combinedViewFilters;
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
views,
|
|
||||||
unsavedToDeleteViewFilterIdsCallbackState,
|
unsavedToDeleteViewFilterIdsCallbackState,
|
||||||
unsavedToUpsertViewFiltersCallbackState,
|
unsavedToUpsertViewFiltersCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
|
||||||
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 { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
// TODO: fix naming
|
// TODO: fix naming
|
||||||
export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
|
||||||
|
|
||||||
const unsavedToUpsertViewSortsCallbackState =
|
const unsavedToUpsertViewSortsCallbackState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
unsavedToUpsertViewSortsComponentFamilyState,
|
unsavedToUpsertViewSortsComponentFamilyState,
|
||||||
@ -29,7 +25,13 @@ export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
|||||||
const getViewSortsCombined = useRecoilCallback(
|
const getViewSortsCombined = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(viewId: string) => {
|
(viewId: string) => {
|
||||||
const view = views.find((view) => view.id === viewId);
|
const view = snapshot
|
||||||
|
.getLoadable(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
if (!isDefined(view)) {
|
if (!isDefined(view)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -56,7 +58,6 @@ export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
|||||||
return combinedViewSorts;
|
return combinedViewSorts;
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
views,
|
|
||||||
unsavedToDeleteViewSortIdsCallbackState,
|
unsavedToDeleteViewSortIdsCallbackState,
|
||||||
unsavedToUpsertViewSortsCallbackState,
|
unsavedToUpsertViewSortsCallbackState,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||||
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
|
import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector';
|
||||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
|
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
|
||||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||||
@ -15,12 +17,10 @@ import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/u
|
|||||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||||
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
||||||
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
||||||
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||||
@ -29,16 +29,28 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
|||||||
viewBarInstanceId,
|
viewBarInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
currentViewIdComponentState,
|
contextStoreCurrentViewIdComponentState,
|
||||||
instanceId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewObjectMetadataId = useRecoilComponentValueV2(
|
const indexViewId = useRecoilValue(
|
||||||
viewObjectMetadataIdComponentState,
|
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||||
instanceId,
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentViewFromViewId = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId ?? '',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const indexView = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: indexViewId ?? '',
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const setIsCurrentViewKeyIndex = useSetRecoilComponentStateV2(
|
const setIsCurrentViewKeyIndex = useSetRecoilComponentStateV2(
|
||||||
@ -46,25 +58,17 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
|||||||
instanceId,
|
instanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentViewFromCurrentViewId = views.find(
|
|
||||||
(view) => view.id === currentViewId,
|
|
||||||
);
|
|
||||||
const indexView = views.find(
|
|
||||||
(view) =>
|
|
||||||
view.key === 'INDEX' && view.objectMetadataId === viewObjectMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentView = currentViewId ? currentViewFromCurrentViewId : indexView;
|
|
||||||
|
|
||||||
const viewId = currentViewId ?? indexView?.id;
|
const viewId = currentViewId ?? indexView?.id;
|
||||||
|
const currentView = currentViewFromViewId ?? indexView;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsCurrentViewKeyIndex(currentView?.key === 'INDEX');
|
setIsCurrentViewKeyIndex(currentView?.key === 'INDEX');
|
||||||
}, [currentView, setIsCurrentViewKeyIndex]);
|
}, [currentView, setIsCurrentViewKeyIndex]);
|
||||||
|
|
||||||
const viewsOnCurrentObject = getObjectMetadataItemViews(
|
const viewsOnCurrentObject = useRecoilValue(
|
||||||
viewObjectMetadataId ?? '',
|
prefetchViewsFromObjectMetadataItemFamilySelector({
|
||||||
views,
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const unsavedToUpsertViewFilters = useRecoilComponentFamilyValueV2(
|
const unsavedToUpsertViewFilters = useRecoilComponentFamilyValueV2(
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
export const useGetCurrentViewOnly = () => {
|
export const useGetCurrentViewOnly = () => {
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
const currentView = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
const currentView = useMemo(
|
viewId: currentViewId ?? '',
|
||||||
() => views.find((view) => view.id === currentViewId),
|
}),
|
||||||
[views, currentViewId],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
import { useCallback } from 'react';
|
|
||||||
import { useApolloClient } from '@apollo/client';
|
|
||||||
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
|
||||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
|
|
||||||
export const useGetViewFromCache = () => {
|
|
||||||
const client = useApolloClient();
|
|
||||||
const cache = client.cache;
|
|
||||||
|
|
||||||
const getRecordFromCache = useGetRecordFromCache({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.View,
|
|
||||||
});
|
|
||||||
|
|
||||||
const getViewFromCache = useCallback(
|
|
||||||
async (viewId: string) => {
|
|
||||||
return getRecordFromCache<View>(viewId, cache);
|
|
||||||
},
|
|
||||||
[cache, getRecordFromCache],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
getViewFromCache,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user