fix(command-menu-item): persist overrides after save and add reset-to-default (#21623)
## Context Command menu items are an overridable entity (like page-layout / FIELDS widgets), but the override flow in layout-customization mode was broken: - **Move / pin-unpin / hide-label didn't persist.** `useSaveCommandMenuItemsDraft` fired the `updateCommandMenuItem` mutations (backend persisted correctly) but never wrote the result back into `metadataStoreState`, the source the live menu and edit panel read from. So the UI reverted on exit and changes only showed after a hard reload. - **No true "reset to default".** Existing reset controls only reverted the draft to the last-saved values (which still contained overrides). there was no way to clear overrides back to the original values after a save. Notes - removed the footer "Reset to default" button. This is not clear to me how we want to build, let's re-implement better in the next version - reset are done on click and not delayed on the save. This is similar to other reset to default on page layouts where we actually usually reload the component and this is because the FE has no idea what's original VS override from the response itself <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21623?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -3287,6 +3287,7 @@ type Mutation {
|
||||
updateOneLogicFunction(input: UpdateLogicFunctionFromSourceInput!): Boolean!
|
||||
createCommandMenuItem(input: CreateCommandMenuItemInput!): CommandMenuItem!
|
||||
updateCommandMenuItem(input: UpdateCommandMenuItemInput!): CommandMenuItem!
|
||||
resetCommandMenuItem(id: UUID!): CommandMenuItem!
|
||||
deleteCommandMenuItem(id: UUID!): CommandMenuItem!
|
||||
createFrontComponent(input: CreateFrontComponentInput!): FrontComponent!
|
||||
updateFrontComponent(input: UpdateFrontComponentInput!): FrontComponent!
|
||||
|
||||
@@ -2809,6 +2809,7 @@ export interface Mutation {
|
||||
updateOneLogicFunction: Scalars['Boolean']
|
||||
createCommandMenuItem: CommandMenuItem
|
||||
updateCommandMenuItem: CommandMenuItem
|
||||
resetCommandMenuItem: CommandMenuItem
|
||||
deleteCommandMenuItem: CommandMenuItem
|
||||
createFrontComponent: FrontComponent
|
||||
updateFrontComponent: FrontComponent
|
||||
@@ -5952,6 +5953,7 @@ export interface MutationGenqlSelection{
|
||||
updateOneLogicFunction?: { __args: {input: UpdateLogicFunctionFromSourceInput} }
|
||||
createCommandMenuItem?: (CommandMenuItemGenqlSelection & { __args: {input: CreateCommandMenuItemInput} })
|
||||
updateCommandMenuItem?: (CommandMenuItemGenqlSelection & { __args: {input: UpdateCommandMenuItemInput} })
|
||||
resetCommandMenuItem?: (CommandMenuItemGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
deleteCommandMenuItem?: (CommandMenuItemGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
createFrontComponent?: (FrontComponentGenqlSelection & { __args: {input: CreateFrontComponentInput} })
|
||||
updateFrontComponent?: (FrontComponentGenqlSelection & { __args: {input: UpdateFrontComponentInput} })
|
||||
|
||||
@@ -7585,6 +7585,15 @@ export default {
|
||||
]
|
||||
}
|
||||
],
|
||||
"resetCommandMenuItem": [
|
||||
35,
|
||||
{
|
||||
"id": [
|
||||
3,
|
||||
"UUID!"
|
||||
]
|
||||
}
|
||||
],
|
||||
"deleteCommandMenuItem": [
|
||||
35,
|
||||
{
|
||||
|
||||
@@ -2549,6 +2549,7 @@ export type Mutation = {
|
||||
renewToken: AuthTokens;
|
||||
resendEmailVerificationToken: ResendEmailVerificationToken;
|
||||
resendWorkspaceInvitation: SendInvitations;
|
||||
resetCommandMenuItem: CommandMenuItem;
|
||||
resetPageLayoutTabToDefault: PageLayoutTab;
|
||||
resetPageLayoutToDefault: PageLayout;
|
||||
resetPageLayoutWidgetToDefault: PageLayoutWidget;
|
||||
@@ -3240,6 +3241,11 @@ export type MutationResendWorkspaceInvitationArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationResetCommandMenuItemArgs = {
|
||||
id: Scalars['UUID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationResetPageLayoutTabToDefaultArgs = {
|
||||
id: Scalars['String']['input'];
|
||||
};
|
||||
@@ -6750,6 +6756,16 @@ export type CommandMenuItemFieldsFragment = { __typename?: 'CommandMenuItem', id
|
||||
| { __typename?: 'PathCommandMenuItemPayload', path: string }
|
||||
| null };
|
||||
|
||||
export type ResetCommandMenuItemMutationVariables = Exact<{
|
||||
id: Scalars['UUID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ResetCommandMenuItemMutation = { __typename?: 'Mutation', resetCommandMenuItem: { __typename?: 'CommandMenuItem', id: string, applicationId?: string | null, workflowVersionId?: string | null, frontComponentId?: string | null, engineComponentKey: EngineComponentKey, label: string, icon?: string | null, shortLabel?: string | null, position: number, isPinned: boolean, hotKeys?: Array<string> | null, conditionalAvailabilityExpression?: string | null, availabilityType: CommandMenuItemAvailabilityType, availabilityObjectMetadataId?: string | null, pageLayoutId?: string | null, isActive: boolean, frontComponent?: { __typename?: 'FrontComponent', id: string, name: string, isHeadless: boolean } | null, payload?:
|
||||
| { __typename?: 'ObjectMetadataCommandMenuItemPayload', objectMetadataItemId: string }
|
||||
| { __typename?: 'PathCommandMenuItemPayload', path: string }
|
||||
| null } };
|
||||
|
||||
export type UpdateCommandMenuItemMutationVariables = Exact<{
|
||||
input: UpdateCommandMenuItemInput;
|
||||
}>;
|
||||
@@ -8616,6 +8632,7 @@ export const CheckUserExistsDocument = {"kind":"Document","definitions":[{"kind"
|
||||
export const FindApplicationRegistrationByClientIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindApplicationRegistrationByClientId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"clientId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findApplicationRegistrationByClientId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"clientId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"clientId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"websiteUrl"}}]}}]}}]} as unknown as DocumentNode<FindApplicationRegistrationByClientIdQuery, FindApplicationRegistrationByClientIdQueryVariables>;
|
||||
export const GetPublicWorkspaceDataByDomainDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPublicWorkspaceDataByDomain"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"origin"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getPublicWorkspaceDataByDomain"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"origin"},"value":{"kind":"Variable","name":{"kind":"Name","value":"origin"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceUrls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkspaceUrlsFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"authProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sso"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"issuer"}}]}},{"kind":"Field","name":{"kind":"Name","value":"google"}},{"kind":"Field","name":{"kind":"Name","value":"magicLink"}},{"kind":"Field","name":{"kind":"Name","value":"password"}},{"kind":"Field","name":{"kind":"Name","value":"microsoft"}}]}},{"kind":"Field","name":{"kind":"Name","value":"authBypassProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"google"}},{"kind":"Field","name":{"kind":"Name","value":"password"}},{"kind":"Field","name":{"kind":"Name","value":"microsoft"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkspaceUrlsFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUrls"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subdomainUrl"}},{"kind":"Field","name":{"kind":"Name","value":"customUrl"}}]}}]} as unknown as DocumentNode<GetPublicWorkspaceDataByDomainQuery, GetPublicWorkspaceDataByDomainQueryVariables>;
|
||||
export const ValidatePasswordResetTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ValidatePasswordResetToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validatePasswordResetToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"passwordResetToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"hasPassword"}}]}}]}}]} as unknown as DocumentNode<ValidatePasswordResetTokenQuery, ValidatePasswordResetTokenQueryVariables>;
|
||||
export const ResetCommandMenuItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResetCommandMenuItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resetCommandMenuItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommandMenuItemFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommandMenuItemFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommandMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"workflowVersionId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponentId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isHeadless"}}]}},{"kind":"Field","name":{"kind":"Name","value":"engineComponentKey"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"shortLabel"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"isPinned"}},{"kind":"Field","name":{"kind":"Name","value":"payload"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PathCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ObjectMetadataCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objectMetadataItemId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"hotKeys"}},{"kind":"Field","name":{"kind":"Name","value":"conditionalAvailabilityExpression"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityType"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}}]} as unknown as DocumentNode<ResetCommandMenuItemMutation, ResetCommandMenuItemMutationVariables>;
|
||||
export const UpdateCommandMenuItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateCommandMenuItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateCommandMenuItemInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateCommandMenuItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommandMenuItemFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommandMenuItemFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommandMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"workflowVersionId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponentId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isHeadless"}}]}},{"kind":"Field","name":{"kind":"Name","value":"engineComponentKey"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"shortLabel"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"isPinned"}},{"kind":"Field","name":{"kind":"Name","value":"payload"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PathCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ObjectMetadataCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objectMetadataItemId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"hotKeys"}},{"kind":"Field","name":{"kind":"Name","value":"conditionalAvailabilityExpression"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityType"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}}]} as unknown as DocumentNode<UpdateCommandMenuItemMutation, UpdateCommandMenuItemMutationVariables>;
|
||||
export const FindManyCommandMenuItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindManyCommandMenuItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"commandMenuItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommandMenuItemFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommandMenuItemFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommandMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"workflowVersionId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponentId"}},{"kind":"Field","name":{"kind":"Name","value":"frontComponent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isHeadless"}}]}},{"kind":"Field","name":{"kind":"Name","value":"engineComponentKey"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"shortLabel"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"isPinned"}},{"kind":"Field","name":{"kind":"Name","value":"payload"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PathCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ObjectMetadataCommandMenuItemPayload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objectMetadataItemId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"hotKeys"}},{"kind":"Field","name":{"kind":"Name","value":"conditionalAvailabilityExpression"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityType"}},{"kind":"Field","name":{"kind":"Name","value":"availabilityObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}}]} as unknown as DocumentNode<FindManyCommandMenuItemsQuery, FindManyCommandMenuItemsQueryVariables>;
|
||||
export const DuplicateDashboardDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DuplicateDashboard"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duplicateDashboard"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<DuplicateDashboardMutation, DuplicateDashboardMutationVariables>;
|
||||
|
||||
+6
-9
@@ -1,3 +1,4 @@
|
||||
import { useResetCommandMenuItemToDefault } from '@/command-menu-item/edit/hooks/useResetCommandMenuItemToDefault';
|
||||
import { useUpdateCommandMenuItemInDraft } from '@/command-menu-item/edit/hooks/useUpdateCommandMenuItemInDraft';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
@@ -34,14 +35,13 @@ export const CommandMenuItemOptionsDropdown = ({
|
||||
const dropdownId = getCommandMenuItemOptionsDropdownId(itemId);
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
const { updateCommandMenuItemInDraft } = useUpdateCommandMenuItemInDraft();
|
||||
const { resetCommandMenuItemToDefault } = useResetCommandMenuItemToDefault();
|
||||
|
||||
const normalizedServerShortLabel = serverShortLabel ?? null;
|
||||
const normalizedShortLabel = shortLabel ?? null;
|
||||
const hasNoShortLabel = normalizedServerShortLabel === null;
|
||||
const isLabelHidden =
|
||||
normalizedShortLabel === null && isDefined(normalizedServerShortLabel);
|
||||
const hasShortLabelOverride =
|
||||
normalizedShortLabel !== normalizedServerShortLabel;
|
||||
|
||||
const handleToggleHideLabel = (toggled: boolean) => {
|
||||
updateCommandMenuItemInDraft(itemId, {
|
||||
@@ -49,11 +49,9 @@ export const CommandMenuItemOptionsDropdown = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleResetLabelToDefault = () => {
|
||||
updateCommandMenuItemInDraft(itemId, {
|
||||
shortLabel: normalizedServerShortLabel,
|
||||
});
|
||||
const handleResetToDefault = async () => {
|
||||
closeDropdown(dropdownId);
|
||||
await resetCommandMenuItemToDefault(itemId);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -74,10 +72,9 @@ export const CommandMenuItemOptionsDropdown = ({
|
||||
/>
|
||||
<MenuItem
|
||||
LeftIcon={IconRefresh}
|
||||
onClick={handleResetLabelToDefault}
|
||||
onClick={handleResetToDefault}
|
||||
accent="default"
|
||||
text={t`Reset label to default`}
|
||||
disabled={!hasShortLabelOverride}
|
||||
text={t`Reset to default`}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
|
||||
-18
@@ -2,7 +2,6 @@ import { CommandMenuItemEditRecordSelectionDropdown } from '@/command-menu-item/
|
||||
import { CommandMenuItemOptionsDropdown } from '@/command-menu-item/edit/components/CommandMenuItemOptionsDropdown';
|
||||
import { useEditableCommandMenuItems } from '@/command-menu-item/edit/hooks/useEditableCommandMenuItems';
|
||||
import { useReorderCommandMenuItemsInDraft } from '@/command-menu-item/edit/hooks/useReorderCommandMenuItemsInDraft';
|
||||
import { useResetCommandMenuItemsDraft } from '@/command-menu-item/edit/hooks/useResetCommandMenuItemsDraft';
|
||||
import { useUpdateCommandMenuItemInDraft } from '@/command-menu-item/edit/hooks/useUpdateCommandMenuItemInDraft';
|
||||
import { useCurrentCommandMenuContextApi } from '@/command-menu-item/hooks/useCurrentCommandMenuContextApi';
|
||||
import { commandMenuItemsSelector } from '@/command-menu-item/states/commandMenuItemsSelector';
|
||||
@@ -14,7 +13,6 @@ import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState';
|
||||
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
|
||||
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { SidePanelFooter } from '@/ui/layout/side-panel/components/SidePanelFooter';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { type DropResult } from '@hello-pangea/dnd';
|
||||
import { styled } from '@linaria/react';
|
||||
@@ -28,10 +26,8 @@ import {
|
||||
IconDotsVertical,
|
||||
IconPin,
|
||||
IconPinnedOff,
|
||||
IconRefresh,
|
||||
useIcons,
|
||||
} from 'twenty-ui-deprecated/display';
|
||||
import { Button } from 'twenty-ui-deprecated/input';
|
||||
import { MenuItem, MenuItemDraggable } from 'twenty-ui-deprecated/navigation';
|
||||
import { themeCssVariables } from 'twenty-ui-deprecated/theme-constants';
|
||||
import { type CommandMenuItemFieldsFragment } from '~/generated-metadata/graphql';
|
||||
@@ -79,7 +75,6 @@ export const SidePanelCommandMenuItemEditPage = () => {
|
||||
);
|
||||
const { updateCommandMenuItemInDraft } = useUpdateCommandMenuItemInDraft();
|
||||
const { reorderCommandMenuItemInDraft } = useReorderCommandMenuItemsInDraft();
|
||||
const { resetCommandMenuItemsDraft } = useResetCommandMenuItemsDraft();
|
||||
|
||||
const editableCommandMenuItems = useEditableCommandMenuItems();
|
||||
|
||||
@@ -298,19 +293,6 @@ export const SidePanelCommandMenuItemEditPage = () => {
|
||||
</SidePanelGroup>
|
||||
</SidePanelList>
|
||||
</StyledContent>
|
||||
<SidePanelFooter
|
||||
actions={[
|
||||
<Button
|
||||
key="reset"
|
||||
Icon={IconRefresh}
|
||||
title={t`Reset to default`}
|
||||
variant="secondary"
|
||||
accent="default"
|
||||
size="small"
|
||||
onClick={resetCommandMenuItemsDraft}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { useMutation } from '@apollo/client/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { commandMenuItemsDraftState } from '@/command-menu-item/edit/states/commandMenuItemsDraftState';
|
||||
import { RESET_COMMAND_MENU_ITEM } from '@/command-menu-item/graphql/mutations/resetCommandMenuItem';
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import {
|
||||
type ResetCommandMenuItemMutation,
|
||||
type ResetCommandMenuItemMutationVariables,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useResetCommandMenuItemToDefault = () => {
|
||||
const store = useStore();
|
||||
const [resetCommandMenuItem] = useMutation<
|
||||
ResetCommandMenuItemMutation,
|
||||
ResetCommandMenuItemMutationVariables
|
||||
>(RESET_COMMAND_MENU_ITEM);
|
||||
const { updateInDraft, applyChanges } = useUpdateMetadataStoreDraft();
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
const resetCommandMenuItemToDefault = useCallback(
|
||||
async (id: string) => {
|
||||
try {
|
||||
const result = await resetCommandMenuItem({ variables: { id } });
|
||||
|
||||
const resetItem = result.data?.resetCommandMenuItem;
|
||||
|
||||
if (!isDefined(resetItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateInDraft('commandMenuItems', [resetItem]);
|
||||
applyChanges();
|
||||
|
||||
const draft = store.get(commandMenuItemsDraftState.atom);
|
||||
|
||||
if (isDefined(draft)) {
|
||||
store.set(
|
||||
commandMenuItemsDraftState.atom,
|
||||
draft.map((item) =>
|
||||
item.id === id ? { ...item, ...resetItem } : item,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (CombinedGraphQLErrors.is(error)) {
|
||||
handleMetadataError(error, {
|
||||
primaryMetadataName: 'commandMenuItem',
|
||||
operationType: CrudOperationType.UPDATE,
|
||||
});
|
||||
} else {
|
||||
enqueueErrorSnackBar({ message: t`An error occurred.` });
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
resetCommandMenuItem,
|
||||
updateInDraft,
|
||||
applyChanges,
|
||||
store,
|
||||
handleMetadataError,
|
||||
enqueueErrorSnackBar,
|
||||
],
|
||||
);
|
||||
|
||||
return { resetCommandMenuItemToDefault };
|
||||
};
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
import { commandMenuItemsDraftState } from '@/command-menu-item/edit/states/commandMenuItemsDraftState';
|
||||
import { commandMenuItemsSelector } from '@/command-menu-item/states/commandMenuItemsSelector';
|
||||
|
||||
// Resets the draft to the current server state, discarding all user edits.
|
||||
export const useResetCommandMenuItemsDraft = () => {
|
||||
const store = useStore();
|
||||
|
||||
const resetCommandMenuItemsDraft = useCallback(() => {
|
||||
const serverItems = store.get(commandMenuItemsSelector.atom);
|
||||
|
||||
store.set(
|
||||
commandMenuItemsDraftState.atom,
|
||||
serverItems.map((item) => ({ ...item })),
|
||||
);
|
||||
}, [store]);
|
||||
|
||||
return { resetCommandMenuItemsDraft };
|
||||
};
|
||||
+25
-3
@@ -6,13 +6,22 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { commandMenuItemsDraftState } from '@/command-menu-item/edit/states/commandMenuItemsDraftState';
|
||||
import { UPDATE_COMMAND_MENU_ITEM } from '@/command-menu-item/graphql/mutations/updateCommandMenuItem';
|
||||
import { commandMenuItemsSelector } from '@/command-menu-item/states/commandMenuItemsSelector';
|
||||
import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { type UpdateCommandMenuItemInput } from '~/generated-metadata/graphql';
|
||||
import {
|
||||
type UpdateCommandMenuItemInput,
|
||||
type UpdateCommandMenuItemMutation,
|
||||
type UpdateCommandMenuItemMutationVariables,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useSaveCommandMenuItemsDraft = () => {
|
||||
const store = useStore();
|
||||
const [updateCommandMenuItem] = useMutation(UPDATE_COMMAND_MENU_ITEM);
|
||||
const [updateCommandMenuItem] = useMutation<
|
||||
UpdateCommandMenuItemMutation,
|
||||
UpdateCommandMenuItemMutationVariables
|
||||
>(UPDATE_COMMAND_MENU_ITEM);
|
||||
const commandMenuItems = useAtomStateValue(commandMenuItemsSelector);
|
||||
const { updateInDraft, applyChanges } = useUpdateMetadataStoreDraft();
|
||||
|
||||
const saveCommandMenuItemsDraft = useCallback(async () => {
|
||||
const draft = store.get(commandMenuItemsDraftState.atom);
|
||||
@@ -39,6 +48,10 @@ export const useSaveCommandMenuItemsDraft = () => {
|
||||
);
|
||||
});
|
||||
|
||||
if (changedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
changedItems.map((item) => {
|
||||
const input: UpdateCommandMenuItemInput = {
|
||||
@@ -51,7 +64,16 @@ export const useSaveCommandMenuItemsDraft = () => {
|
||||
return updateCommandMenuItem({ variables: { input } });
|
||||
}),
|
||||
);
|
||||
}, [store, commandMenuItems, updateCommandMenuItem]);
|
||||
|
||||
updateInDraft('commandMenuItems', changedItems);
|
||||
applyChanges();
|
||||
}, [
|
||||
store,
|
||||
commandMenuItems,
|
||||
updateCommandMenuItem,
|
||||
updateInDraft,
|
||||
applyChanges,
|
||||
]);
|
||||
|
||||
return { saveCommandMenuItemsDraft };
|
||||
};
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { COMMAND_MENU_ITEM_FRAGMENT } from '@/command-menu-item/graphql/fragments/commandMenuItemFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const RESET_COMMAND_MENU_ITEM = gql`
|
||||
${COMMAND_MENU_ITEM_FRAGMENT}
|
||||
mutation ResetCommandMenuItem($id: UUID!) {
|
||||
resetCommandMenuItem(id: $id) {
|
||||
...CommandMenuItemFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
+3
@@ -8,6 +8,7 @@ export enum CommandMenuItemExceptionCode {
|
||||
COMMAND_MENU_ITEM_NOT_FOUND = 'COMMAND_MENU_ITEM_NOT_FOUND',
|
||||
INVALID_COMMAND_MENU_ITEM_INPUT = 'INVALID_COMMAND_MENU_ITEM_INPUT',
|
||||
WORKFLOW_OR_FRONT_COMPONENT_REQUIRED = 'WORKFLOW_OR_FRONT_COMPONENT_REQUIRED',
|
||||
COMMAND_MENU_ITEM_CANNOT_BE_RESET = 'COMMAND_MENU_ITEM_CANNOT_BE_RESET',
|
||||
}
|
||||
|
||||
const getCommandMenuItemExceptionUserFriendlyMessage = (
|
||||
@@ -20,6 +21,8 @@ const getCommandMenuItemExceptionUserFriendlyMessage = (
|
||||
return msg`Invalid command menu item input.`;
|
||||
case CommandMenuItemExceptionCode.WORKFLOW_OR_FRONT_COMPONENT_REQUIRED:
|
||||
return msg`Either workflow version or front component is required.`;
|
||||
case CommandMenuItemExceptionCode.COMMAND_MENU_ITEM_CANNOT_BE_RESET:
|
||||
return msg`Custom command menu item cannot be reset to default.`;
|
||||
default:
|
||||
assertUnreachable(code);
|
||||
}
|
||||
|
||||
+9
@@ -136,6 +136,15 @@ export class CommandMenuItemResolver {
|
||||
return await this.commandMenuItemService.update(input, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => CommandMenuItemDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async resetCommandMenuItem(
|
||||
@Args('id', { type: () => UUIDScalarType }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<CommandMenuItemDTO> {
|
||||
return await this.commandMenuItemService.reset(id, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => CommandMenuItemDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async deleteCommandMenuItem(
|
||||
|
||||
+84
@@ -245,6 +245,90 @@ export class CommandMenuItemService {
|
||||
);
|
||||
}
|
||||
|
||||
async reset(id: string, workspaceId: string): Promise<CommandMenuItemDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const { flatCommandMenuItemMaps: existingFlatCommandMenuItemMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatCommandMenuItemMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const existingFlatCommandMenuItem = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: existingFlatCommandMenuItemMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatCommandMenuItem)) {
|
||||
throw new CommandMenuItemException(
|
||||
'Command menu item not found',
|
||||
CommandMenuItemExceptionCode.COMMAND_MENU_ITEM_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
existingFlatCommandMenuItem.applicationUniversalIdentifier ===
|
||||
workspaceCustomFlatApplication.universalIdentifier
|
||||
) {
|
||||
throw new CommandMenuItemException(
|
||||
'Custom command menu item cannot be reset to default',
|
||||
CommandMenuItemExceptionCode.COMMAND_MENU_ITEM_CANNOT_BE_RESET,
|
||||
);
|
||||
}
|
||||
|
||||
const flatCommandMenuItemToUpdate: FlatCommandMenuItem = {
|
||||
...existingFlatCommandMenuItem,
|
||||
isActive: true,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
commandMenuItem: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [flatCommandMenuItemToUpdate],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while resetting command menu item to default',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatCommandMenuItemMaps: recomputedFlatCommandMenuItemMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatCommandMenuItemMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return fromFlatCommandMenuItemToCommandMenuItemDto(
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedFlatCommandMenuItemMaps,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async delete(id: string, workspaceId: string): Promise<CommandMenuItemDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ export const commandMenuItemGraphqlApiExceptionHandler = (error: Error) => {
|
||||
throw new NotFoundError(error);
|
||||
case CommandMenuItemExceptionCode.INVALID_COMMAND_MENU_ITEM_INPUT:
|
||||
case CommandMenuItemExceptionCode.WORKFLOW_OR_FRONT_COMPONENT_REQUIRED:
|
||||
case CommandMenuItemExceptionCode.COMMAND_MENU_ITEM_CANNOT_BE_RESET:
|
||||
throw new UserInputError(error);
|
||||
default: {
|
||||
return assertUnreachable(error.code);
|
||||
|
||||
Reference in New Issue
Block a user