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

Multiple operations on webhooks #7807

Merged
merged 16 commits into from
Oct 23, 2024
Merged

Multiple operations on webhooks #7807

merged 16 commits into from
Oct 23, 2024

Conversation

ehconitin
Copy link
Contributor

@ehconitin ehconitin commented Oct 17, 2024

fixes #7792

WIP :)

webhook.mp4

);
} else {
this.logger.debug(
`CallWebhookJobsJob on eventName '${eventName}' did not trigger any webhooks.`,
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we dont really need this log right?

Copy link
Contributor

Choose a reason for hiding this comment

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

think we can remove those 'not trigger any ...' logs

Copy link
Contributor

@martmull martmull left a comment

Choose a reason for hiding this comment

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

Hey @ehconitin thanks for your PR. The code looks good to me but I think we must take care of the data migrations. I suggest a 2 steps migration strategy:

First PR

  • leave operation column like it exists now and create a new column operations
  • create the command to copy data from operation to operations with arrays of lenght 1
  • duplicate operation updates into the operations column

Second PR

  • update the frontend and backend so it uses operations instead of operation
  • add the frontend code that enable operations arrays of length > 1
  • remove the operation column

);
} else {
this.logger.debug(
`CallWebhookJobsJob on eventName '${eventName}' did not trigger any webhooks.`,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

think we can remove those 'not trigger any ...' logs

Comment on lines 32 to 39
@WorkspaceField({
standardId: WEBHOOK_STANDARD_FIELD_IDS.operation,
type: FieldMetadataType.TEXT,
type: FieldMetadataType.ARRAY,
label: 'Operation',
description: 'Webhook operation',
icon: 'IconCheckbox',
})
operation: string;
operations: string[];
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should proceed with a 2 steps strategy to migrate data properly:

First PR

  • leave operation column like it exists now and create a new column operations
  • create the command to copy data from operation to operations with arrays of lenght 1
  • duplicate operation updates into the operations column

Second PR

  • update the frontend and backend so it uses operations instead of operation
  • add the frontend code that enable operations arrays of length > 1
  • remove the operation column

@ehconitin
Copy link
Contributor Author

ehconitin commented Oct 18, 2024

@Bonapara @martmull
How about this?

update - just saw #7807 (comment)
working on it

webhook_new.mp4

@martmull
Copy link
Contributor

@ehconitin
If the first operation is *.*, there is no need to add another operation as it will be necessarily included in the *.*
So we should allow adding the second operation only when the first operation is updated
And so on
I suggest to do that like @Bonapara designed it on Figma, without any "Add operation" button, secondary operations can be added automatically with the criteria details above (first operation is updated => add another operation, second operation is updated => add a 3rd operation, ...)

@ehconitin
Copy link
Contributor Author

@ehconitin If the first operation is *.*, there is no need to add another operation as it will be necessarily included in the *.* So we should allow adding the second operation only when the first operation is updated And so on I suggest to do that like @Bonapara designed it on Figma, without any "Add operation" button, secondary operations can be added automatically with the criteria details above (first operation is updated => add another operation, second operation is updated => add a 3rd operation, ...)

Yep! missed your comment explaining this behavior in the above comments! Understood! Thanks

{ value: '*', label: 'All Actions', Icon: IconNorthStar },
{ value: 'create', label: 'Create', Icon: IconPlus },
{ value: 'update', label: 'Update', Icon: IconRefresh },
{ value: 'delete', label: 'Delete', Icon: IconTrash },
Copy link
Contributor

Choose a reason for hiding this comment

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

@charlesBochet @Bonapara should we add destroy there?
@ehconitin you can add it if needed

@ehconitin
Copy link
Contributor Author

All requested changes from the review have been addressed!

TODO:

  1. On initial render, if the operation is not *.*, insert a WEBHOOK_EMPTY_OPERATION below.

  2. Find a better way to remove the existing filter.
    @Bonapara suggested adding a 'No object' or 'Choose object' option, which could be treated as null and filtered out in cleanAndFormatOperations.
    I’m still a bit uncertain about this approach but will give it a try.
    @martmull, do you have any suggestions for the second TODO? We want to avoid having a delete (trash) button here.

- Mark operation as deprecated

- Add operations migration command

- Avoid breaking changes

- Fix ellipsis display

- Improve empty operation apearance
@martmull martmull marked this pull request as ready for review October 22, 2024 16:49
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 multiple operations for webhooks, addressing issue #7792. The changes include updating both frontend and backend components to support an array of operations instead of a single operation.

  • Added 'operations' field to WebhookWorkspaceEntity and deprecated 'operation' field
  • Updated SettingsDevelopersWebhookDetail component to handle multiple operations
  • Implemented CopyWebhookOperationIntoOperationsCommand for data migration
  • Modified CallWebhookJobsJob to query and process multiple operations
  • Added new icons (IconHandClick and IconNorthStar) to support the UI changes

14 file(s) reviewed, 13 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +76 to +88
const baseOperations = data?.operations
? data.operations.map((op: string) => {
const [object, action] = op.split('.');
return { object, action };
})
: data?.operation
? [
{
object: data.operation.split('.')[0],
action: data.operation.split('.')[1],
},
]
: [];
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 logic might be better placed in a separate function for clarity

Suggested change
const baseOperations = data?.operations
? data.operations.map((op: string) => {
const [object, action] = op.split('.');
return { object, action };
})
: data?.operation
? [
{
object: data.operation.split('.')[0],
action: data.operation.split('.')[1],
},
]
: [];
const mapOperations = (data) => {
return data?.operations
? data.operations.map((op: string) => {
const [object, action] = op.split('.');
return { object, action };
})
: data?.operation
? [
{
object: data.operation.split('.')[0],
action: data.operation.split('.')[1],
},
]
: [];
};
const baseOperations = mapOperations(data);

Comment on lines +147 to +148
operation: cleanedOperations?.[0],
operations: cleanedOperations,
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Saving both 'operation' and 'operations' might lead to inconsistencies. Consider removing 'operation'

Suggested change
operation: cleanedOperations?.[0],
operations: cleanedOperations,
await updateOneRecord({
idToUpdate: webhookId,
updateOneRecordInput: {
operations: cleanedOperations,
description: description,
},
});

Comment on lines 158 to 163
if (
!newOperations.some((op) => op.object === '*' && op.action === '*') &&
!newOperations.some((op) => op.object === null || op.action === null)
) {
return [...newOperations, WEBHOOK_EMPTY_OPERATION];
}
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 logic might add unnecessary empty operations. Consider simplifying

Suggested change
if (
!newOperations.some((op) => op.object === '*' && op.action === '*') &&
!newOperations.some((op) => op.object === null || op.action === null)
) {
return [...newOperations, WEBHOOK_EMPTY_OPERATION];
}
if (!newOperations.some((op) => op.object === '*' && op.action === '*')) {
return [...newOperations, WEBHOOK_EMPTY_OPERATION];
}

Comment on lines 19 to 27
const [formValues, setFormValues] = useState<{
targetUrl: string;
operation: string;
operations: string[];
}>({
targetUrl: '',
operation: '*.*',
operations: ['*.*'],
});
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Consider removing the 'operation' field from the state as it's being replaced by 'operations' array. This will prevent potential inconsistencies.

Suggested change
const [formValues, setFormValues] = useState<{
targetUrl: string;
operation: string;
operations: string[];
}>({
targetUrl: '',
operation: '*.*',
operations: ['*.*'],
});
const [formValues, setFormValues] = useState<{
targetUrl: string;
operations: string[];
}>({
targetUrl: '',
operations: ['*.*'],
});

Comment on lines +45 to +48
if ('operation' in webhook) {
await webhookRepository.update(webhook.id, {
operations: [webhook.operation],
});
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Consider handling the case where 'operations' already exists to avoid overwriting existing data

Comment on lines +46 to +48
await webhookRepository.update(webhook.id, {
operations: [webhook.operation],
});
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Ensure webhook.operation is not null or undefined before adding to array

'webhook',
);

const webhooks = await webhookRepository.find();
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 pagination for large datasets to avoid potential memory issues

options: BaseCommandOptions,
activeWorkspaceIds: string[],
): Promise<void> {
this.logger.log('Running command to copy operation to operations');
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Log the total number of workspaces being processed for better progress tracking

Comment on lines +49 to +51
this.logger.log(
chalk.yellow(`Copied webhook operation to operations`),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Log the webhook ID for better traceability

icon: 'IconCheckbox',
defaultValue: ['*.*'],
})
operations: string[];
Copy link
Contributor

Choose a reason for hiding this comment

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

style: operations field should have a more specific type than string[], e.g., string[] as WebhookOperation[]

Suggested change
operations: string[];
type WebhookOperation = string; // Define a specific type for operations
operations: WebhookOperation[];

@martmull
Copy link
Contributor

  • add migration command
  • avoid breaking change
  • fix dropdown selected option ellipsis display
    image
    image
  • fix empty operation option appearance

@Bonapara
Copy link
Member

@martmull @ehconitin Let me know when you're finished with this so I can do a final Product / Design review ;)

@martmull
Copy link
Contributor

Finished

@martmull
Copy link
Contributor

@Bonapara

@martmull martmull enabled auto-merge (squash) October 23, 2024 15:40
@martmull martmull merged commit 18778c5 into twentyhq:main Oct 23, 2024
16 checks passed
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.

Allow multiple operations in webhooks
4 participants