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

[WEB-2383] feat: Inbox Settings v2 #6644

Open
wants to merge 12 commits into
base: preview
Choose a base branch
from
Open

Conversation

Saurabhkmr98
Copy link
Collaborator

@Saurabhkmr98 Saurabhkmr98 commented Feb 19, 2025

Description

Inbox settings page UI and APIs

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Screenshot 2025-02-19 at 3 15 22 PM

Summary by CodeRabbit

  • New Features
    • Introduced workspace-specific notification preference management, allowing users to view and update their notification settings for activities, including task updates and comments.
    • Added a dedicated notifications settings page with an improved interface featuring intuitive toggles for in-app and email notifications.
    • Expanded support for multiple languages, enhancing the localization of notification settings.
    • Refined backend processes to automatically create and update missing notification preferences for a smoother user experience.

Copy link
Contributor

coderabbitai bot commented Feb 19, 2025

Walkthrough

This PR extends the notification system to support workspace-specific user preferences. It introduces a new serializer and model for workspace notifications, new endpoints (GET and PATCH) to manage these preferences, and updates to URL routing and view logic. Additionally, it adds background task functions for mention processing, a MobX store with hooks and services to manage notification settings, multiple new React components for the UI, and expanded localization and TypeScript definitions for notifications.

Changes

File(s) Change Summary
apiserver/plane/app/serializers/{__init__.py, notification.py} Updated import statements and added WorkspaceUserNotificationPreferenceSerializer.
apiserver/plane/app/urls/notification.py Added URL patterns for WorkspaceUserNotificationPreferenceEndpoint.
apiserver/plane/app/views/{__init__.py, notification/base.py, workspace/home.py} Introduced new endpoint WorkspaceUserNotificationPreferenceEndpoint with GET and PATCH methods; added logic to auto-create missing workspace notification preferences.
apiserver/plane/bgtasks/notification_task.py Added functions process_mentions, create_in_app_notifications, and create_email_notifications; refactored mention and subscriber handling in notifications.
apiserver/plane/db/models/{__init__.py, notification.py} Expanded imports and added the WorkspaceUserNotificationPreference model along with the NotificationTransportChoices enum.
packages/constants/src/notification.ts Added new enums (ENotificationSettingsKey, EWorkspaceNotificationTransport) and notification settings constants.
packages/i18n/src/locales/{cs, de, en, es, fr, id, it, ja, ko, pl, pt-BR, ro, ru, sk, ua, vi-VN, zh-CN, zh-TW}/translations.json Introduced a new notification_settings section for locale-specific notification preference translations.
packages/types/src/{index.d.ts, notification.d.ts} Added export for the notification module and new TypeScript types (TNotificationSettings, TWorkspaceUserNotification).
web/app/[workspaceSlug]/(projects)/notifications/settings/{header.tsx, layout.tsx, page.tsx} Created new React components for notifications settings: header, layout, and page.
web/ce/components/inbox/{index.ts, settings/index.ts, settings/root.tsx, settings/update-setting-row.tsx} Added exports and new components for inbox settings, including InboxSettingsRoot and InboxSettingUpdateRow.
web/core/components/inbox/settings/{content-header.tsx, content-wrapper.tsx, update-setting.tsx, index.ts} Introduced new UI components for inbox settings such as InboxSettingsContentHeader, InboxSettingContentWrapper, and InboxSettingUpdate.
web/core/constants/fetch-keys.ts Added new constants: SLACK_USER_CONNECTION_STATUS and NOTIFICATION_SETTINGS.
web/core/hooks/store/notifications/{index.ts, use-workspace-notification-settings.ts} Added and exported the custom hook useWorkspaceNotificationSettings.
web/core/services/workspace-notification-settings.service.ts Added a new service class with methods to fetch and update workspace notification settings.
web/core/store/notifications/workspace-notification-settings.store.ts Introduced a new MobX store for managing workspace notification settings.
web/core/store/root.store.ts Updated the root store to include workspaceNotificationSettings for managing notification settings state.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant E as Workspace Endpoint
    participant DB as Database/Store
    participant S as Serializer

    %% GET Flow:
    C->>E: GET /workspaces/{slug}/user-notification-preferences
    E->>DB: Query notification preferences
    DB-->>E: Return preferences
    E->>S: Serialize preferences
    S-->>E: Return serialized data
    E-->>C: 200 OK with JSON response

    %% PATCH Flow:
    C->>E: PATCH /workspaces/{slug}/user-notification-preferences/{transport}
    E->>DB: Retrieve & validate preference
    DB-->>E: Return updated record or error (e.g., 404)
    E-->>C: Return success/error response
Loading

Possibly related PRs

Suggested labels

🌟improvement, 🌐frontend, 🧹chore

Suggested reviewers

  • sriramveeraghanta
  • anmolsinghbhatia
  • prateekshourya29

Poem

In my burrow, soft and light,
I hop through code both day and night.
New endpoints and settings, oh what fun,
Like fresh green clover under the sun.
With each change, I wiggle my nose—
Happy coding, everyone! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

@Saurabhkmr98 Saurabhkmr98 changed the title [WEB-2383] - Feat/inbox settings 2.0 [WEB-2383] feat: Inbox Settings v2 Feb 19, 2025
)
def get(self, request, slug):
workspace = Workspace.objects.get(slug=slug)
get_notification_preferences = (
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line 377 to 395 can be clubbed into the following.

existing_transports = UserNotificationPreference.objects.filter(
    workspace=workspace, user=request.user
).values_list('transport', flat=True)
create_transports = [
    transport
    for transport, _ in NotificationTransportChoices.choices
    if transport not in existing_transports
]

This will be concise and improve readability of the code.

@henit-chobisa henit-chobisa changed the title [WEB-2383] feat: Inbox Settings v2 [WEB-2383] feat: Inbox Settings v2 Mar 11, 2025
Copy link

makeplane bot commented Mar 11, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@Saurabhkmr98 Saurabhkmr98 marked this pull request as ready for review April 9, 2025 14:42
Copy link
Contributor

@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: 5

♻️ Duplicate comments (2)
web/core/components/inbox/settings/update-setting.tsx (1)

45-51: The toggle switch should be center aligned

As mentioned in the previous review, the toggle switch isn't center aligned in the UI component. Check the alignment to ensure it's visually consistent.

apiserver/plane/app/views/notification/base.py (1)

387-396: Consider succinctly computing create_transports ().
A past review comment suggested using direct set operations to compute the missing transports, which improves readability. Reusing that approach:

- for transport in transports:
-     if transport not in get_notification_preferences.values_list("transport", flat=True):
-         create_transports.append(transport)

+ existing_transports = get_notification_preferences.values_list("transport", flat=True)
+ create_transports = [
+     transport
+     for transport, _ in NotificationTransportChoices.choices
+     if transport not in existing_transports
+ ]
🧹 Nitpick comments (25)
web/core/hooks/store/notifications/index.ts (1)

3-3: LGTM! Consider using double quotes for consistency.

The export statement correctly exposes the workspace notification settings hook, but uses single quotes while the rest of the file uses double quotes. Consider standardizing for consistency.

-export * from './use-workspace-notification-settings';
+export * from "./use-workspace-notification-settings";
apiserver/plane/app/serializers/notification.py (1)

4-4: Line length exceeds recommended limit

This import line exceeds the recommended maximum line length (105 > 88 characters).

Consider breaking this import into multiple lines for better readability:

-from plane.db.models import Notification, UserNotificationPreference, WorkspaceUserNotificationPreference
+from plane.db.models import (
+    Notification,
+    UserNotificationPreference,
+    WorkspaceUserNotificationPreference,
+)
🧰 Tools
🪛 Ruff (0.8.2)

4-4: Line too long (105 > 88)

(E501)

web/core/hooks/store/notifications/use-workspace-notification-settings.ts (1)

9-9: Fix the error message to match the hook name.

The error message references "useNotification" but the hook is named "useWorkspaceNotificationSettings".

- if (context === undefined) throw new Error("useNotification must be used within StoreProvider");
+ if (context === undefined) throw new Error("useWorkspaceNotificationSettings must be used within StoreProvider");
web/app/[workspaceSlug]/(projects)/notifications/settings/layout.tsx (2)

7-8: Remove extra blank line for consistency.

There's an extra blank line after the imports that can be removed for better code consistency.

import { NotificationsSettingsHeader } from "./header";

-

12-13: Remove extra blank line for consistency.

There's another extra blank line that can be removed.

}

-
apiserver/plane/app/urls/notification.py (1)

51-60: Potential URL reverse lookup conflict.

Both URL patterns are assigned the same name "workspace-user-notification-preference", which could cause issues with URL reverse lookups. Consider using different names like "workspace-user-notification-preference-detail" and "workspace-user-notification-preference-list" to distinguish them.

 path(
     "workspaces/<str:slug>/user-notification-preferences/<str:transport>/",
     WorkspaceUserNotificationPreferenceEndpoint.as_view(),
-    name="workspace-user-notification-preference",
+    name="workspace-user-notification-preference-detail",
 ),
 path(
     "workspaces/<str:slug>/user-notification-preferences/",
     WorkspaceUserNotificationPreferenceEndpoint.as_view(),
-    name="workspace-user-notification-preference",
+    name="workspace-user-notification-preference-list",
 ),
web/core/components/inbox/settings/content-wrapper.tsx (2)

7-7: Remove unnecessary empty lines.

There are extra empty lines that could be removed to improve code consistency.

-

Also applies to: 20-20


16-19: Consider extracting Tailwind classes to named constants for readability.

For improved maintainability, consider extracting complex Tailwind class combinations to named constants, especially for repeated patterns or complex responsive layouts.

+const HAMBURGER_CONTAINER_CLASSES = "block flex-shrink-0 border-b border-custom-border-200 p-4 md:hidden";
+
 <div className="flex h-full flex-col">
-  <div className="block flex-shrink-0 border-b border-custom-border-200 p-4 md:hidden">
+  <div className={HAMBURGER_CONTAINER_CLASSES}>
     <SidebarHamburgerToggle />
   </div>
packages/i18n/src/locales/pt-BR/translations.json (1)

2435-2470: New "notification_settings" section added successfully.
The new block introduces keys for Inbox Settings (page label, descriptions, notification category titles and subtitles). The translations are clear and follow the style of the rest of the file. One minor suggestion: the subtitle for "work_item_property" is identical to "task_updates_subtitle". Please confirm if the intended nuance between “atualizações de itens de trabalho” and “atualização de qualquer propriedade do item de trabalho” should be differentiated further for better user clarity.

packages/i18n/src/locales/ru/translations.json (1)

2442-2474: New "notification_settings" section added with comprehensive keys.
All keys are translated consistently with the rest of the file. One detail to note is with the key "work_item_property_title". The current translation reads:
  "Обновление любой свойства рабочего элемента"
Since "свойство" is a neuter noun in Russian, the adjective should agree in the genitive form—consider changing it to:
  "Обновление любого свойства рабочего элемента"
This change would improve grammatical accuracy. Please verify if any other subtitles (such as for task updates) require differentiation, as they currently duplicate the text used in other parts.

web/ce/components/inbox/settings/root.tsx (1)

23-27: Consider extracting duplicated grid header into a reusable component.

The grid header with advanced settings, in-plane, and email columns is duplicated in both the task updates and comments sections. Consider extracting this into a reusable component or function to improve maintainability and follow the DRY principle.

+ const SettingsGridHeader = () => {
+   const { t } = useTranslation();
+   return (
+     <div className="grid gap-4 grid-cols-[50%_repeat(auto-fit,minmax(0,1fr))] text-sm text-custom-text-350 font-semibold">
+       <div>{t("notification_settings.advanced_settings")}</div>
+       <div>{t("notification_settings.in_plane")}</div>
+       <div>{t("notification_settings.email")}</div>
+     </div>
+   );
+ };

  // Then use it in both places:
  <SettingsGridHeader />

Also applies to: 43-47

apiserver/plane/app/views/workspace/home.py (3)

77-77: Remove unnecessary empty line.

There's an extra empty line that can be removed to maintain consistent spacing.


84-91: Use a descriptive variable name instead of underscore.

Using _ as a variable name indicates that the result is not used, but in this case, the result (created notification preferences) might be useful for debugging or future extensions. Consider using a descriptive variable name instead.

- _ = WorkspaceUserNotificationPreference.objects.bulk_create(
+ created_preferences = WorkspaceUserNotificationPreference.objects.bulk_create(

5-5: Line exceeds recommended length limit.

This line is 104 characters long, which exceeds the recommended PEP 8 limit of 88 characters. Consider breaking it into multiple lines for better readability.

- from plane.db.models import Workspace, WorkspaceUserNotificationPreference, NotificationTransportChoices
+ from plane.db.models import (
+     Workspace, 
+     WorkspaceUserNotificationPreference, 
+     NotificationTransportChoices
+ )
🧰 Tools
🪛 Ruff (0.8.2)

5-5: Line too long (104 > 88)

(E501)

web/ce/components/inbox/settings/update-setting-row.tsx (1)

32-34: Remove unnecessary empty className props.

The divs have empty className props that don't provide any styling. These can be removed for cleaner code.

- <div className="">
+ <div>
  <InboxSettingUpdate transport={EWorkspaceNotificationTransport.IN_APP} settings_key={settings_key} />
</div>
- <div className="">
+ <div>
  <InboxSettingUpdate transport={EWorkspaceNotificationTransport.EMAIL} settings_key={settings_key} />
</div>

Also applies to: 35-37

apiserver/plane/db/models/notification.py (1)

159-167: Consider simplifying uniqueness constraints

You have both unique_together and a UniqueConstraint with a condition that define similar constraints. While this works, it's generally cleaner to use just one approach.

If the null constraint on deleted_at is essential, you can remove the unique_together line and keep only the more specific UniqueConstraint with the condition.

apiserver/plane/app/views/notification/base.py (1)

426-444: Endpoint logic looks good; consider adding test coverage.
The patch method follows a straightforward partial update pattern and returns appropriate responses. It would be beneficial to add or expand unit/integration tests to ensure correct handling of edge cases (e.g., missing or invalid transport values).

Would you like help creating a new test or issue to track complete test coverage?

web/core/services/workspace-notification-settings.service.ts (2)

18-23: Remove redundant try/catch ().
Catching and rethrowing the same error is unnecessary. You can safely remove it for cleaner code:

 async fetchNotificationSettings(workspaceSlug: string): Promise<TWorkspaceUserNotification[] | undefined> {
-   try {
        const { data } = await this.get(`/api/workspaces/${workspaceSlug}/user-notification-preferences/`);
        return data || undefined;
-   } catch (error) {
-       throw error;
-   }
 }
🧰 Tools
🪛 Biome (1.9.4)

[error] 22-22: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)


32-40: Avoid catch-and-rethrow pattern ().
Same reasoning applies here:

 async updateNotificationSettings(
   workspaceSlug: string,
   transport: EWorkspaceNotificationTransport,
   payload: Partial<TWorkspaceUserNotification>
 ): Promise<TWorkspaceUserNotification | undefined> {
-   try {
       const { data } = await this.patch(
         `/api/workspaces/${workspaceSlug}/user-notification-preferences/${transport}/`,
         payload
       );
       return data || undefined;
-   } catch (error) {
-       throw error;
-   }
 }
🧰 Tools
🪛 Biome (1.9.4)

[error] 39-39: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)

apiserver/plane/bgtasks/notification_task.py (1)

359-359: Line length warnings ().
Some lines exceed typical style guidelines (e.g., line 359, 402, 539). Consider wrapping them for better readability.

Also applies to: 402-402, 539-539

🧰 Tools
🪛 Ruff (0.8.2)

359-359: Line too long (122 > 88)

(E501)

web/core/store/notifications/workspace-notification-settings.store.ts (5)

6-7: Remove or implement placeholder comments.

Lines 6-7 contain comment placeholders without any actual imports. Either add the intended imports or remove these comments for cleaner code.

- // plane web services
- // plane web root store

74-78: Incorrect JSDoc description.

The JSDoc comment doesn't match the function's actual behavior. It describes getting "project ids by workspace slug" but the function returns notification settings for the current workspace.

- /**
-  * @description get project ids by workspace slug
-  * @param { string } workspaceSlug
-  * @returns { string[] | undefined }
-  */
+ /**
+  * @description get notification settings for the current workspace
+  * @returns { Record<string, TWorkspaceUserNotification> | undefined }
+  */

104-107: Improve JSDoc description.

The function description "handle states" is vague and doesn't clearly describe what the function does. Consider updating it to be more descriptive of the actual functionality.

- /**
-  * @description handle states
-  * @returns { TWorkspaceUserNotification[] | undefined }
-  */
+ /**
+  * @description Fetch all notification settings for the current workspace
+  * @returns { TWorkspaceUserNotification[] | undefined }
+  */

133-138: Incorrect JSDoc return type.

The JSDoc comment states the return type as EWorkspaceNotificationTransport, but the function actually returns a Promise<TWorkspaceUserNotification | undefined>.

- /**
-  * @description - updates user notification settings for a transport
-  * @param transport
-  * @param settings
-  * @returns { EWorkspaceNotificationTransport }
-  */
+ /**
+  * @description - updates user notification settings for a transport
+  * @param { EWorkspaceNotificationTransport } transport
+  * @param { Partial<TWorkspaceUserNotification> } settings
+  * @returns { Promise<TWorkspaceUserNotification | undefined> }
+  */

32-35: Consider using a more specific type for error.

The error property is typed as a generic object, which doesn't provide type safety. Consider using a more specific type or an Error instance.

- error: object = {};
+ error: Error | Record<string, any> = {};
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 993c789 and fe62709.

📒 Files selected for processing (48)
  • apiserver/plane/app/serializers/__init__.py (1 hunks)
  • apiserver/plane/app/serializers/notification.py (2 hunks)
  • apiserver/plane/app/urls/notification.py (2 hunks)
  • apiserver/plane/app/views/__init__.py (1 hunks)
  • apiserver/plane/app/views/notification/base.py (3 hunks)
  • apiserver/plane/app/views/workspace/home.py (2 hunks)
  • apiserver/plane/bgtasks/notification_task.py (4 hunks)
  • apiserver/plane/db/models/__init__.py (1 hunks)
  • apiserver/plane/db/models/notification.py (1 hunks)
  • packages/constants/src/notification.ts (2 hunks)
  • packages/i18n/src/locales/cs/translations.json (1 hunks)
  • packages/i18n/src/locales/de/translations.json (1 hunks)
  • packages/i18n/src/locales/en/translations.json (1 hunks)
  • packages/i18n/src/locales/es/translations.json (1 hunks)
  • packages/i18n/src/locales/fr/translations.json (1 hunks)
  • packages/i18n/src/locales/id/translations.json (1 hunks)
  • packages/i18n/src/locales/it/translations.json (1 hunks)
  • packages/i18n/src/locales/ja/translations.json (1 hunks)
  • packages/i18n/src/locales/ko/translations.json (1 hunks)
  • packages/i18n/src/locales/pl/translations.json (1 hunks)
  • packages/i18n/src/locales/pt-BR/translations.json (1 hunks)
  • packages/i18n/src/locales/ro/translations.json (1 hunks)
  • packages/i18n/src/locales/ru/translations.json (1 hunks)
  • packages/i18n/src/locales/sk/translations.json (1 hunks)
  • packages/i18n/src/locales/ua/translations.json (1 hunks)
  • packages/i18n/src/locales/vi-VN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-CN/translations.json (1 hunks)
  • packages/i18n/src/locales/zh-TW/translations.json (1 hunks)
  • packages/types/src/index.d.ts (1 hunks)
  • packages/types/src/notification.d.ts (1 hunks)
  • web/app/[workspaceSlug]/(projects)/notifications/settings/header.tsx (1 hunks)
  • web/app/[workspaceSlug]/(projects)/notifications/settings/layout.tsx (1 hunks)
  • web/app/[workspaceSlug]/(projects)/notifications/settings/page.tsx (1 hunks)
  • web/ce/components/inbox/index.ts (1 hunks)
  • web/ce/components/inbox/settings/index.ts (1 hunks)
  • web/ce/components/inbox/settings/root.tsx (1 hunks)
  • web/ce/components/inbox/settings/update-setting-row.tsx (1 hunks)
  • web/core/components/inbox/index.ts (1 hunks)
  • web/core/components/inbox/settings/content-header.tsx (1 hunks)
  • web/core/components/inbox/settings/content-wrapper.tsx (1 hunks)
  • web/core/components/inbox/settings/index.ts (1 hunks)
  • web/core/components/inbox/settings/update-setting.tsx (1 hunks)
  • web/core/constants/fetch-keys.ts (2 hunks)
  • web/core/hooks/store/notifications/index.ts (1 hunks)
  • web/core/hooks/store/notifications/use-workspace-notification-settings.ts (1 hunks)
  • web/core/services/workspace-notification-settings.service.ts (1 hunks)
  • web/core/store/notifications/workspace-notification-settings.store.ts (1 hunks)
  • web/core/store/root.store.ts (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (17)
apiserver/plane/app/serializers/__init__.py (1)
apiserver/plane/app/serializers/notification.py (3)
  • NotificationSerializer (10-18)
  • UserNotificationPreferenceSerializer (21-24)
  • WorkspaceUserNotificationPreferenceSerializer (26-29)
apiserver/plane/app/urls/notification.py (1)
apiserver/plane/app/views/notification/base.py (1)
  • WorkspaceUserNotificationPreferenceEndpoint (370-444)
web/core/hooks/store/notifications/use-workspace-notification-settings.ts (2)
web/core/store/notifications/workspace-notification-settings.store.ts (1)
  • IWorkspaceNotificationSettingsStore (11-28)
space/core/lib/store-provider.tsx (1)
  • StoreContext (10-10)
web/core/components/inbox/settings/content-wrapper.tsx (1)
web/core/components/core/sidebar/sidebar-menu-hamburger-toggle.tsx (1)
  • SidebarHamburgerToggle (7-20)
apiserver/plane/app/views/workspace/home.py (3)
apiserver/plane/db/models/workspace.py (1)
  • Workspace (117-187)
apiserver/plane/db/models/notification.py (2)
  • WorkspaceUserNotificationPreference (126-175)
  • NotificationTransportChoices (178-180)
apiserver/plane/app/views/notification/base.py (3)
  • get (242-271)
  • get (348-353)
  • get (377-421)
apiserver/plane/app/views/__init__.py (1)
apiserver/plane/app/views/notification/base.py (1)
  • WorkspaceUserNotificationPreferenceEndpoint (370-444)
web/app/[workspaceSlug]/(projects)/notifications/settings/header.tsx (4)
admin/core/hooks/store/use-workspace.tsx (1)
  • useWorkspace (6-10)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/store/workspace/index.ts (1)
  • currentWorkspace (98-103)
packages/i18n/src/store/index.ts (1)
  • t (231-252)
web/app/[workspaceSlug]/(projects)/notifications/settings/page.tsx (6)
web/core/hooks/store/notifications/use-workspace-notification-settings.ts (1)
  • useWorkspaceNotificationSettings (7-12)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/constants/fetch-keys.ts (1)
  • NOTIFICATION_SETTINGS (280-281)
web/core/components/ui/loader/settings/email.tsx (1)
  • EmailSettingsLoader (3-29)
web/core/components/inbox/settings/content-wrapper.tsx (1)
  • InboxSettingContentWrapper (13-31)
web/core/components/inbox/settings/content-header.tsx (1)
  • InboxSettingsContentHeader (9-17)
web/core/services/workspace-notification-settings.service.ts (2)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
packages/types/src/notification.d.ts (1)
  • TWorkspaceUserNotification (9-21)
web/core/components/inbox/settings/update-setting.tsx (3)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/hooks/store/notifications/use-workspace-notification-settings.ts (1)
  • useWorkspaceNotificationSettings (7-12)
packages/i18n/src/store/index.ts (1)
  • t (231-252)
apiserver/plane/app/views/notification/base.py (3)
apiserver/plane/app/serializers/notification.py (1)
  • WorkspaceUserNotificationPreferenceSerializer (26-29)
apiserver/plane/db/models/workspace.py (1)
  • Workspace (117-187)
apiserver/plane/db/models/notification.py (2)
  • WorkspaceUserNotificationPreference (126-175)
  • NotificationTransportChoices (178-180)
web/core/store/root.store.ts (1)
web/core/store/notifications/workspace-notification-settings.store.ts (2)
  • IWorkspaceNotificationSettingsStore (11-28)
  • WorkspaceNotificationSettingsStore (30-164)
apiserver/plane/app/serializers/notification.py (1)
apiserver/plane/db/models/notification.py (7)
  • Notification (9-45)
  • UserNotificationPreference (57-94)
  • WorkspaceUserNotificationPreference (126-175)
  • Meta (37-41)
  • Meta (86-90)
  • Meta (120-124)
  • Meta (159-171)
packages/constants/src/notification.ts (2)
packages/types/src/notification.d.ts (1)
  • TNotificationSettings (3-7)
web/core/constants/fetch-keys.ts (1)
  • NOTIFICATION_SETTINGS (280-281)
apiserver/plane/db/models/notification.py (2)
apiserver/plane/app/serializers/notification.py (3)
  • Meta (16-18)
  • Meta (22-24)
  • Meta (27-29)
apiserver/plane/db/models/user.py (3)
  • Meta (114-118)
  • Meta (198-202)
  • Meta (228-233)
apiserver/plane/bgtasks/notification_task.py (2)
apiserver/plane/db/models/notification.py (3)
  • NotificationTransportChoices (178-180)
  • WorkspaceUserNotificationPreference (126-175)
  • Notification (9-45)
apiserver/plane/db/models/issue.py (5)
  • IssueComment (455-493)
  • Issue (104-253)
  • IssueSubscriber (560-585)
  • IssueAssignee (340-365)
  • IssueActivity (415-452)
web/core/store/notifications/workspace-notification-settings.store.ts (7)
packages/types/src/users.d.ts (1)
  • IUser (15-33)
packages/types/src/workspace.d.ts (1)
  • IWorkspace (5-20)
packages/types/src/notification.d.ts (1)
  • TWorkspaceUserNotification (9-21)
web/core/services/workspace-notification-settings.service.ts (1)
  • WorkspaceNotificationSettingsService (12-42)
web/core/store/root.store.ts (1)
  • CoreRootStore (39-135)
web/core/store/workspace/index.ts (1)
  • currentWorkspace (98-103)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
🪛 Ruff (0.8.2)
apiserver/plane/app/views/workspace/home.py

5-5: Line too long (104 > 88)

(E501)

apiserver/plane/app/serializers/notification.py

4-4: Line too long (105 > 88)

(E501)

apiserver/plane/bgtasks/notification_task.py

359-359: Line too long (122 > 88)

(E501)


402-402: Line too long (98 > 88)

(E501)


539-539: Line too long (90 > 88)

(E501)

🪛 Biome (1.9.4)
web/core/services/workspace-notification-settings.service.ts

[error] 22-22: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)


[error] 39-39: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.

(lint/complexity/noUselessCatch)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (56)
web/core/components/inbox/index.ts (1)

7-7: LGTM! Export statement for settings module is properly added.

The export statement follows the existing pattern in the file and makes the notification settings components accessible through the inbox component's index.

packages/types/src/index.d.ts (1)

44-44: LGTM! Export statement for notification types is properly added.

The export follows the existing pattern in the file and makes the new notification types accessible throughout the application, which is essential for TypeScript type checking of the new notification settings functionality.

web/ce/components/inbox/index.ts (1)

1-1: LGTM! Export statement for settings module in CE version is properly added.

This change ensures that the Community Edition has access to the same notification settings components as the core version, maintaining feature parity.

web/ce/components/inbox/settings/index.ts (1)

1-2: Export structure looks good

This file establishes a clean barrel export pattern, making it easy to import all inbox setting components from a single entry point.

apiserver/plane/app/views/__init__.py (1)

206-206: Properly imported the new workspace notification preference endpoint

The new WorkspaceUserNotificationPreferenceEndpoint is correctly imported alongside the other notification-related endpoints, maintaining the organization of the file.

web/core/components/inbox/settings/index.ts (1)

1-3: Export structure looks good

This file establishes a clean barrel export pattern for the inbox settings components, providing a consolidated entry point for importing these components elsewhere in the application.

apiserver/plane/app/serializers/notification.py (1)

26-29: New serializer for workspace notification preferences looks good

The WorkspaceUserNotificationPreferenceSerializer class is correctly implemented, inheriting from BaseSerializer and configuring the Meta class appropriately. It will handle the serialization and deserialization of workspace-level notification preferences for different transport methods.

web/core/components/inbox/settings/content-header.tsx (1)

1-17: Clean and well-structured component!

The InboxSettingsContentHeader component is implemented using proper TypeScript types and follows React best practices with functional components. The styling with Tailwind CSS classes provides a clear visual hierarchy for the header content.

web/core/hooks/store/notifications/use-workspace-notification-settings.ts (1)

1-12: Well-implemented custom hook!

The hook correctly follows React patterns by using the context API and providing proper error handling when used outside a StoreProvider. The hook provides a clean interface to access workspace notification settings from the MobX store.

web/app/[workspaceSlug]/(projects)/notifications/settings/layout.tsx (1)

1-24: Good layout component structure!

The component implements a clean layout structure for the notifications settings page with proper TypeScript typing for props.

packages/i18n/src/locales/es/translations.json (1)

2444-2476: Comprehensive translations for notification settings!

The added Spanish translations for notification settings are thorough and cover all the necessary UI elements including section headers, descriptions, and specific notification types.

packages/i18n/src/locales/ko/translations.json (1)

2442-2476: New localization keys added for notification settings feature.

These translations support the new workspace notification preferences feature, providing Korean language support for inbox settings, notification types, and status messages. The translations are well-structured with both titles and descriptive subtitles for each setting.

apiserver/plane/app/urls/notification.py (1)

9-9: Import added for new workspace notification preferences endpoint.

The import is correctly added to support the new URL routes below.

packages/i18n/src/locales/fr/translations.json (1)

2442-2474: New French localization keys added for notification settings feature.

These translations provide proper French language support for the new notification preferences feature. The translations are well-structured with titles and descriptive subtitles that clearly explain each notification setting's purpose.

packages/i18n/src/locales/de/translations.json (1)

2398-2430: LGTM - New notification settings translations are well structured and comprehensive.

The added German translations for notification settings are well-organized and cover all necessary UI elements for the new inbox settings feature. The translations maintain consistency with the existing localization patterns in the file.

packages/types/src/notification.d.ts (2)

1-7: TypeScript types properly defined for notification settings.

The TNotificationSettings type is well-structured with appropriate properties for internationalization and type safety. This will help ensure consistent implementation of notification settings across the application.


9-21: User notification preferences type is comprehensive.

The TWorkspaceUserNotification type properly captures all the necessary properties for workspace-specific notification preferences, with appropriate boolean flags for different notification types. This provides good type safety for the notification settings feature.

packages/i18n/src/locales/zh-TW/translations.json (1)

2444-2476: LGTM - Traditional Chinese translations consistently implemented.

The Traditional Chinese translations for notification settings match the structure of the German translations and provide good coverage of all notification setting options. The translations are well-formatted and maintain consistency with existing localization patterns.

packages/i18n/src/locales/zh-CN/translations.json (4)

2432-2440: LGTM: Clean implementation of notification settings localization

The new "notification_settings" section is well-structured with clear key naming conventions that align with the UI components. The header and description translations look good.


2441-2451: LGTM: Notification channel options and task updates translations

Good implementation of notification channel options (Plane, email, Slack) and task updates section with appropriate subtitle explanations.


2452-2462: LGTM: Property and comment notification translations

The translations for different notification types (property changes, status, priority, etc.) are well-organized with clear titles and descriptive subtitles.


2463-2464: LGTM: Status messages for settings updates

The success and error message translations for settings updates are clear and concise.

packages/i18n/src/locales/sk/translations.json (1)

2441-2472: LGTM: Slovak translations for notification settings

The Slovak translations for the notification settings section are consistent with the Chinese version, maintaining the same structure and covering all the necessary UI elements.

web/app/[workspaceSlug]/(projects)/notifications/settings/header.tsx (3)

1-13: LGTM: Clean import structure

The imports are well-organized and properly grouped by category with clear comments separating them. Using "use client" directive is appropriate for this client-side component.


14-17: LGTM: Component setup with proper hooks

Good use of MobX's observer pattern for reactivity, and appropriate hooks for workspace data and translations.


18-44: LGTM: Clean breadcrumb navigation implementation

The header with breadcrumb navigation is well-structured, providing a clear path from notifications to settings. The use of icons enhances the UI, and the translation keys are consistent with the added translations.

apiserver/plane/app/serializers/__init__.py (1)

118-122: LGTM: Improved import formatting with new serializer

The change to a multi-line import format improves readability, and the addition of the WorkspaceUserNotificationPreferenceSerializer aligns with the new notification settings feature.

packages/i18n/src/locales/ro/translations.json (1)

2436-2468: Notification Settings (Romanian): Looks well-structured and consistent!

The newly added "notification_settings" section neatly introduces all the keys required for the inbox settings update. The labels, subtitles, and placeholders (e.g. {workspace}) are clear and align with the naming conventions used throughout the file. Please verify that these translations completely match the backend API and UI design expectations.

packages/i18n/src/locales/it/translations.json (1)

2441-2473: Notification Settings (Italian): Comprehensive and consistent addition!

The new "notification_settings" block provides all the necessary keys and their corresponding subtitles for managing notification preferences (including inbox settings, advanced settings, task updates, comments, and various notifications). The use of placeholders like {workspace} and the overall terminology is consistent with other sections in the file. Please double-check that these strings are in full agreement with the UI and backend requirements.

packages/i18n/src/locales/ua/translations.json (1)

2400-2432: Complete translation coverage for notification settings - good job!

The new notification settings section provides comprehensive Ukrainian translations for all UI elements in the inbox settings feature. This includes headers, descriptions, and specific notification types, ensuring a consistent user experience for Ukrainian-speaking users.

web/core/components/inbox/settings/content-wrapper.tsx (1)

13-31: Well-structured responsive component with good mobile adaptation.

The component correctly handles different screen sizes, showing the hamburger toggle only on mobile screens and adjusting padding responsively. The use of the cn utility for class merging is a good practice.

packages/i18n/src/locales/en/translations.json (1)

2275-2307: Complete English translations for the notification settings feature.

All required translation keys for the inbox notification settings feature are properly implemented with clear and concise English text. The translations cover all UI elements including headers, descriptions, and specific notification types.

packages/i18n/src/locales/ja/translations.json (1)

2442-2474: Good implementation of notification settings localization in Japanese

The newly added "notification_settings" section includes comprehensive translations for all required UI elements such as settings titles, descriptions, and notification categories. The structure is consistent with the rest of the file and provides complete coverage for the new notification preferences feature.

packages/i18n/src/locales/cs/translations.json (1)

2440-2472: Well-implemented Czech translation for notification settings

The added "notification_settings" section maintains consistency with other language files while providing complete coverage of all notification preference UI elements. The translations are properly structured and include all necessary strings for the new inbox settings feature.

apiserver/plane/db/models/__init__.py (1)

47-53: Good refactoring of imports with additional notification models

The change properly imports the new NotificationTransportChoices and WorkspaceUserNotificationPreference models needed for the workspace-specific notification preferences feature. The multi-line formatting improves readability, making the code more maintainable.

packages/i18n/src/locales/vi-VN/translations.json (1)

2398-2429: The new Vietnamese translation keys for notification settings look good!

The translation strings are well-organized, follow the same structure as other sections, and provide complete coverage for the new notification settings feature.

web/core/constants/fetch-keys.ts (2)

224-225: Good addition of the Slack connection status fetch key.

The implementation follows the established pattern in the file, correctly using the workspace slug to create a unique fetch key identifier.


280-281: Properly implemented notification settings fetch key.

This follows the standard pattern for fetch keys in this file, ensuring consistent formatting of the workspace slug.

packages/i18n/src/locales/pl/translations.json (1)

2401-2432: Polish translations for notification settings look well-implemented.

All required translation keys are present and properly structured. The translations align with the feature's requirements and follow consistent formatting.

web/ce/components/inbox/settings/root.tsx (1)

1-56: LGTM! The component structure is clean and well-organized.

The component correctly implements a notification settings UI with clear sections for task updates and comments. Good use of internationalization, grid layouts, and proper component composition.

packages/i18n/src/locales/id/translations.json (1)

2436-2468: LGTM! The translations are well-structured and comprehensive.

The added translations for notification settings are well-organized and provide complete coverage for the new notification settings UI. The translations are consistent with the existing patterns in the file and include all the necessary keys used in the new components.

apiserver/plane/app/views/workspace/home.py (1)

62-92: LGTM! The notification preference functionality is well-implemented.

The added code correctly implements the functionality to retrieve and create user notification preferences for different transport types. It follows the same pattern as the existing preference management code and ensures that users have all the necessary notification preference records.

web/ce/components/inbox/settings/update-setting-row.tsx (1)

1-40: LGTM! The component is well-structured and follows React best practices.

This component effectively implements a row for notification settings with proper type definitions, internationalization support, and MobX integration via the observer HOC. The layout is clean and organized with good separation of concerns.

web/app/[workspaceSlug]/(projects)/notifications/settings/page.tsx (1)

1-46: Nice implementation of the notification settings page!

The component is well-structured, following React and Next.js best practices. Good use of:

  • MobX's observer pattern to react to observable state changes
  • SWR for data fetching with proper loading state handling
  • Translation hooks for internationalization
  • Clean component composition with appropriate wrappers and headers
apiserver/plane/db/models/notification.py (1)

150-155: Consider default values consistency with existing models

The boolean fields in this model default to False while the existing UserNotificationPreference model defaults most fields to True. Verify this is intentional as it may lead to inconsistent default behaviors.

web/core/components/inbox/settings/update-setting.tsx (2)

24-41: Good error handling with user feedback

The component properly handles async operations with try/catch blocks and provides appropriate user feedback through toast notifications. Well implemented!


10-13: Well-typed props interface

The props are well-typed using TypeScript, which enhances code readability and provides better development experience with autocompletion and type checking.

web/core/store/root.store.ts (2)

25-25: Clean import addition for workspace notification settings

The import statement follows the established pattern and correctly imports both the interface and implementation class.


64-64: Consistent store initialization pattern

The new workspaceNotificationSettings property is properly declared and consistently initialized in both the constructor and resetOnSignOut method, following the established pattern for store management.

Also applies to: 94-94, 128-128

apiserver/plane/app/views/notification/base.py (2)

12-12: Good import usage.
No issues found with adding the serializer import here.


21-23: Clean import definitions.
Importing Workspace, WorkspaceUserNotificationPreference, and NotificationTransportChoices looks correct and consistent with the usage below.

packages/constants/src/notification.ts (1)

140-205: Constants and enums look adequately structured.
All enums and arrays for notification settings are logically organized and easy to read.

apiserver/plane/bgtasks/notification_task.py (1)

210-271: Clean mention processing function.
The process_mentions function is well-structured and clearly separates new mentions, removed mentions, and comment-based mentions.

web/core/store/notifications/workspace-notification-settings.store.ts (3)

51-68: The autorun implementation is well-structured.

Good use of autorun to reactively update the store when the current user or workspace changes. The condition checks both for initialization and updates, ensuring the store stays in sync with the root store.


116-123: Good use of runInAction with lodash set.

The combination of runInAction with lodash's set function is a good approach for updating nested state structures in MobX while ensuring reactivity. This pattern correctly updates the settings without causing unnecessary rerenders.


11-28: Well-defined interface with clear documentation.

The interface is well-structured with clear sections for observables, computed functions, and actions. This makes the code more maintainable and provides good documentation for consumers of the store.

Comment on lines +62 to +64
# Notification preference get or create
workspace = Workspace.objects.get(slug=slug)
get_notification_preferences = (
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove redundant workspace fetch.

The workspace object is already fetched on line 21, so there's no need to fetch it again here. This redundant fetch can be removed to improve performance.

  # Notification preference get or create
- workspace = Workspace.objects.get(slug=slug)
  get_notification_preferences = (
      WorkspaceUserNotificationPreference.objects.filter(
📝 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
# Notification preference get or create
workspace = Workspace.objects.get(slug=slug)
get_notification_preferences = (
# Notification preference get or create
get_notification_preferences = (
WorkspaceUserNotificationPreference.objects.filter(

Comment on lines +126 to +175
class WorkspaceUserNotificationPreference(BaseModel):
# user it is related to
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="user_workspace_notification_preferences",
)
# workspace if it is applicable
workspace = models.ForeignKey(
"db.Workspace",
on_delete=models.CASCADE,
related_name="workspace_user_notification_preferences",
)
# project
project = models.ForeignKey(
"db.Project",
on_delete=models.CASCADE,
related_name="project_user_notification_preferences",
null=True,
)

transport = models.CharField(max_length=50, default="EMAIL")

# task updates
property_change = models.BooleanField(default=False)
state_change = models.BooleanField(default=False)
priority = models.BooleanField(default=False)
assignee = models.BooleanField(default=False)
start_due_date = models.BooleanField(default=False)
# comments fields
comment = models.BooleanField(default=False)
mention = models.BooleanField(default=False)
comment_reactions = models.BooleanField(default=False)
class Meta:
unique_together = ["workspace", "user", "transport", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["workspace", "user", "transport"],
condition=models.Q(deleted_at__isnull=True),
name="notification_preferences_unique_workspace_user_transport_when_deleted_at_null",
)
]
verbose_name = "Workspace User Notification Preference"
verbose_name_plural = "Workspace User Notification Preferences"
db_table = "workspace_user_notification_preferences"
ordering = ("-created_at",)

def __str__(self):
"""Return the user"""
return f"<{self.user}>"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Model definition looks good but should explicitly use choice field constraints

The WorkspaceUserNotificationPreference model is well-structured with appropriate relationships and fields. However, the transport field should explicitly use the NotificationTransportChoices you've defined.

- transport = models.CharField(max_length=50, default="EMAIL")
+ transport = models.CharField(
+     max_length=50,
+     choices=NotificationTransportChoices.choices,
+     default=NotificationTransportChoices.EMAIL
+ )

This provides better data validation and makes the relationship between the field and the choices class explicit.

📝 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
class WorkspaceUserNotificationPreference(BaseModel):
# user it is related to
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="user_workspace_notification_preferences",
)
# workspace if it is applicable
workspace = models.ForeignKey(
"db.Workspace",
on_delete=models.CASCADE,
related_name="workspace_user_notification_preferences",
)
# project
project = models.ForeignKey(
"db.Project",
on_delete=models.CASCADE,
related_name="project_user_notification_preferences",
null=True,
)
transport = models.CharField(max_length=50, default="EMAIL")
# task updates
property_change = models.BooleanField(default=False)
state_change = models.BooleanField(default=False)
priority = models.BooleanField(default=False)
assignee = models.BooleanField(default=False)
start_due_date = models.BooleanField(default=False)
# comments fields
comment = models.BooleanField(default=False)
mention = models.BooleanField(default=False)
comment_reactions = models.BooleanField(default=False)
class Meta:
unique_together = ["workspace", "user", "transport", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["workspace", "user", "transport"],
condition=models.Q(deleted_at__isnull=True),
name="notification_preferences_unique_workspace_user_transport_when_deleted_at_null",
)
]
verbose_name = "Workspace User Notification Preference"
verbose_name_plural = "Workspace User Notification Preferences"
db_table = "workspace_user_notification_preferences"
ordering = ("-created_at",)
def __str__(self):
"""Return the user"""
return f"<{self.user}>"
class WorkspaceUserNotificationPreference(BaseModel):
# user it is related to
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="user_workspace_notification_preferences",
)
# workspace if it is applicable
workspace = models.ForeignKey(
"db.Workspace",
on_delete=models.CASCADE,
related_name="workspace_user_notification_preferences",
)
# project
project = models.ForeignKey(
"db.Project",
on_delete=models.CASCADE,
related_name="project_user_notification_preferences",
null=True,
)
transport = models.CharField(
max_length=50,
choices=NotificationTransportChoices.choices,
default=NotificationTransportChoices.EMAIL
)
# task updates
property_change = models.BooleanField(default=False)
state_change = models.BooleanField(default=False)
priority = models.BooleanField(default=False)
assignee = models.BooleanField(default=False)
start_due_date = models.BooleanField(default=False)
# comments fields
comment = models.BooleanField(default=False)
mention = models.BooleanField(default=False)
comment_reactions = models.BooleanField(default=False)
class Meta:
unique_together = ["workspace", "user", "transport", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["workspace", "user", "transport"],
condition=models.Q(deleted_at__isnull=True),
name="notification_preferences_unique_workspace_user_transport_when_deleted_at_null",
)
]
verbose_name = "Workspace User Notification Preference"
verbose_name_plural = "Workspace User Notification Preferences"
db_table = "workspace_user_notification_preferences"
ordering = ("-created_at",)
def __str__(self):
"""Return the user"""
return f"<{self.user}>"

Comment on lines +345 to +354
actor = User.objects.get(pk=actor_id)
for mention_id in comment_mentions:
if mention_id != actor_id:
in_app_preference = WorkspaceUserNotificationPreference.objects.filter(
user_id=mention_id,
workspace_id=issue_workspace_id,
transport=NotificationTransportChoices.IN_APP[0],
).first()

if in_app_preference.mention:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent potential NoneType error when checking in-app preferences.
If in_app_preference is None, calling in_app_preference.mention will raise an error. Consider verifying it first:

- if in_app_preference.mention:
+ if in_app_preference and in_app_preference.mention:
     ...

- if not in_app_preference.mention:
+ if not in_app_preference or not in_app_preference.mention:
     continue

Also applies to: 371-378

Comment on lines +482 to +483
if email_preference.mention:
for issue_activity in issue_activities_created:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid NoneType usage in email preference checks.
Similar to the in-app logic, do a null check to prevent AttributeError if email_preference is not found:

- if email_preference.mention:
+ if email_preference and email_preference.mention:
    ...

- if not email_preference.mention:
+ if not email_preference or not email_preference.mention:
    continue

Also applies to: 503-504

Comment on lines +94 to +101
getNotificationSettingsForTransport = computedFn((transport: EWorkspaceNotificationTransport) => {
const workspaceSlug = this.store.workspaceRoot?.currentWorkspace?.slug;
if (!workspaceSlug || !transport) {
return;
}
const notificationSettingsForTransport = this.settings[workspaceSlug][transport] || undefined;
return notificationSettingsForTransport;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prevent potential undefined access error.

The code attempts to access this.settings[workspaceSlug][transport] without checking if this.settings[workspaceSlug] exists. This could lead to a runtime error if the settings for the workspace haven't been initialized yet.

getNotificationSettingsForTransport = computedFn((transport: EWorkspaceNotificationTransport) => {
  const workspaceSlug = this.store.workspaceRoot?.currentWorkspace?.slug;
  if (!workspaceSlug || !transport) {
    return;
  }
- const notificationSettingsForTransport = this.settings[workspaceSlug][transport] || undefined;
+ const workspaceSettings = this.settings[workspaceSlug];
+ const notificationSettingsForTransport = workspaceSettings ? workspaceSettings[transport] : undefined;
  return notificationSettingsForTransport;
});
📝 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
getNotificationSettingsForTransport = computedFn((transport: EWorkspaceNotificationTransport) => {
const workspaceSlug = this.store.workspaceRoot?.currentWorkspace?.slug;
if (!workspaceSlug || !transport) {
return;
}
const notificationSettingsForTransport = this.settings[workspaceSlug][transport] || undefined;
return notificationSettingsForTransport;
});
getNotificationSettingsForTransport = computedFn((transport: EWorkspaceNotificationTransport) => {
const workspaceSlug = this.store.workspaceRoot?.currentWorkspace?.slug;
if (!workspaceSlug || !transport) {
return;
}
const workspaceSettings = this.settings[workspaceSlug];
const notificationSettingsForTransport = workspaceSettings ? workspaceSettings[transport] : undefined;
return notificationSettingsForTransport;
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants