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

Support custom object renaming #7504

Merged
merged 26 commits into from
Oct 24, 2024
Merged

Support custom object renaming #7504

merged 26 commits into from
Oct 24, 2024

Conversation

gitstart-app[bot]
Copy link
Contributor

@gitstart-app gitstart-app bot commented Oct 8, 2024

This PR was created by GitStart to address the requirements from this ticket: TWNTY-5491.
This ticket was imported from: TWNTY-5491


Description

How To Test:\

  1. Reset db using npx nx database:reset twenty-server on this PR

  2. Run both backend and frontend

  3. Navigate to settings/data-model/objects/ page

  4. Select a Custom object from the list or create a new Custom object

  5. Navigate to custom object details page and click on edit button

  6. Finally edit the object details.

Issues and bugs
The Typecheck is failing but we could not see this error locally
There is a bug after updating the label of a custom object. View title is not updated till refreshing the page. We could not find a consistent way to update this, should we reload the page after editing an object?

### Demo

https://www.loom.com/share/64ecb57efad7498d99085cb11480b5dd?sid=28d0868c-e54f-454d-8432-3f789be9e2b7

Refs

#5491

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR implements custom object renaming functionality in the Twenty application. Key changes include:

  • Added 'areLabelAndNameSync' field to ObjectMetadataEntity for controlling label and API name synchronization
  • Updated SettingsDataModelObjectAboutForm with new UI elements for advanced settings and API name fields
  • Modified ObjectMetadataService to handle object renaming and related metadata updates
  • Introduced SyncObjectLabelAndNameToggle component for toggling synchronization
  • Updated validation schemas and GraphQL queries to support the new renaming feature

20 file(s) reviewed, 10 comment(s)
Edit PR Review Bot Settings

Comment on lines 104 to 109
const areLabelAndNameSync = watch('areLabelAndNameSync');
const labelSingular = watch('labelSingular');
const labelPlural = watch('labelPlural');
const apiNameTooltipText = areLabelAndNameSync
? 'Deactivate "Synchronize Objects Labels and API Names" to set a custom API name'
: 'Input must be in camel case and cannot start with a number';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider memoizing these watch calls to optimize performance

Comment on lines 125 to 134
useEffect(() => {
if (areLabelAndNameSync) {
labelSingular &&
setValue(
'nameSingular',
computeMetadataNameFromLabelOrThrow(labelSingular),
{ shouldDirty: true },
);
}
}, [areLabelAndNameSync, labelSingular, setValue]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider combining this effect with the previous one to reduce code duplication

)}
/>
</StyledSectionWrapper>
<AnimatePresence>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Large conditional render block may impact performance. Consider extracting to a separate component

Comment on lines 1569 to 1573
private async updateObjectNamesandLabels(
oldObject: ObjectMetadataEntity,
updatedObject: ObjectMetadataEntity,
input: UpdateOneObjectInput,
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Method name has a typo: 'updateObjectNamesandLabels' should be 'updateObjectNamesAndLabels'

);
}

if (updatedObject.areLabelAndNameSync) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: This block doesn't handle the case where both label and name are updated simultaneously. Consider adding a check for this scenario

updatedObjectWithSyncedName,
);
} else {
if (input.update.nameSingular || input.update.namePlural) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Similar to the previous comment, this block doesn't handle simultaneous updates to both singular and plural names

@@ -40,6 +43,8 @@ const reservedKeywords = [
'addresses',
];

const METADATA_NAME_VALID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider using a more descriptive name for this regex constant, e.g., VALID_METADATA_NAME_PATTERN

);

if (!formattedString.match(METADATA_NAME_VALID_PATTERN)) {
throw new Error(`"${string}" is not a valid name`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: This error message could be more specific about why the name is invalid

Comment on lines +75 to +77
if (formattedString.match(METADATA_NAME_VALID_PATTERN) !== null) {
return toCamelCase(formattedString);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: This condition might allow some invalid names through. Consider using a stricter check

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

(updates since last review)

This PR continues the implementation of custom object renaming functionality in the Twenty application. The main changes include:

  • Added 'areLabelAndNameSync' property to various test files and schemas
  • Updated GraphQL queries and mutations to support the new renaming feature
  • Modified ObjectMetadataService to handle object renaming and related metadata updates

Key points to highlight:

  • The 'areLabelAndNameSync' property has been added to multiple test files, reflecting the new feature for syncing labels and API names in custom objects
  • The settingsCreateObjectInputSchema and settingsUpdateObjectInputSchema have been updated to include new fields for custom object renaming
  • The ObjectMetadataService has been modified to improve handling of object name and label updates

The changes align with the requirements outlined in the related issue, particularly in supporting independent API names and labels for custom objects.

8 file(s) reviewed, 2 comment(s)
Edit PR Review Bot Settings

);
}

if (updatedObject.areLabelAndNameSync) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: This block doesn't handle the case where both label and name are updated simultaneously. Consider adding a check for this scenario

updatedObjectWithSyncedName,
);
} else {
if (input.update.nameSingular || input.update.namePlural) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Similar to the previous comment, this block doesn't handle simultaneous updates to both singular and plural names

@ijreilly
Copy link
Collaborator

ijreilly commented Oct 9, 2024

indicated on discord as actually still in internal review, @gitstart-twenty can you confirm?

@gitstart-twenty
Copy link
Contributor

indicated on discord as actually still in internal review, @gitstart-twenty can you confirm?

Hi @ijreilly, this PR is ready for your review. We have clarified it here

Copy link
Collaborator

@ijreilly ijreilly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I have noticed some important errors/unexpected behaviours while testing

  1. When advanced settings are on, if label plural is updated, it updates the label singular, I am not sure this is expected? (see video)
  2. When advanced settings are on, if I am only updating the label singular, it says object already exists, probably because it tries to save the object with the same name that is already taken (i suppose) (also in the video)
  3. Label updates does not seem to work, I updated it and still see the old "Rockets" label everywhere

Can you please make sure to fully test the feature:

  • update of any of the labelSingular, labelPlural, nameSingular, namePlural independently works: check on the app + in the database (fieldMetadata, name of columns etc)
  • no weird behaviour on the form like unexpected dependencies between form fields (try updating a field then another, hiding and showing advanced mode, etc.)

Let us know if we can help!

errors1and2.mov

@@ -189,6 +189,7 @@ export type CreateFieldInput = {
};

export type CreateObjectInput = {
areLabelAndNameSync?: InputMaybe<Scalars['Boolean']['input']>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we rename to shouldSyncLabelAndName?

const { contentRef, motionAnimationVariants } = useExpandedHeightAnimation(
isAdvancedModeEnabled,
);
const infoCircleElementId = `info-circle-id-${Math.random().toString(36).slice(2)}`;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this is used elsewhere but why is this id computed like this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we were using this to avoid duplicated ids, but the duplication is not happening, so we will update this

@@ -111,7 +111,8 @@ export class BeforeUpdateOneObject<T extends UpdateObjectPayload>
) {
if (
update.nameSingular &&
update.nameSingular !== objectMetadata.nameSingular
update.nameSingular !== objectMetadata.nameSingular &&
!objectMetadata.isCustom
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this condition here. Shouldn't it be
if (update.nameSingular && areLabelAndNameSync && (update.nameSingular !== objectMetadata.nameSingular)) ? this check only being valid if label and name are sync

@@ -120,22 +121,28 @@ export class BeforeUpdateOneObject<T extends UpdateObjectPayload>

if (
update.labelSingular &&
update.labelSingular !== objectMetadata.labelSingular
update.labelSingular !== objectMetadata.labelSingular &&
!objectMetadata.isCustom
) {
throw new BadRequestException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually with this feature we want to enable udpate of label and names !

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the changes in this file we are enabling the update but only for custom objects

@@ -441,7 +445,29 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
): Promise<ObjectMetadataEntity> {
validateObjectMetadataInputOrThrow(input.update);

const updatedObject = await super.updateOne(input.id, input.update);
const oldObject = await this.objectMetadataRepository.findOne({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const oldObject = await this.objectMetadataRepository.findOne({
const existingObjectMetadata = await this.objectMetadataRepository.findOne({

oldObject: ObjectMetadataEntity,
updatedObject: ObjectMetadataEntity,
) {
const oldTableName = computeObjectTargetTable(oldObject);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const oldTableName = computeObjectTargetTable(oldObject);
const existingTableName = computeObjectTargetTable(oldObject);

name: `${oldObject.nameSingular}Id`,
};

const fieldWithNonCustomRelation =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const fieldWithNonCustomRelation =
const fieldWihStandardRelation =

@gitstart-twenty
Copy link
Contributor

Hello @ijreilly
regarding your comment about the label singular being synced with the label plural, this is mentioned on the issue. Also, if the advanced settings are off, the user can only see the label plural and we need to update the label singular as well

@ijreilly
Copy link
Collaborator

ijreilly commented Oct 14, 2024

Hi @gitstart-twenty, thanks for your work I will take it from here !

@charlesBochet
Copy link
Member

I'm a bit overwhelmed, @Weiko will take the review on this one

@charlesBochet charlesBochet assigned Weiko and unassigned charlesBochet Oct 21, 2024
Copy link
Member

@Weiko Weiko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Weiko Weiko enabled auto-merge (squash) October 24, 2024 11:49
@Weiko Weiko merged commit 414f2ac into main Oct 24, 2024
18 checks passed
@Weiko Weiko deleted the TWNTY-5491 branch October 24, 2024 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants