Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { useContext } from 'react';

export const Action = ({
onClick,
disabled = false,
closeSidePanelOnShowPageOptionsActionExecution = false,
closeSidePanelOnCommandMenuListActionExecution = true,
}: {
onClick: () => void;
disabled?: boolean;
closeSidePanelOnShowPageOptionsActionExecution?: boolean;
closeSidePanelOnCommandMenuListActionExecution?: boolean;
}) => {
Expand All @@ -24,9 +26,13 @@ export const Action = ({
}

const handleClick = () => {
if (disabled) {
return;
}

closeActionMenu();
onClick();
};

return <ActionDisplay onClick={handleClick} />;
return <ActionDisplay onClick={handleClick} disabled={disabled} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ export const ActionButton = ({
action,
onClick,
to,
disabled = false,
}: {
action: ActionDisplayProps;
onClick?: (event?: React.MouseEvent<HTMLElement>) => void;
to?: string;
disabled?: boolean;
}) => {
const label = getActionLabel(action.label);

Expand All @@ -38,6 +40,7 @@ export const ActionButton = ({
onClick={onClick}
title={shortLabel}
ariaLabel={label}
disabled={disabled}
/>
) : (
<div id={`action-menu-entry-${action.key}`} key={action.key}>
Expand All @@ -49,6 +52,7 @@ export const ActionButton = ({
to={to}
onClick={onClick}
ariaLabel={label}
disabled={disabled}
/>
<StyledWrapper>
<AppTooltip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ export type ActionDisplayProps = {
export const ActionDisplay = ({
onClick,
to,
disabled = false,
}: {
onClick?: (event?: React.MouseEvent<HTMLElement>) => void;
to?: string;
disabled?: boolean;
}) => {
const action = useContext(ActionConfigContext);
const { displayType } = useContext(ActionMenuContext);
Expand All @@ -35,15 +37,36 @@ export const ActionDisplay = ({
}

if (displayType === 'button') {
return <ActionButton action={action} onClick={onClick} to={to} />;
return (
<ActionButton
action={action}
onClick={onClick}
to={to}
disabled={disabled}
/>
);
}

if (displayType === 'listItem') {
return <ActionListItem action={action} onClick={onClick} to={to} />;
return (
<ActionListItem
action={action}
onClick={onClick}
to={to}
disabled={disabled}
/>
);
}

if (displayType === 'dropdownItem') {
return <ActionDropdownItem action={action} onClick={onClick} to={to} />;
return (
<ActionDropdownItem
action={action}
onClick={onClick}
to={to}
disabled={disabled}
/>
);
}

return assertUnreachable(displayType, 'Unsupported display type');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ export const ActionDropdownItem = ({
action,
onClick,
to,
disabled = false,
}: {
action: ActionDisplayProps;
onClick?: () => void;
to?: string;
disabled?: boolean;
}) => {
const navigate = useNavigate();

const handleClick = () => {
if (disabled) {
return;
}

onClick?.();
if (isDefined(to)) {
navigate(to);
Expand All @@ -45,6 +51,7 @@ export const ActionDropdownItem = ({
LeftIcon={action.Icon}
onClick={handleClick}
text={getActionLabel(action.label)}
disabled={disabled}
/>
</SelectableListItem>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ export const ActionListItem = ({
action,
onClick,
to,
disabled = false,
}: {
action: ActionDisplayProps;
onClick?: () => void;
to?: string;
disabled?: boolean;
}) => {
const navigate = useNavigate();

const handleClick = () => {
if (disabled) {
return;
}

onClick?.();
if (isDefined(to)) {
navigate(to);
Expand All @@ -33,6 +39,7 @@ export const ActionListItem = ({
to={to}
onClick={onClick}
hotKeys={action.hotKeys}
disabled={disabled}
/>
</SelectableListItem>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ export const NavigateToNextRecordSingleRecordAction = () => {

const recordId = useSelectedRecordIdOrThrow();

const { navigateToNextRecord } = useRecordShowPagePagination(
objectMetadataItem.nameSingular,
recordId,
);
const { navigateToNextRecord, canNavigateToNextRecord } =
useRecordShowPagePagination(objectMetadataItem.nameSingular, recordId);

return <Action onClick={navigateToNextRecord} />;
return (
<Action
onClick={navigateToNextRecord}
disabled={!canNavigateToNextRecord}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ export const NavigateToPreviousRecordSingleRecordAction = () => {

const recordId = useSelectedRecordIdOrThrow();

const { navigateToPreviousRecord } = useRecordShowPagePagination(
objectMetadataItem.nameSingular,
recordId,
);
const { navigateToPreviousRecord, canNavigateToPreviousRecord } =
useRecordShowPagePagination(objectMetadataItem.nameSingular, recordId);

return <Action onClick={navigateToPreviousRecord} />;
return (
<Action
onClick={navigateToPreviousRecord}
disabled={!canNavigateToPreviousRecord}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
orderBy: args.orderBy,
});

if (isDefined(args.offset)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
compositeTypeDefinitions,
} from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';

import { type ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';

import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';

Expand All @@ -15,12 +22,14 @@ export const buildColumnsToSelect = ({
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
orderBy,
}: {
select: Record<string, unknown>;
relations: Record<string, unknown>;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
orderBy?: ObjectRecordOrderBy;
}) => {
const requiredRelationColumns = getRequiredRelationColumns(
relations,
Expand All @@ -39,6 +48,16 @@ export const buildColumnsToSelect = ({
fieldsToSelect[columnName] = true;
}

const orderByColumnNames = extractColumnNamesFromOrderBy(
orderBy,
flatObjectMetadata,
flatFieldMetadataMaps,
);

for (const columnName of orderByColumnNames) {
fieldsToSelect[columnName] = true;
}

return { ...fieldsToSelect, id: true };
};

Expand Down Expand Up @@ -101,3 +120,74 @@ const getRequiredRelationColumns = (

return requiredColumns;
};

const extractColumnNamesFromOrderBy = (
orderBy: ObjectRecordOrderBy | undefined,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
) => {
if (!isDefined(orderBy) || orderBy.length === 0) {
return [];
}

const orderByFlattened = orderBy.reduce(
(acc, orderByItem) => ({ ...acc, ...orderByItem }),
{},
);

const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);

const columnNames = [];

for (const [fieldName, orderByValue] of Object.entries(orderByFlattened)) {
const fieldMetadataId = fieldIdByName[fieldName];

if (!fieldMetadataId) {
columnNames.push(fieldName);
continue;
}

const fieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: fieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
});

if (
isCompositeFieldMetadataType(fieldMetadata.type) &&
isDefined(orderByValue)
) {
const compositeType = compositeTypeDefinitions.get(fieldMetadata.type);

if (!compositeType) {
columnNames.push(fieldName);
continue;
}

const subFieldNames = Object.keys(orderByValue);

for (const subFieldName of subFieldNames) {
const compositeProperty = compositeType.properties.find(
(property) => property.name === subFieldName,
);

if (!compositeProperty) {
continue;
}

const columnName = computeCompositeColumnName(
fieldName,
compositeProperty,
);

columnNames.push(columnName);
}
} else {
columnNames.push(fieldName);
}
}

return columnNames;
};
Loading
Loading