mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 12:02:10 +03:00
7339 implement contextual actions inside the commandmenu (#8000)
Closes #7339 https://github.com/user-attachments/assets/b623caa4-c1b3-448e-8880-4a8301802ba8
This commit is contained in:
parent
8bb07c4a4f
commit
fe2c8bb43b
@ -1,5 +1,5 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
|
||||
import { ActionMenuType } from '@/action-menu/types/ActionMenuType';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
@ -12,17 +12,15 @@ import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTabl
|
||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { IconTrash, isDefined } from 'twenty-ui';
|
||||
|
||||
export const DeleteRecordsActionEffect = ({
|
||||
position,
|
||||
objectMetadataItem,
|
||||
actionMenuType,
|
||||
}: {
|
||||
position: number;
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
actionMenuType: ActionMenuType;
|
||||
}) => {
|
||||
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
|
||||
|
||||
@ -93,6 +91,9 @@ export const DeleteRecordsActionEffect = ({
|
||||
contextStoreNumberOfSelectedRecords < DELETE_MAX_COUNT &&
|
||||
contextStoreNumberOfSelectedRecords > 0;
|
||||
|
||||
const { isInRightDrawer, onActionExecutedCallback } =
|
||||
useContext(ActionMenuContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (canDelete) {
|
||||
addActionMenuEntry({
|
||||
@ -120,17 +121,14 @@ export const DeleteRecordsActionEffect = ({
|
||||
} can be recovered from the Options menu.`}
|
||||
onConfirmClick={() => {
|
||||
handleDeleteClick();
|
||||
|
||||
if (actionMenuType === 'recordShow') {
|
||||
onActionExecutedCallback?.();
|
||||
if (isInRightDrawer) {
|
||||
closeRightDrawer();
|
||||
}
|
||||
}}
|
||||
deleteButtonText={`Delete ${
|
||||
contextStoreNumberOfSelectedRecords > 1 ? 'Records' : 'Record'
|
||||
}`}
|
||||
modalVariant={
|
||||
actionMenuType === 'recordShow' ? 'tertiary' : 'primary'
|
||||
}
|
||||
/>
|
||||
),
|
||||
});
|
||||
@ -142,13 +140,14 @@ export const DeleteRecordsActionEffect = ({
|
||||
removeActionMenuEntry('delete');
|
||||
};
|
||||
}, [
|
||||
actionMenuType,
|
||||
addActionMenuEntry,
|
||||
canDelete,
|
||||
closeRightDrawer,
|
||||
contextStoreNumberOfSelectedRecords,
|
||||
handleDeleteClick,
|
||||
isDeleteRecordsModalOpen,
|
||||
isInRightDrawer,
|
||||
onActionExecutedCallback,
|
||||
position,
|
||||
removeActionMenuEntry,
|
||||
]);
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect';
|
||||
import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect';
|
||||
import { ActionMenuType } from '@/action-menu/types/ActionMenuType';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
|
||||
const actionEffects = [ExportRecordsActionEffect, DeleteRecordsActionEffect];
|
||||
|
||||
export const MultipleRecordsActionMenuEntriesSetter = ({
|
||||
objectMetadataItem,
|
||||
actionMenuType,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
actionMenuType: ActionMenuType;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{actionEffects.map((ActionEffect, index) => (
|
||||
<ActionEffect
|
||||
key={index}
|
||||
position={index}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
actionMenuType={actionMenuType}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,16 +1,23 @@
|
||||
import { MultipleRecordsActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter';
|
||||
import { SingleRecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter';
|
||||
import { ActionMenuType } from '@/action-menu/types/ActionMenuType';
|
||||
import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect';
|
||||
import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect';
|
||||
import { ManageFavoritesActionEffect } from '@/action-menu/actions/record-actions/components/ManageFavoritesActionEffect';
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordActionMenuEntriesSetter = ({
|
||||
actionMenuType,
|
||||
}: {
|
||||
actionMenuType: ActionMenuType;
|
||||
}) => {
|
||||
const singleRecordActionEffects = [
|
||||
ManageFavoritesActionEffect,
|
||||
ExportRecordsActionEffect,
|
||||
DeleteRecordsActionEffect,
|
||||
];
|
||||
|
||||
const multipleRecordActionEffects = [
|
||||
ExportRecordsActionEffect,
|
||||
DeleteRecordsActionEffect,
|
||||
];
|
||||
|
||||
export const RecordActionMenuEntriesSetter = () => {
|
||||
const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
);
|
||||
@ -33,19 +40,20 @@ export const RecordActionMenuEntriesSetter = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
if (contextStoreNumberOfSelectedRecords === 1) {
|
||||
return (
|
||||
<SingleRecordActionMenuEntriesSetter
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
actionMenuType={actionMenuType}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const actions =
|
||||
contextStoreNumberOfSelectedRecords === 1
|
||||
? singleRecordActionEffects
|
||||
: multipleRecordActionEffects;
|
||||
|
||||
return (
|
||||
<MultipleRecordsActionMenuEntriesSetter
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
actionMenuType={actionMenuType}
|
||||
/>
|
||||
<>
|
||||
{actions.map((ActionEffect, index) => (
|
||||
<ActionEffect
|
||||
key={index}
|
||||
position={index}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect';
|
||||
import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect';
|
||||
import { ManageFavoritesActionEffect } from '@/action-menu/actions/record-actions/components/ManageFavoritesActionEffect';
|
||||
import { ActionMenuType } from '@/action-menu/types/ActionMenuType';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
|
||||
export const SingleRecordActionMenuEntriesSetter = ({
|
||||
objectMetadataItem,
|
||||
actionMenuType,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
actionMenuType: ActionMenuType;
|
||||
}) => {
|
||||
const actionEffects = [
|
||||
ManageFavoritesActionEffect,
|
||||
ExportRecordsActionEffect,
|
||||
DeleteRecordsActionEffect,
|
||||
];
|
||||
return (
|
||||
<>
|
||||
{actionEffects.map((ActionEffect, index) => (
|
||||
<ActionEffect
|
||||
key={index}
|
||||
position={index}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
actionMenuType={actionMenuType}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
@ -3,16 +3,12 @@ import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMen
|
||||
import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar';
|
||||
import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown';
|
||||
import { RecordIndexActionMenuEffect } from '@/action-menu/components/RecordIndexActionMenuEffect';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordIndexActionMenu = ({
|
||||
actionMenuId,
|
||||
}: {
|
||||
actionMenuId: string;
|
||||
}) => {
|
||||
export const RecordIndexActionMenu = () => {
|
||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
@ -20,15 +16,18 @@ export const RecordIndexActionMenu = ({
|
||||
return (
|
||||
<>
|
||||
{contextStoreCurrentObjectMetadataId && (
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: actionMenuId }}
|
||||
<ActionMenuContext.Provider
|
||||
value={{
|
||||
isInRightDrawer: false,
|
||||
onActionExecutedCallback: () => {},
|
||||
}}
|
||||
>
|
||||
<RecordIndexActionMenuBar />
|
||||
<RecordIndexActionMenuDropdown />
|
||||
<ActionMenuConfirmationModals />
|
||||
<RecordIndexActionMenuEffect />
|
||||
<RecordActionMenuEntriesSetter actionMenuType="recordIndex" />
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
<RecordActionMenuEntriesSetter />
|
||||
</ActionMenuContext.Provider>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { useActionMenu } from '@/action-menu/hooks/useActionMenu';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
@ -25,6 +27,9 @@ export const RecordIndexActionMenuEffect = () => {
|
||||
`action-menu-dropdown-${actionMenuId}`,
|
||||
),
|
||||
);
|
||||
const { isRightDrawerOpen } = useRightDrawer();
|
||||
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
|
||||
useEffect(() => {
|
||||
if (contextStoreNumberOfSelectedRecords > 0 && !isDropdownOpen) {
|
||||
@ -43,5 +48,11 @@ export const RecordIndexActionMenuEffect = () => {
|
||||
isDropdownOpen,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isRightDrawerOpen || isCommandMenuOpened) {
|
||||
closeActionBar();
|
||||
}
|
||||
}, [closeActionBar, isRightDrawerOpen, isCommandMenuOpened]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
@ -1,30 +1,53 @@
|
||||
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||
import { RecordShowActionMenuBar } from '@/action-menu/components/RecordShowActionMenuBar';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
||||
|
||||
export const RecordShowActionMenu = ({
|
||||
actionMenuId,
|
||||
isFavorite,
|
||||
handleFavoriteButtonClick,
|
||||
record,
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
}: {
|
||||
actionMenuId: string;
|
||||
isFavorite: boolean;
|
||||
handleFavoriteButtonClick: () => void;
|
||||
record: ObjectRecord | undefined;
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
|
||||
// TODO: refactor RecordShowPageBaseHeader to use the context store
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextStoreCurrentObjectMetadataId && (
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: actionMenuId }}
|
||||
<ActionMenuContext.Provider
|
||||
value={{
|
||||
isInRightDrawer: false,
|
||||
onActionExecutedCallback: () => {},
|
||||
}}
|
||||
>
|
||||
<RecordShowActionMenuBar />
|
||||
<RecordShowPageBaseHeader
|
||||
{...{
|
||||
isFavorite,
|
||||
handleFavoriteButtonClick,
|
||||
record,
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
}}
|
||||
/>
|
||||
<ActionMenuConfirmationModals />
|
||||
<RecordActionMenuEntriesSetter actionMenuType="recordShow" />
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
<RecordActionMenuEntriesSetter />
|
||||
</ActionMenuContext.Provider>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -0,0 +1,30 @@
|
||||
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||
import { RecordShowRightDrawerActionMenuBar } from '@/action-menu/components/RecordShowRightDrawerActionMenuBar';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordShowRightDrawerActionMenu = () => {
|
||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextStoreCurrentObjectMetadataId && (
|
||||
<ActionMenuContext.Provider
|
||||
value={{
|
||||
isInRightDrawer: true,
|
||||
onActionExecutedCallback: () => {},
|
||||
}}
|
||||
>
|
||||
<RecordShowRightDrawerActionMenuBar />
|
||||
<ActionMenuConfirmationModals />
|
||||
<RecordActionMenuEntriesSetter />
|
||||
</ActionMenuContext.Provider>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
@ -2,7 +2,7 @@ import { RecordShowActionMenuBarEntry } from '@/action-menu/components/RecordSho
|
||||
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordShowActionMenuBar = () => {
|
||||
export const RecordShowRightDrawerActionMenuBar = () => {
|
||||
const actionMenuEntries = useRecoilComponentValueV2(
|
||||
actionMenuEntriesComponentSelector,
|
||||
);
|
@ -2,7 +2,7 @@ import { expect, jest } from '@storybook/jest';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { RecordShowActionMenuBar } from '@/action-menu/components/RecordShowActionMenuBar';
|
||||
import { RecordShowRightDrawerActionMenuBar } from '@/action-menu/components/RecordShowRightDrawerActionMenuBar';
|
||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
@ -20,9 +20,9 @@ const deleteMock = jest.fn();
|
||||
const addToFavoritesMock = jest.fn();
|
||||
const exportMock = jest.fn();
|
||||
|
||||
const meta: Meta<typeof RecordShowActionMenuBar> = {
|
||||
title: 'Modules/ActionMenu/RecordShowActionMenuBar',
|
||||
component: RecordShowActionMenuBar,
|
||||
const meta: Meta<typeof RecordShowRightDrawerActionMenuBar> = {
|
||||
title: 'Modules/ActionMenu/RecordShowRightDrawerActionMenuBar',
|
||||
component: RecordShowRightDrawerActionMenuBar,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<RecoilRoot
|
||||
@ -98,7 +98,7 @@ const meta: Meta<typeof RecordShowActionMenuBar> = {
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof RecordShowActionMenuBar>;
|
||||
type Story = StoryObj<typeof RecordShowRightDrawerActionMenuBar>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
type ActionMenuContextType = {
|
||||
isInRightDrawer: boolean;
|
||||
onActionExecutedCallback: () => void;
|
||||
};
|
||||
|
||||
export const ActionMenuContext = createContext<ActionMenuContextType>({
|
||||
isInRightDrawer: false,
|
||||
onActionExecutedCallback: () => {},
|
||||
});
|
@ -1 +0,0 @@
|
||||
export type ActionMenuType = 'recordIndex' | 'recordShow';
|
@ -10,6 +10,7 @@ import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchS
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { Command, CommandType } from '@/command-menu/types/Command';
|
||||
import { Company } from '@/companies/types/Company';
|
||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||
import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getCompanyDomainName } from '@/object-metadata/utils/getCompanyDomainName';
|
||||
@ -287,6 +288,14 @@ export const CommandMenu = () => {
|
||||
: true) && cmd.type === CommandType.Create,
|
||||
);
|
||||
|
||||
const matchingActionCommands = commandMenuCommands.filter(
|
||||
(cmd) =>
|
||||
(deferredCommandMenuSearch.length > 0
|
||||
? checkInShortcuts(cmd, deferredCommandMenuSearch) ||
|
||||
checkInLabels(cmd, deferredCommandMenuSearch)
|
||||
: true) && cmd.type === CommandType.Action,
|
||||
);
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [commandMenuRef],
|
||||
callback: closeCommandMenu,
|
||||
@ -312,6 +321,7 @@ export const CommandMenu = () => {
|
||||
|
||||
const selectableItemIds = copilotCommands
|
||||
.map((cmd) => cmd.id)
|
||||
.concat(matchingActionCommands.map((cmd) => cmd.id))
|
||||
.concat(matchingCreateCommand.map((cmd) => cmd.id))
|
||||
.concat(matchingNavigateCommand.map((cmd) => cmd.id))
|
||||
.concat(people?.map((person) => person.id))
|
||||
@ -320,22 +330,28 @@ export const CommandMenu = () => {
|
||||
.concat(notes?.map((note) => note.id));
|
||||
|
||||
const isNoResults =
|
||||
!matchingActionCommands.length &&
|
||||
!matchingCreateCommand.length &&
|
||||
!matchingNavigateCommand.length &&
|
||||
!people?.length &&
|
||||
!companies?.length &&
|
||||
!notes?.length &&
|
||||
!opportunities?.length;
|
||||
|
||||
const isLoading =
|
||||
isPeopleLoading ||
|
||||
isNotesLoading ||
|
||||
isOpportunitiesLoading ||
|
||||
isCompaniesLoading;
|
||||
|
||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||
mainContextStoreComponentInstanceIdState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isCommandMenuOpened && (
|
||||
<StyledCommandMenu ref={commandMenuRef}>
|
||||
<StyledCommandMenu ref={commandMenuRef} className="command-menu">
|
||||
<StyledInputContainer>
|
||||
<StyledInput
|
||||
autoFocus
|
||||
@ -393,6 +409,23 @@ export const CommandMenu = () => {
|
||||
</SelectableItem>
|
||||
</CommandGroup>
|
||||
)}
|
||||
{mainContextStoreComponentInstanceId && (
|
||||
<CommandGroup heading="Actions">
|
||||
{matchingActionCommands?.map((actionCommand) => (
|
||||
<SelectableItem
|
||||
itemId={actionCommand.id}
|
||||
key={actionCommand.id}
|
||||
>
|
||||
<CommandMenuItem
|
||||
id={actionCommand.id}
|
||||
label={actionCommand.label}
|
||||
Icon={actionCommand.Icon}
|
||||
onClick={actionCommand.onCommandClick}
|
||||
/>
|
||||
</SelectableItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
)}
|
||||
<CommandGroup heading="Create">
|
||||
{matchingCreateCommand.map((cmd) => (
|
||||
<SelectableItem itemId={cmd.id} key={cmd.id}>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
@ -9,7 +9,9 @@ import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousH
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
|
||||
import { COMMAND_MENU_COMMANDS } from '@/command-menu/constants/CommandMenuCommands';
|
||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { ALL_ICONS } from '@ui/display/icon/providers/internal/AllIcons';
|
||||
import { sortByProperty } from '~/utils/array/sortByProperty';
|
||||
@ -27,10 +29,43 @@ export const useCommandMenu = () => {
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const openCommandMenu = useCallback(() => {
|
||||
setIsCommandMenuOpened(true);
|
||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
||||
}, [setHotkeyScopeAndMemorizePreviousScope, setIsCommandMenuOpened]);
|
||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||
mainContextStoreComponentInstanceIdState,
|
||||
);
|
||||
|
||||
const openCommandMenu = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
if (isDefined(mainContextStoreComponentInstanceId)) {
|
||||
const actionMenuEntries = snapshot.getLoadable(
|
||||
actionMenuEntriesComponentSelector.selectorFamily({
|
||||
instanceId: mainContextStoreComponentInstanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
const actionCommands = actionMenuEntries
|
||||
.getValue()
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: actionMenuEntry.label,
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.Action,
|
||||
}));
|
||||
|
||||
setCommands(actionCommands);
|
||||
}
|
||||
|
||||
setIsCommandMenuOpened(true);
|
||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
||||
},
|
||||
[
|
||||
mainContextStoreComponentInstanceId,
|
||||
setCommands,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
setIsCommandMenuOpened,
|
||||
],
|
||||
);
|
||||
|
||||
const closeCommandMenu = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
|
@ -3,13 +3,14 @@ import { IconComponent } from 'twenty-ui';
|
||||
export enum CommandType {
|
||||
Navigate = 'Navigate',
|
||||
Create = 'Create',
|
||||
Action = 'Action',
|
||||
}
|
||||
|
||||
export type Command = {
|
||||
id: string;
|
||||
to: string;
|
||||
to?: string;
|
||||
label: string;
|
||||
type: CommandType.Navigate | CommandType.Create;
|
||||
type: CommandType.Navigate | CommandType.Create | CommandType.Action;
|
||||
Icon?: IconComponent;
|
||||
firstHotKey?: string;
|
||||
secondHotKey?: string;
|
||||
|
@ -3,7 +3,7 @@ import { mainContextStoreComponentInstanceIdState } from '@/context-store/states
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
export const SetMainContextStoreComponentInstanceIdEffect = () => {
|
||||
export const MainContextStoreComponentInstanceIdSetterEffect = () => {
|
||||
const setMainContextStoreComponentInstanceId = useSetRecoilState(
|
||||
mainContextStoreComponentInstanceIdState,
|
||||
);
|
@ -71,7 +71,7 @@ export const RecordBoard = () => {
|
||||
|
||||
useListenClickOutsideByClassName({
|
||||
classNames: ['record-board-card'],
|
||||
excludeClassNames: ['bottom-bar', 'action-menu-dropdown'],
|
||||
excludeClassNames: ['bottom-bar', 'action-menu-dropdown', 'command-menu'],
|
||||
callback: resetRecordSelection,
|
||||
});
|
||||
|
||||
|
@ -206,6 +206,7 @@ export const RecordIndexContainer = () => {
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
</SpreadsheetImportProvider>
|
||||
|
||||
{recordIndexViewType === ViewType.Table && (
|
||||
<>
|
||||
<RecordIndexTableContainer
|
||||
@ -232,7 +233,7 @@ export const RecordIndexContainer = () => {
|
||||
/>
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
<RecordIndexActionMenu actionMenuId={recordIndexId} />
|
||||
<RecordIndexActionMenu />
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||
@ -38,19 +40,29 @@ export const RightDrawerRecord = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledRightDrawerRecord>
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
{!isNewViewableRecordLoading && (
|
||||
<RecordValueSetterEffect recordId={objectRecordId} />
|
||||
)}
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
isNewRightDrawerItemLoading={isNewViewableRecordLoading}
|
||||
/>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</StyledRightDrawerRecord>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: `record-show-${objectRecordId}`,
|
||||
}}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<StyledRightDrawerRecord>
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
{!isNewViewableRecordLoading && (
|
||||
<RecordValueSetterEffect recordId={objectRecordId} />
|
||||
)}
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
isNewRightDrawerItemLoading={isNewViewableRecordLoading}
|
||||
/>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer';
|
||||
|
||||
import { SetMainContextStoreComponentInstanceIdEffect } from '@/context-store/components/SetMainContextStoreComponentInstanceIdEffect';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { MainContextStoreComponentInstanceIdSetterEffect } from '@/context-store/components/MainContextStoreComponentInstanceIdSetterEffect';
|
||||
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
|
||||
import { RecordShowContainerContextStoreEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreEffect';
|
||||
|
||||
import { RecordShowContainerContextStoreObjectMetadataIdEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreObjectMetadataIdEffect';
|
||||
import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect';
|
||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||
import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs';
|
||||
import { ShowPageSubContainer } from '@/ui/layout/show-page/components/ShowPageSubContainer';
|
||||
@ -41,16 +42,15 @@ export const RecordShowContainer = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'record-show',
|
||||
}}
|
||||
>
|
||||
<RecordShowContainerContextStoreEffect
|
||||
<>
|
||||
<RecordShowContainerContextStoreObjectMetadataIdEffect
|
||||
recordId={objectRecordId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
{!isInRightDrawer && <SetMainContextStoreComponentInstanceIdEffect />}
|
||||
<RecordShowContainerContextStoreTargetedRecordsEffect
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
{!isInRightDrawer && <MainContextStoreComponentInstanceIdSetterEffect />}
|
||||
{recordFromStore && recordFromStore.deletedAt && (
|
||||
<InformationBannerDeletedRecord
|
||||
recordId={objectRecordId}
|
||||
@ -69,6 +69,6 @@ export const RecordShowContainer = ({
|
||||
isNewRightDrawerItemLoading={isNewRightDrawerItemLoading}
|
||||
/>
|
||||
</ShowPageContainer>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,30 @@
|
||||
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;
|
||||
};
|
@ -1,29 +1,17 @@
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const RecordShowContainerContextStoreEffect = ({
|
||||
export const RecordShowContainerContextStoreTargetedRecordsEffect = ({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
}: {
|
||||
recordId: string;
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
const setContextStoreCurrentObjectMetadataId = useSetRecoilComponentStateV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: objectNameSingular,
|
||||
});
|
||||
|
||||
const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
);
|
||||
@ -33,7 +21,6 @@ export const RecordShowContainerContextStoreEffect = ({
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [recordId],
|
||||
});
|
||||
setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id);
|
||||
setContextStoreNumberOfSelectedRecords(1);
|
||||
|
||||
return () => {
|
||||
@ -41,14 +28,11 @@ export const RecordShowContainerContextStoreEffect = ({
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
});
|
||||
setContextStoreCurrentObjectMetadataId(null);
|
||||
setContextStoreNumberOfSelectedRecords(0);
|
||||
};
|
||||
}, [
|
||||
recordId,
|
||||
setContextStoreTargetedRecordsRule,
|
||||
setContextStoreCurrentObjectMetadataId,
|
||||
objectMetadataItem?.id,
|
||||
setContextStoreNumberOfSelectedRecords,
|
||||
]);
|
||||
|
@ -27,7 +27,7 @@ export const RecordTableInternalEffect = ({
|
||||
|
||||
useListenClickOutsideByClassName({
|
||||
classNames: ['entity-table-cell'],
|
||||
excludeClassNames: ['bottom-bar', 'action-menu-dropdown'],
|
||||
excludeClassNames: ['bottom-bar', 'action-menu-dropdown', 'command-menu'],
|
||||
callback: () => {
|
||||
leaveTableFocus();
|
||||
},
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
|
||||
@ -14,6 +16,10 @@ export const useTriggerActionMenuDropdown = ({
|
||||
}: {
|
||||
recordTableId: string;
|
||||
}) => {
|
||||
const actionMenuInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
ActionMenuComponentInstanceContext,
|
||||
);
|
||||
|
||||
const triggerActionMenuDropdown = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(event: React.MouseEvent, recordId: string) => {
|
||||
@ -24,7 +30,7 @@ export const useTriggerActionMenuDropdown = ({
|
||||
set(
|
||||
extractComponentState(
|
||||
recordIndexActionMenuDropdownPositionComponentState,
|
||||
`action-menu-dropdown-${recordTableId}`,
|
||||
`action-menu-dropdown-${actionMenuInstanceId}`,
|
||||
),
|
||||
{
|
||||
x: event.clientX,
|
||||
@ -48,19 +54,19 @@ export const useTriggerActionMenuDropdown = ({
|
||||
|
||||
const isActionMenuDropdownOpenState = extractComponentState(
|
||||
isDropdownOpenComponentState,
|
||||
`action-menu-dropdown-${recordTableId}`,
|
||||
`action-menu-dropdown-${actionMenuInstanceId}`,
|
||||
);
|
||||
|
||||
const isActionBarOpenState = isBottomBarOpenedComponentState.atomFamily(
|
||||
{
|
||||
instanceId: `action-bar-${recordTableId}`,
|
||||
instanceId: `action-bar-${actionMenuInstanceId}`,
|
||||
},
|
||||
);
|
||||
|
||||
set(isActionBarOpenState, false);
|
||||
set(isActionMenuDropdownOpenState, true);
|
||||
},
|
||||
[recordTableId],
|
||||
[actionMenuInstanceId, recordTableId],
|
||||
);
|
||||
|
||||
return { triggerActionMenuDropdown };
|
||||
|
@ -1,5 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
@ -21,22 +23,32 @@ export const SignInBackgroundMockContainer = () => {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<ViewComponentInstanceContext.Provider value={{ instanceId: viewBarId }}>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
onCurrentViewChange={async () => {}}
|
||||
optionsDropdownButton={<></>}
|
||||
/>
|
||||
<SignInBackgroundMockContainerEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
recordTableId={recordIndexId}
|
||||
viewId={viewBarId}
|
||||
/>
|
||||
<RecordTableWithWrappers
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={viewBarId}
|
||||
updateRecordMutation={() => {}}
|
||||
/>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: recordIndexId,
|
||||
}}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
onCurrentViewChange={async () => {}}
|
||||
optionsDropdownButton={<></>}
|
||||
/>
|
||||
<SignInBackgroundMockContainerEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
recordTableId={recordIndexId}
|
||||
viewId={viewBarId}
|
||||
/>
|
||||
<RecordTableWithWrappers
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={viewBarId}
|
||||
updateRecordMutation={() => {}}
|
||||
/>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
@ -219,6 +219,7 @@ export const Modal = ({
|
||||
|
||||
return (
|
||||
<StyledBackDrop
|
||||
className="modal-backdrop"
|
||||
onMouseDown={stopEventPropagation}
|
||||
modalVariant={modalVariant}
|
||||
>
|
||||
|
@ -47,6 +47,10 @@ const StyledContainer = styled(motion.div)<{ isRightDrawerMinimized: boolean }>`
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
|
||||
.modal-backdrop {
|
||||
background: ${({ theme }) => theme.background.overlayTertiary};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledRightDrawer = styled.div`
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { RecordShowActionMenu } from '@/action-menu/components/RecordShowActionMenu';
|
||||
import { RecordShowRightDrawerActionMenu } from '@/action-menu/components/RecordShowRightDrawerActionMenu';
|
||||
import { Calendar } from '@/activities/calendar/components/Calendar';
|
||||
import { EmailThreads } from '@/activities/emails/components/EmailThreads';
|
||||
import { Attachments } from '@/activities/files/components/Attachments';
|
||||
@ -221,7 +221,7 @@ export const ShowPageSubContainer = ({
|
||||
</StyledContentContainer>
|
||||
{isInRightDrawer && recordFromStore && !recordFromStore.deletedAt && (
|
||||
<StyledButtonContainer>
|
||||
<RecordShowActionMenu actionMenuId={'right-drawer-action-menu'} />
|
||||
<RecordShowRightDrawerActionMenu />
|
||||
</StyledButtonContainer>
|
||||
)}
|
||||
</StyledShowPageRightContainer>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { SetMainContextStoreComponentInstanceIdEffect } from '@/context-store/components/SetMainContextStoreComponentInstanceIdEffect';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { MainContextStoreComponentInstanceIdSetterEffect } from '@/context-store/components/MainContextStoreComponentInstanceIdSetterEffect';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
@ -81,13 +82,19 @@ export const RecordIndexPage = () => {
|
||||
<StyledIndexContainer>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'record-index',
|
||||
instanceId: `record-index-${objectMetadataItem.id}`,
|
||||
}}
|
||||
>
|
||||
<RecordIndexContainerContextStoreObjectMetadataEffect />
|
||||
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||
<SetMainContextStoreComponentInstanceIdEffect />
|
||||
<RecordIndexContainer />
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: `record-index-${objectMetadataItem.id}`,
|
||||
}}
|
||||
>
|
||||
<RecordIndexContainerContextStoreObjectMetadataEffect />
|
||||
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||
<MainContextStoreComponentInstanceIdSetterEffect />
|
||||
<RecordIndexContainer />
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</StyledIndexContainer>
|
||||
</PageBody>
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { RecordShowActionMenu } from '@/action-menu/components/RecordShowActionMenu';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
@ -11,7 +14,6 @@ import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||
import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
||||
import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader';
|
||||
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
||||
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
||||
|
||||
export const RecordShowPage = () => {
|
||||
@ -38,49 +40,61 @@ export const RecordShowPage = () => {
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<RecordValueSetterEffect recordId={objectRecordId} />
|
||||
<PageContainer>
|
||||
<PageTitle title={pageTitle} />
|
||||
<RecordShowPageHeader
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
headerIcon={headerIcon}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: `record-show-${objectRecordId}`,
|
||||
}}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<>
|
||||
{objectNameSingular === CoreObjectNameSingular.Workflow ? (
|
||||
<RecordShowPageWorkflowHeader workflowId={objectRecordId} />
|
||||
) : objectNameSingular ===
|
||||
CoreObjectNameSingular.WorkflowVersion ? (
|
||||
<RecordShowPageWorkflowVersionHeader
|
||||
workflowVersionId={objectRecordId}
|
||||
/>
|
||||
) : (
|
||||
<RecordShowPageBaseHeader
|
||||
{...{
|
||||
isFavorite,
|
||||
handleFavoriteButtonClick,
|
||||
record,
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
labelIdentifierValue: pageName,
|
||||
}}
|
||||
>
|
||||
<RecordShowContainer
|
||||
<RecordValueSetterEffect recordId={objectRecordId} />
|
||||
<PageContainer>
|
||||
<PageTitle title={pageTitle} />
|
||||
<RecordShowPageHeader
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={loading}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
headerIcon={headerIcon}
|
||||
>
|
||||
<>
|
||||
{objectNameSingular === CoreObjectNameSingular.Workflow ? (
|
||||
<RecordShowPageWorkflowHeader workflowId={objectRecordId} />
|
||||
) : objectNameSingular ===
|
||||
CoreObjectNameSingular.WorkflowVersion ? (
|
||||
<RecordShowPageWorkflowVersionHeader
|
||||
workflowVersionId={objectRecordId}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<RecordShowActionMenu
|
||||
{...{
|
||||
isFavorite,
|
||||
handleFavoriteButtonClick,
|
||||
record,
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
labelIdentifierValue: pageName,
|
||||
}}
|
||||
>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={loading}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user