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

feat: send test message #44

Merged
merged 3 commits into from
Jan 30, 2025
Merged

feat: send test message #44

merged 3 commits into from
Jan 30, 2025

Conversation

waltergalvao
Copy link
Member

@waltergalvao waltergalvao commented Jan 30, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ability to send test messages for integrations.
    • Implemented rate limiting for GraphQL API endpoints.
  • Improvements

    • Enhanced error handling for various scenarios, including rate limit exceeded.
    • Added more detailed error messages for users.
  • Technical Updates

    • Introduced new GraphQL directive for rate limiting.
    • Added new mutation for sending test messages across integrations.
    • Updated GraphQL schema to include new input types and mutation arguments.

@sweetr-dev sweetr-dev bot added the large Large PR - Consider splitting up into smaller PRs to reduce risk and review time label Jan 30, 2025
Copy link

coderabbitai bot commented Jan 30, 2025

Walkthrough

This pull request introduces a comprehensive implementation of test message sending functionality and rate limiting for the API. The changes span multiple files across the application, adding a new GraphQL mutation for sending test messages to Slack, implementing a rate limiter plugin, and creating supporting infrastructure like a new exception type and directive. The implementation includes both backend and frontend components to enable sending test messages and controlling API request rates.

Changes

File Change Summary
apps/api/package.json Added @envelop/rate-limiter dependency
apps/api/src/app/directives.schema.ts Introduced new @rateLimit GraphQL directive
apps/api/src/app/errors/exceptions/rate-limit.exception.ts Created RateLimitException class
apps/api/src/lib/rate-limiter.plugin.ts Implemented rate limiter plugin
apps/api/src/yoga.ts Added rateLimiterPlugin to Yoga server
apps/api/src/app/integrations/resolvers/integrations.schema.ts Added sendTestMessage mutation with rate limit
apps/web/src/api/integrations.api.ts Added useSendTestMessageMutation hook
apps/web/src/app/teams/[id]/digests/settings/components/digest-base-fields/digest-base-fields.tsx Enhanced UI with test message sending button
apps/web/src/app/teams/[id]/use-send-test-message.ts Introduced useSendTestMessage custom hook
packages/graphql-types/api.ts Added sendTestMessage mutation and SendTestMessageInput type
packages/graphql-types/frontend/gql.ts Added mutation operation for sendTestMessage
packages/graphql-types/frontend/graphql.ts Updated mutation and input types for sendTestMessage
packages/graphql-types/shared.ts Added RATE_LIMIT_EXCEEDED to ErrorCode enum

Possibly related PRs

  • feat: team digests #31: The changes in this PR introduce a new database table for managing digests, which is directly related to the new functionality added in the main PR for handling different types of digests.
  • feat: metrics digest #35: This PR involves modifications to the package.json file, which may relate to the new dependency added in the main PR for rate limiting, indicating a connection in terms of dependency management for the API.

Suggested labels

enhancement, huge

Suggested reviewers

  • sweetrdev

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43bdd73 and ebff8b8.

📒 Files selected for processing (1)
  • apps/api/src/lib/rate-limiter.plugin.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/src/lib/rate-limiter.plugin.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript-typescript)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (12)
apps/api/src/app/directives.schema.ts (1)

2-8: Consider improving type safety for the rate limit directive.

The window parameter being a String type could lead to validation issues. Consider:

  1. Using an enum for predefined time windows, or
  2. Adding a custom scalar type for duration/interval

Also, consider adding GraphQL descriptions to document the purpose and usage of each parameter.

 directive @rateLimit(
+    """Maximum number of requests allowed within the time window"""
     max: Int
+    """Time window for rate limiting (e.g., "60s", "1h")"""
     window: String
+    """Custom error message when rate limit is exceeded"""
     message: String
+    """Arguments used to identify the rate limit subject"""
     identityArgs: [String]
+    """Field name containing the array length for bulk operations"""
     arrayLengthField: String
   ) on FIELD_DEFINITION
apps/api/src/app/errors/exceptions/rate-limit.exception.ts (1)

14-19: Consider making severity level configurable.

The severity level is hardcoded to "log", but rate limit violations might need different severity levels based on the context (e.g., potential abuse vs normal usage patterns).

   super(message, {
     code: ErrorCode.RATE_LIMIT_EXCEEDED,
     userFacingMessage: "You have exceeded the rate limit.",
-    severity: "log",
+    severity: options?.severity ?? "log",
     ...options,
   });
apps/api/src/lib/rate-limiter.plugin.ts (1)

8-11: Enhance error message handling.

Consider adding validation for the error message and including rate limit details (remaining attempts, reset time) in the user-facing message.

   transformError: (message: string) =>
     new RateLimitException("Rate limit exceeded", {
-      userFacingMessage: message,
+      userFacingMessage: message.trim() || "You have exceeded the rate limit. Please try again later.",
+      extra: { originalMessage: message },
     }),
apps/api/src/app/digests/workers/digest-send.worker.ts (1)

22-22: Enhance error handling and add success logging.

Consider adding try-catch block and success logging for better observability.

-    await sendDigest(digest);
+    try {
+      await sendDigest(digest);
+      logger.info("digestSendWorker: Digest sent successfully", {
+        extra: { digestId: digest.id, type: digest.type },
+      });
+    } catch (error) {
+      logger.error("digestSendWorker: Failed to send digest", {
+        extra: { digestId: digest.id, type: digest.type, error },
+      });
+      throw error;
+    }
apps/web/src/providers/error-message.provider.ts (1)

18-25: LGTM! Consider extracting error codes to a constant.

The error handling implementation looks good and properly integrates with the new rate limiting feature. However, consider extracting the array of error codes to a named constant for better maintainability.

+const USER_FACING_ERROR_CODES = [
+  "INPUT_VALIDATION_FAILED",
+  "RESOURCE_NOT_FOUND",
+  "RATE_LIMIT_EXCEEDED",
+] as const;

 if (
   extensions &&
-  [
-    "INPUT_VALIDATION_FAILED",
-    "RESOURCE_NOT_FOUND",
-    "RATE_LIMIT_EXCEEDED",
-  ].includes(extensions.code)
+  USER_FACING_ERROR_CODES.includes(extensions.code as typeof USER_FACING_ERROR_CODES[number])
 ) {
apps/api/src/app/integrations/resolvers/integrations.schema.ts (2)

26-30: LGTM! Consider adding field descriptions.

The input type structure looks good, but consider adding descriptions for the fields to improve schema documentation.

 input SendTestMessageInput {
+  "The ID of the workspace to send the test message to"
   workspaceId: SweetID!
+  "The integration app to use for sending the message"
   app: IntegrationApp!
+  "The channel where the test message will be sent"
   channel: String!
 }

39-44: Consider increasing the rate limit window.

The current rate limit of 5 requests per minute might be too restrictive for users testing multiple channels. Consider increasing it to a more user-friendly limit, such as 10 requests per minute.

 sendTestMessage(input: SendTestMessageInput!): Void
   @rateLimit(
     window: "60s"
-    max: 5
-    message: "You got rate limited. You can send 5 test messages per minute."
+    max: 10
+    message: "You got rate limited. You can send 10 test messages per minute."
   )
apps/web/src/app/teams/[id]/use-send-test-message.ts (1)

17-19: Consider making the integration app configurable.

The app parameter is hardcoded to SLACK. If other integrations are planned, consider making this configurable.

+  const sendTestMessage = (channel: string, app: IntegrationApp = IntegrationApp.SLACK) => {
     mutate(
       {
         input: {
           workspaceId: workspace.id,
-          app: IntegrationApp.SLACK,
+          app,
           channel: channel.trim(),
         },
       },
apps/api/src/app/integrations/slack/services/slack-client.service.ts (1)

73-75: Consider adding more context to the error message.

The error message could be more helpful by including the channel name.

-    throw new ResourceNotFoundException("Slack channel not found", {
-      userFacingMessage: "Could not find Slack channel.",
+    throw new ResourceNotFoundException(`Slack channel "${channelName}" not found`, {
+      userFacingMessage: `Could not find Slack channel "${channelName}".`,
     });
apps/web/src/api/integrations.api.ts (1)

99-118: Consider adding query invalidation for consistency.

Other mutation hooks in this file invalidate related queries in their onSettled handlers. Consider whether the sendTestMessage mutation should invalidate any queries to maintain UI consistency.

Apply this diff to add query invalidation if needed:

 export const useSendTestMessageMutation = (
   options?: UseMutationOptions<
     SendTestMessageMutation,
     unknown,
     MutationSendTestMessageArgs,
     unknown
   >,
 ) =>
   useMutation({
     mutationFn: (args) =>
       graphQLClient.request(
         graphql(/* GraphQL */ `
           mutation SendTestMessage($input: SendTestMessageInput!) {
             sendTestMessage(input: $input)
           }
         `),
         args,
       ),
+    onSettled: () => {
+      queryClient.invalidateQueries({
+        queryKey: ["integrations"],
+      });
+    },
     ...options,
   });
apps/api/src/app/integrations/slack/services/slack-integration.service.ts (1)

129-144: Improve error handling and message configuration.

The function implementation is good, but consider these improvements:

  1. Add error handling for sendSlackMessage.
  2. Externalize the test message text for easier maintenance and potential localization.

Apply this diff to improve the implementation:

+const TEST_MESSAGE = "Sweet, it works! 🍧";
+
 export const sendTestMessage = async (workspaceId: number, channel: string) => {
   const { slackClient } = await getWorkspaceSlackClient(workspaceId);

   const slackChannel = await joinSlackChannel(slackClient, channel);

   if (!slackChannel?.id) {
     throw new ResourceNotFoundException("Slack channel not found");
   }

-  await sendSlackMessage(slackClient, {
-    channel: slackChannel.id,
-    text: "Sweet, it works! 🍧",
-    unfurl_links: false,
-    unfurl_media: false,
-  });
+  try {
+    await sendSlackMessage(slackClient, {
+      channel: slackChannel.id,
+      text: TEST_MESSAGE,
+      unfurl_links: false,
+      unfurl_media: false,
+    });
+  } catch (error) {
+    throw new IntegrationException("Failed to send test message", {
+      originalError: error,
+    });
+  }
 };
apps/web/src/app/teams/[id]/digests/settings/components/digest-base-fields/digest-base-fields.tsx (1)

80-91: Enhance button behavior and error handling.

Consider these improvements to the test button implementation:

  1. Disable the button when the channel field is empty.
  2. Add error handling for the onClick handler.

Apply this diff to improve the implementation:

 <Tooltip label="Send a test message to the channel" withArrow>
   <Button
     variant="default"
+    disabled={!form.values.channel}
     onClick={() => {
+      try {
         sendTestMessage(form.values.channel);
+      } catch (error) {
+        console.error('Failed to send test message:', error);
+      }
     }}
     leftSection={<IconBrandSlack size={16} stroke={1.5} />}
     loading={isSendingTestMessage}
   >
     Test
   </Button>
 </Tooltip>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1e0b0 and 43bdd73.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • apps/api/package.json (1 hunks)
  • apps/api/src/app/digests/services/digest.service.ts (2 hunks)
  • apps/api/src/app/digests/workers/digest-send.worker.ts (2 hunks)
  • apps/api/src/app/directives.schema.ts (1 hunks)
  • apps/api/src/app/errors/exceptions/rate-limit.exception.ts (1 hunks)
  • apps/api/src/app/integrations/resolvers/integrations.schema.ts (1 hunks)
  • apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts (1 hunks)
  • apps/api/src/app/integrations/slack/services/slack-client.service.ts (1 hunks)
  • apps/api/src/app/integrations/slack/services/slack-integration.service.ts (2 hunks)
  • apps/api/src/lib/rate-limiter.plugin.ts (1 hunks)
  • apps/api/src/yoga.ts (2 hunks)
  • apps/web/src/api/integrations.api.ts (2 hunks)
  • apps/web/src/app/teams/[id]/digests/settings/components/digest-base-fields/digest-base-fields.tsx (2 hunks)
  • apps/web/src/app/teams/[id]/use-send-test-message.ts (1 hunks)
  • apps/web/src/providers/error-message.provider.ts (1 hunks)
  • packages/graphql-types/api.ts (8 hunks)
  • packages/graphql-types/frontend/gql.ts (2 hunks)
  • packages/graphql-types/frontend/graphql.ts (5 hunks)
  • packages/graphql-types/shared.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
packages/graphql-types/shared.ts (1)

37-37: LGTM! Error code addition looks good.

The new RATE_LIMIT_EXCEEDED error code is properly added to the enum, maintaining consistent style and alphabetical ordering.

apps/api/src/yoga.ts (1)

9-9: LGTM! Plugin integration looks good.

The rate limiter plugin is properly imported and integrated with the existing plugins array.

Also applies to: 25-25

apps/api/src/app/integrations/slack/services/slack-client.service.ts (1)

Line range hint 47-54: Address the pagination TODO comment.

The current implementation has a hard limit of 1000 channels which might not be sufficient for large workspaces.

Would you like me to implement pagination for the channel list? This would involve:

  1. Using cursor-based pagination with Slack's API
  2. Implementing a channel search function
  3. Adding proper error handling for rate limits
apps/web/src/api/integrations.api.ts (1)

13-13: LGTM!

The new type imports are correctly added and properly organized with the existing imports.

Also applies to: 15-15

apps/api/src/app/integrations/slack/services/slack-integration.service.ts (1)

14-15: LGTM!

The imports are correctly organized and the ResourceNotFoundException is appropriately used for the channel not found case.

Also applies to: 18-18

apps/web/src/app/teams/[id]/digests/settings/components/digest-base-fields/digest-base-fields.tsx (2)

15-16: LGTM!

The imports are well-organized and the Mantine UI components are appropriately imported.

Also applies to: 19-24, 30-30


37-37: LGTM!

The hook is correctly destructured to access both the action and loading state.

packages/graphql-types/frontend/gql.ts (2)

36-36: LGTM!

The SendTestMessage mutation document is correctly added to the documents map.


150-153: LGTM!

The type export for the SendTestMessage mutation is properly defined and follows the existing pattern.

packages/graphql-types/api.ts (4)

250-250: LGTM: Appropriate return type for the mutation

The Maybe<Void> return type is well-chosen for this action-based mutation, allowing for both success (null) and error (undefined) cases.


524-528: Consider adding channel format validation

The input type structure is good, but consider validating the channel format on the resolver level since different apps may have different channel format requirements (e.g., Slack channels starting with '#').


968-974: LGTM: Well-structured rate limiting configuration

The rate limit directive arguments provide a comprehensive and flexible configuration structure with all necessary parameters for effective rate limiting.


976-976: LGTM: Properly typed directive resolver

The resolver type is correctly defined with appropriate context and argument types.

packages/graphql-types/frontend/graphql.ts (3)

887-889: LGTM: Properly typed mutation variables

The mutation variables are correctly typed using the SendTestMessageInput type.


892-892: LGTM: Consistent return type

The mutation return type correctly matches the API schema definition.


1040-1040: LGTM: Well-defined GraphQL document

The document is properly typed and structured for use with GraphQL clients.

Comment on lines 6 to 7
identifyFn: (context: GraphQLContext) =>
context.workspaceId?.toString() ?? context.currentToken.userId.toString(),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null checks to prevent runtime errors.

The identifyFn lacks null checks for context.currentToken, which could cause runtime errors if the token is not present.

   identifyFn: (context: GraphQLContext) =>
-    context.workspaceId?.toString() ?? context.currentToken.userId.toString(),
+    context.workspaceId?.toString() ?? context.currentToken?.userId?.toString() ?? 'anonymous',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
identifyFn: (context: GraphQLContext) =>
context.workspaceId?.toString() ?? context.currentToken.userId.toString(),
identifyFn: (context: GraphQLContext) =>
context.workspaceId?.toString() ?? context.currentToken?.userId?.toString() ?? 'anonymous',


await protectWithPaywall(input.workspaceId);

await sendTestMessage(input.workspaceId, input.channel);
Copy link

@coderabbitai coderabbitai bot Jan 30, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider error handling for sendTestMessage.

The service call should be wrapped in a try-catch block to handle potential integration errors gracefully.

-    await sendTestMessage(input.workspaceId, input.channel);
+    try {
+      await sendTestMessage(input.workspaceId, input.channel);
+    } catch (error) {
+      logger.error("Failed to send test message", { error, input });
+      throw error;
+    }

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Member Author

Choose a reason for hiding this comment

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

GraphQL already handles this. We show a specific user facing error message

Copy link

Choose a reason for hiding this comment

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

@waltergalvao Understood, thanks for the clarification. The GraphQL layer's error handling is sufficient here.


✏️ Learnings added
Learnt from: waltergalvao
PR: sweetr-dev/sweetr.dev#44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:35.781Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +16 to +19
workspaceId: z.number(),
channel: z.string().max(80),
app: z.nativeEnum(IntegrationApp),
}),
Copy link

@coderabbitai coderabbitai bot Jan 30, 2025

Choose a reason for hiding this comment

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

💡 Codebase verification

Remove unused app parameter or implement multi-app support

The app parameter is validated but not used in the implementation. The service is currently Slack-specific with no support for other integration apps. Either:

  • Remove the app parameter if only Slack support is intended
  • Implement the functionality for other integration apps if multi-app support is planned
🔗 Analysis chain

Verify the usage of the app parameter.

The app parameter is validated but not passed to the sendTestMessage function. This could indicate:

  1. Missing functionality for other integration apps
  2. Unnecessary validation if only Slack is supported
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if sendTestMessage is implemented for other apps
rg -A 5 "sendTestMessage.*\(" apps/api/src/app/integrations/

Length of output: 2642

Copy link
Member Author

Choose a reason for hiding this comment

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

Just future-proofing for when we support MS Teams.

Copy link

Choose a reason for hiding this comment

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

@waltergalvao Ah, that makes perfect sense! Thanks for the clarification.

(`∀´)D


✏️ Learnings added
Learnt from: waltergalvao
PR: sweetr-dev/sweetr.dev#44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:16-19
Timestamp: 2025-01-30T06:09:54.631Z
Learning: The `app` parameter in the `sendTestMessage` mutation is included to support future MS Teams integration, even though it's currently only used with Slack.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: waltergalvao
PR: sweetr-dev/sweetr.dev#44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:36.043Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Comment on lines +13 to +33
const sendTestMessage = (channel: string) => {
mutate(
{
input: {
workspaceId: workspace.id,
app: IntegrationApp.SLACK,
channel: channel,
},
},
{
onError: (error) => {
showErrorNotification({
message: getErrorMessage(error),
});
},
onSuccess: () => {
showSuccessNotification({ message: "Test message sent" });
},
},
);
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation for the channel parameter.

The channel parameter should be validated before making the API call to provide immediate feedback to users.

   const sendTestMessage = (channel: string) => {
+    if (!channel?.trim()) {
+      showErrorNotification({
+        message: "Please enter a valid channel name",
+      });
+      return;
+    }
+
     mutate(
       {
         input: {
           workspaceId: workspace.id,
           app: IntegrationApp.SLACK,
-          channel: channel,
+          channel: channel.trim(),
         },
       },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sendTestMessage = (channel: string) => {
mutate(
{
input: {
workspaceId: workspace.id,
app: IntegrationApp.SLACK,
channel: channel,
},
},
{
onError: (error) => {
showErrorNotification({
message: getErrorMessage(error),
});
},
onSuccess: () => {
showSuccessNotification({ message: "Test message sent" });
},
},
);
};
const sendTestMessage = (channel: string) => {
if (!channel?.trim()) {
showErrorNotification({
message: "Please enter a valid channel name",
});
return;
}
mutate(
{
input: {
workspaceId: workspace.id,
app: IntegrationApp.SLACK,
channel: channel.trim(),
},
},
{
onError: (error) => {
showErrorNotification({
message: getErrorMessage(error),
});
},
onSuccess: () => {
showSuccessNotification({ message: "Test message sent" });
},
},
);
};

Comment on lines +107 to +115
export const sendDigest = async (digest: DigestWithRelations) => {
if (digest.type === DigestType.TEAM_METRICS) {
await sendTeamMetricsDigest(digest);
}

if (digest.type === DigestType.TEAM_WIP) {
await sendTeamWipDigest(digest);
}
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling and type safety.

The current implementation has several areas for improvement:

  1. No error handling for the service calls
  2. No handling for unknown digest types
  3. Type checking could be more maintainable
 export const sendDigest = async (digest: DigestWithRelations) => {
+  try {
-    if (digest.type === DigestType.TEAM_METRICS) {
-      await sendTeamMetricsDigest(digest);
-    }
-
-    if (digest.type === DigestType.TEAM_WIP) {
-      await sendTeamWipDigest(digest);
-    }
+    const digestHandlers = {
+      [DigestType.TEAM_METRICS]: sendTeamMetricsDigest,
+      [DigestType.TEAM_WIP]: sendTeamWipDigest,
+    } as const;
+
+    const handler = digestHandlers[digest.type];
+    if (!handler) {
+      throw new Error(`Unsupported digest type: ${digest.type}`);
+    }
+
+    await handler(digest);
+  } catch (error) {
+    throw new Error(`Failed to send digest: ${error.message}`);
+  }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const sendDigest = async (digest: DigestWithRelations) => {
if (digest.type === DigestType.TEAM_METRICS) {
await sendTeamMetricsDigest(digest);
}
if (digest.type === DigestType.TEAM_WIP) {
await sendTeamWipDigest(digest);
}
};
export const sendDigest = async (digest: DigestWithRelations) => {
try {
const digestHandlers = {
[DigestType.TEAM_METRICS]: sendTeamMetricsDigest,
[DigestType.TEAM_WIP]: sendTeamWipDigest,
} as const;
const handler = digestHandlers[digest.type];
if (!handler) {
throw new Error(`Unsupported digest type: ${digest.type}`);
}
await handler(digest);
} catch (error) {
throw new Error(`Failed to send digest: ${error.message}`);
}
};

@@ -31,6 +31,7 @@
"@date-fns/tz": "^1.2.0",
"@date-fns/utc": "^2.1.0",
"@envelop/generic-auth": "^7.0.0",
"@envelop/rate-limiter": "^6.2.1",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing required peer dependency for rate limiter

The @envelop/rate-limiter package requires @envelop/core ^5.0.2 as a peer dependency, but it's not found in package.json. Please add it to ensure proper functionality.

🔗 Analysis chain

Verify rate limiter package compatibility

The @envelop/rate-limiter package is appropriately added. Let's verify the version compatibility and check for any known issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for latest version and any security advisories
echo "Checking NPM for latest version..."
npm view @envelop/rate-limiter version

echo -e "\nChecking for known vulnerabilities..."
npm audit @envelop/rate-limiter

echo -e "\nChecking package compatibility with graphql-yoga..."
npm view [email protected] peerDependencies

Length of output: 799


Script:

#!/bin/bash
# Check peer dependencies and version requirements
echo "Checking @envelop/rate-limiter peer dependencies..."
npm view @envelop/rate-limiter peerDependencies

echo -e "\nChecking graphql version in package.json..."
cat apps/api/package.json | grep '"graphql":'

Length of output: 411


Script:

#!/bin/bash
# Check @envelop/core version
echo "Checking @envelop/core version in package.json..."
cat apps/api/package.json | grep '"@envelop/core":'

Length of output: 162

@waltergalvao waltergalvao merged commit ad084c2 into main Jan 30, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
large Large PR - Consider splitting up into smaller PRs to reduce risk and review time
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants