Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make workflow objects read only in frontend #7545

Merged
merged 7 commits into from
Oct 10, 2024
Merged
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 @@ -3,6 +3,7 @@ import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
import { DELETE_MAX_COUNT } from '@/object-record/constants/DeleteMaxCount';
import { useDeleteTableData } from '@/object-record/record-index/options/hooks/useDeleteTableData';
import {
Expand Down Expand Up @@ -55,12 +56,13 @@ export const useComputeActionsBasedOnContextStore = ({
filename: `${objectMetadataItem.nameSingular}.csv`,
});

const isRemoteObject = objectMetadataItem.isRemote;
const isRemote = objectMetadataItem.isRemote;

const numberOfSelectedRecords = contextStoreTargetedRecordIds.length;

const canDelete =
!isRemoteObject && numberOfSelectedRecords < DELETE_MAX_COUNT;
!isObjectMetadataReadOnly(objectMetadataItem) &&
numberOfSelectedRecords < DELETE_MAX_COUNT;

const menuActions: ActionMenuEntry[] = useMemo(
() =>
Expand Down Expand Up @@ -125,7 +127,7 @@ export const useComputeActionsBasedOnContextStore = ({
return {
availableActionsInContext: [
...menuActions,
...(!isRemoteObject && isFavorite && hasOnlyOneRecordSelected
...(!isRemote && isFavorite && hasOnlyOneRecordSelected
? [
{
label: 'Remove from favorites',
Expand All @@ -134,7 +136,7 @@ export const useComputeActionsBasedOnContextStore = ({
},
]
: []),
...(!isRemoteObject && !isFavorite && hasOnlyOneRecordSelected
...(!isRemote && !isFavorite && hasOnlyOneRecordSelected
? [
{
label: 'Add to favorites',
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ export enum CoreObjectNameSingular {
Workflow = 'workflow',
MessageChannelMessageAssociation = 'messageChannelMessageAssociation',
WorkflowVersion = 'workflowVersion',
WorkflowRun = 'workflowRun',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';

export const isObjectMetadataReadOnly = (
objectMetadataItem: Pick<ObjectMetadataItem, 'isRemote' | 'nameSingular'>,
) =>
objectMetadataItem.isRemote ||
isWorkflowSubObjectMetadata(objectMetadataItem.nameSingular);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';

export const isWorkflowSubObjectMetadata = (
objectMetadataNameSingular?: string,
) =>
objectMetadataNameSingular === CoreObjectNameSingular.WorkflowVersion ||
objectMetadataNameSingular === CoreObjectNameSingular.WorkflowRun;
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { useContext } from 'react';
import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor';
import { isFieldRichText } from '@/object-record/record-field/types/guards/isFieldRichText';
import { FieldContext } from '../contexts/FieldContext';
import { isFieldMetadataReadOnly } from '../utils/isFieldMetadataReadOnly';

export const useIsFieldReadOnly = () => {
const { fieldDefinition } = useContext(FieldContext);

const { metadata } = fieldDefinition;

return (
fieldDefinition.metadata.fieldName === 'noteTargets' ||
fieldDefinition.metadata.fieldName === 'taskTargets' ||
isFieldActor(fieldDefinition) ||
isFieldRichText(fieldDefinition)
isFieldRichText(fieldDefinition) ||
isFieldMetadataReadOnly(metadata)
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';

export const isFieldMetadataReadOnly = (fieldMetadata: FieldMetadata) => {
if (
fieldMetadata.fieldName === 'noteTargets' ||
fieldMetadata.fieldName === 'taskTargets'
) {
return true;
}

return (
isWorkflowSubObjectMetadata(fieldMetadata.objectMetadataNameSingular) ||
(fieldMetadata.objectMetadataNameSingular ===
CoreObjectNameSingular.Workflow &&
fieldMetadata.fieldName !== 'name')
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useRecoilValue } from 'recoil';
import { useIcons } from 'twenty-ui';

import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { isObjectMetadataReadOnly } from '@/object-metadata/utils/isObjectMetadataReadOnly';
import { RecordIndexPageKanbanAddButton } from '@/object-record/record-index/components/RecordIndexPageKanbanAddButton';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
Expand Down Expand Up @@ -30,8 +31,11 @@ export const RecordIndexPageHeader = () => {

const recordIndexViewType = useRecoilValue(recordIndexViewTypeState);

const isTable =
recordIndexViewType === ViewType.Table && !objectMetadataItem?.isRemote;
const shouldDisplayAddButton = objectMetadataItem
? !isObjectMetadataReadOnly(objectMetadataItem)
: false;

const isTable = recordIndexViewType === ViewType.Table;

const pageHeaderTitle =
objectMetadataItem?.labelPlural ?? capitalize(objectNamePlural);
Expand All @@ -43,11 +47,12 @@ export const RecordIndexPageHeader = () => {
return (
<PageHeader title={pageHeaderTitle} Icon={Icon}>
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
{isTable ? (
<PageAddButton onClick={handleAddButtonClick} />
) : (
<RecordIndexPageKanbanAddButton />
)}
{shouldDisplayAddButton &&
(isTable ? (
<PageAddButton onClick={handleAddButtonClick} />
) : (
<RecordIndexPageKanbanAddButton />
))}
</PageHeader>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from '@/object-record/record-field/contexts/FieldContext';
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { isFieldMetadataReadOnly } from '@/object-record/record-field/utils/isFieldMetadataReadOnly';
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
Expand Down Expand Up @@ -180,6 +181,8 @@ export const RecordDetailRelationRecordsListItem = ({
[isExpanded],
);

const canEdit = !isFieldMetadataReadOnly(fieldDefinition.metadata);

return (
<>
<RecordValueSetterEffect recordId={relationRecord.id} />
Expand All @@ -195,37 +198,39 @@ export const RecordDetailRelationRecordsListItem = ({
accent="tertiary"
/>
</StyledClickableZone>
<DropdownScope dropdownScopeId={dropdownScopeId}>
<Dropdown
dropdownId={dropdownScopeId}
dropdownPlacement="right-start"
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconDotsVertical}
accent="tertiary"
/>
}
dropdownComponents={
<DropdownMenuItemsContainer>
<MenuItem
LeftIcon={IconUnlink}
text="Detach"
onClick={handleDetach}
{canEdit && (
<DropdownScope dropdownScopeId={dropdownScopeId}>
<Dropdown
dropdownId={dropdownScopeId}
dropdownPlacement="right-start"
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconDotsVertical}
accent="tertiary"
/>
{!isAccountOwnerRelation && (
}
dropdownComponents={
<DropdownMenuItemsContainer>
<MenuItem
LeftIcon={IconTrash}
text="Delete"
accent="danger"
onClick={handleDelete}
LeftIcon={IconUnlink}
text="Detach"
onClick={handleDetach}
/>
)}
</DropdownMenuItemsContainer>
}
dropdownHotkeyScope={{ scope: dropdownScopeId }}
/>
</DropdownScope>
{!isAccountOwnerRelation && (
<MenuItem
LeftIcon={IconTrash}
text="Delete"
accent="danger"
onClick={handleDelete}
/>
)}
</DropdownMenuItemsContainer>
}
dropdownHotkeyScope={{ scope: dropdownScopeId }}
/>
</DropdownScope>
)}
</StyledListItem>
<AnimatedEaseInOut isOpen={isExpanded}>
<PropertyBox>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { usePersistField } from '@/object-record/record-field/hooks/usePersistFi
import { RelationFromManyFieldInputMultiRecordsEffect } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect';
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { isFieldMetadataReadOnly } from '@/object-record/record-field/utils/isFieldMetadataReadOnly';
import { RecordDetailRelationRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList';
import { RecordDetailSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailSection';
import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader';
Expand Down Expand Up @@ -158,6 +159,8 @@ export const RecordDetailRelationSection = ({
recordId,
});

const canEdit = !isFieldMetadataReadOnly(fieldDefinition.metadata);

if (loading) return null;

return (
Expand All @@ -178,49 +181,51 @@ export const RecordDetailRelationSection = ({
hideRightAdornmentOnMouseLeave={!isDropdownOpen && !isMobile}
areRecordsAvailable={relationRecords.length > 0}
rightAdornment={
<DropdownScope dropdownScopeId={dropdownId}>
<StyledAddDropdown
dropdownId={dropdownId}
dropdownPlacement="right-start"
onClose={handleCloseRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={isToOneObject ? IconPencil : IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<RelationPickerScope relationPickerScopeId={dropdownId}>
{isToOneObject ? (
<SingleEntitySelectMenuItemsWithSearch
EmptyIcon={IconForbid}
onEntitySelected={handleRelationPickerEntitySelected}
selectedRelationRecordIds={relationRecordIds}
relationObjectNameSingular={
relationObjectMetadataNameSingular
}
relationPickerScopeId={dropdownId}
onCreate={createNewRecordAndOpenRightDrawer}
/>
) : (
<>
<ObjectMetadataItemsRelationPickerEffect />
<RelationFromManyFieldInputMultiRecordsEffect />
<MultiRecordSelect
canEdit && (
<DropdownScope dropdownScopeId={dropdownId}>
<StyledAddDropdown
dropdownId={dropdownId}
dropdownPlacement="right-start"
onClose={handleCloseRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={isToOneObject ? IconPencil : IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<RelationPickerScope relationPickerScopeId={dropdownId}>
{isToOneObject ? (
<SingleEntitySelectMenuItemsWithSearch
EmptyIcon={IconForbid}
onEntitySelected={handleRelationPickerEntitySelected}
selectedRelationRecordIds={relationRecordIds}
relationObjectNameSingular={
relationObjectMetadataNameSingular
}
relationPickerScopeId={dropdownId}
onCreate={createNewRecordAndOpenRightDrawer}
onChange={updateRelation}
onSubmit={closeDropdown}
/>
</>
)}
</RelationPickerScope>
}
dropdownHotkeyScope={{
scope: dropdownId,
}}
/>
</DropdownScope>
) : (
<>
<ObjectMetadataItemsRelationPickerEffect />
<RelationFromManyFieldInputMultiRecordsEffect />
<MultiRecordSelect
onCreate={createNewRecordAndOpenRightDrawer}
onChange={updateRelation}
onSubmit={closeDropdown}
/>
</>
)}
</RelationPickerScope>
}
dropdownHotkeyScope={{
scope: dropdownId,
}}
/>
</DropdownScope>
)
}
/>
{showContent()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ export const RecordTable = ({
<RecordTableEmptyState />
) : (
<StyledTable className="entity-table-cell">
<RecordTableHeader />
<RecordTableHeader
objectMetadataNameSingular={objectNameSingular}
/>
<RecordTableBody />
</StyledTable>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useObjectIsRemote } from '@/object-metadata/hooks/useObjectIsRemote';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { RecordTableEmptyStateNoRecordAtAll } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordAtAll';
Expand All @@ -18,7 +17,7 @@ export const RecordTableEmptyState = () => {
const { totalCount } = useFindManyRecords({ objectNameSingular, limit: 1 });
const noRecordAtAll = totalCount === 0;

const isRemote = useObjectIsRemote(objectMetadataItem);
const isRemote = objectMetadataItem.isRemote;

const isSoftDeleteActive = useRecoilValue(isSoftDeleteActiveState);

Expand Down
Loading
Loading