Skip to content

Conversation

@abhinavkrin
Copy link
Member

@abhinavkrin abhinavkrin commented Aug 26, 2025

Proposed changes (including videos or screenshots)

This PR fixes unexpected behaviors with the E2EE toggle in Teams:

  • Removes the dependency on the set-readonly permission that was disabling the E2EE toggle during Team creation.
  • Ensures that the E2EE toggle is disabled nad turned off when Private toggled is turned off.
  • Ensures that E2EE toggle remains configurable when toggling Broadcast

Issue(s)

Steps to test or reproduce

  1. Create a role without set-readonly permission.
  2. Assign this role to a user.
  3. As that user, create a new Team → verify that the E2EE toggle is available and independent of set-readonly.
  4. With E2E_Enable = true and E2E_Enabled_Default_PrivateRooms = true:
    • Create/edit a Team → encrypted toggle is ON by default but remains configurable.
    • Toggle Private off → encrypted toggle turns off and is disabled.
    • Toggle Broadcast on/off → encrypted toggle state does not change.

Further comments

CORE-1326
CORE-1327

Summary by CodeRabbit

  • Bug Fixes

    • Fixed Create Team modal where the encryption toggle reset/disabled incorrectly when switching Private/Broadcast or lacking unrelated permissions.
  • Improvements

    • Encryption defaults now follow workspace E2E settings.
    • Read-only toggle respects user permission and broadcast state.
    • Updated encryption help text; removed broadcast-specific restriction.
  • Internationalization

    • Removed obsolete “Not available for broadcast” message across multiple locales.
  • Tests

    • Added comprehensive tests covering encryption, private, broadcast, and read-only interactions.
  • Chores

    • Patch version bumps for dependencies.

@abhinavkrin abhinavkrin requested a review from a team as a code owner August 26, 2025 13:28
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Aug 26, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@abhinavkrin
Copy link
Member Author

I have cherry picked the commit from the PR #36792 as it was the hotfix that should be present for this fix.

@changeset-bot
Copy link

changeset-bot bot commented Aug 26, 2025

🦋 Changeset detected

Latest commit: 8cf32fd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 40 packages
Name Type
@rocket.chat/i18n Patch
@rocket.chat/meteor Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-voip Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/gazzodown Patch
@rocket.chat/livechat Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/queue-worker Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/http-router Patch
@rocket.chat/model-typings Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/presence-service Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/license Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@abhinavkrin abhinavkrin force-pushed the fix/e2ee-toggle-behavior-on-teams branch from e80ab03 to 8822b81 Compare August 26, 2025 13:38
@codecov
Copy link

codecov bot commented Aug 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.42%. Comparing base (d832f91) to head (8cf32fd).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #36797      +/-   ##
===========================================
+ Coverage    66.25%   66.42%   +0.17%     
===========================================
  Files         3339     3341       +2     
  Lines       113725   114284     +559     
  Branches     21064    21179     +115     
===========================================
+ Hits         75347    75915     +568     
+ Misses       35687    35683       -4     
+ Partials      2691     2686       -5     
Flag Coverage Δ
e2e 57.69% <40.00%> (+<0.01%) ⬆️
unit 71.15% <100.00%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

cardoso
cardoso previously approved these changes Aug 27, 2025
@abhinavkrin abhinavkrin force-pushed the fix/e2ee-toggle-behavior-on-teams branch from 8822b81 to 8a7b9f6 Compare September 9, 2025 18:52
@abhinavkrin abhinavkrin requested a review from cardoso September 9, 2025 18:53
@dougfabris dougfabris added this to the 7.11.0 milestone Sep 9, 2025
Copy link
Member

@dougfabris dougfabris left a comment

Choose a reason for hiding this comment

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

Nice work here, I just have a concern regarding set-readonly

Signed-off-by: Abhinav Kumar <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

This change updates Create Team modals and related hooks to decouple encryption from broadcast, gate read‑only by permission, and align encryption defaults with settings. It removes broadcast-specific encryption messaging and translations, adds comprehensive tests, and includes a changeset noting a patch bump and the Teams modal bug fix scope.

Changes

Cohort / File(s) Summary
Create Team modals (logic updates)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx, apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx
Aligned encryption default to require both E2E settings; removed broadcast-driven encryption resets; simplified encryption gating to isPrivate && e2eEnabled; introduced canSetReadOnly and `readOnlyDisabled = broadcast
Create Team modal tests
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx
Added parameterized tests covering encryption/private/broadcast/read-only interactions under varying E2E settings and permissions for both old and new implementations.
Encrypted description hooks (API/logic)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx, apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx
Removed broadcast from inner function signature and logic; retained flow based on E2E enablement, privacy, and encryption.
Encrypted description hook tests
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx
Updated tests to drop broadcast input and related expectations; validated messages for E2E on/off, private/non-private, and encrypted states.
Locales cleanup
packages/i18n/src/locales/en.i18n.json, .../nb.i18n.json, .../nn.i18n.json, .../pt-BR.i18n.json, .../sv.i18n.json
Removed Not_available_for_broadcast translation key across locales.
Changeset metadata
.changeset/rare-walls-press.md
Added changeset bumping @rocket.chat/i18n and @rocket.chat/meteor with note about Teams modal encryption toggle bug fix scope.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant M as CreateTeamModal
  participant S as Settings (E2E_Enable, E2E_Default_Private)
  participant P as Permissions (set-readonly)

  U->>M: Open modal
  M->>S: Read E2E settings
  S-->>M: e2eEnabled, e2eDefaultPrivate
  M->>M: Compute encrypted default = e2eEnabled && e2eDefaultPrivate
  M->>P: Check 'set-readonly' (owner-scoped)
  P-->>M: canSetReadOnly
  M->>M: readOnlyDisabled = broadcast || !canSetReadOnly
  M->>M: canChangeEncrypted = isPrivate && e2eEnabled
  Note right of M: Encryption no longer depends on broadcast or read-only permission

  U->>M: Toggle Private/Broadcast/Read-only/Encrypted
  alt Toggle Read-only
    M->>M: Allow only if !readOnlyDisabled
  end
  alt Toggle Encrypted
    M->>M: Allow only if canChangeEncrypted
  end
  M-->>U: Update UI states and hints (no broadcast-specific hint)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly identifies the primary change—correcting the E2EE toggle behavior in the Teams creation modal and its interaction with private and broadcast toggles—and aligns with the pull request’s objectives without introducing unrelated details or noise.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I nudge the toggles, hop-hop—just so,
Private burrow locked, but secrets flow.
No broadcast burps to flip my key,
Permissions checked—an owner’s decree.
Strings trimmed neat, the hints now clean—
Patchy clouds parted, UI serene. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/e2ee-toggle-behavior-on-teams

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

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: 1

♻️ Duplicate comments (1)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (1)

59-59: Kept scoped permission for read-only — aligns with channel behavior.

🧹 Nitpick comments (16)
.changeset/rare-walls-press.md (1)

1-6: Clarify the changeset and reference tickets explicitly.

Recommend tightening the summary and referencing CORE-1326/CORE-1327 so the release notes are self-explanatory. Also mention the i18n key removal for completeness.

 ---
 '@rocket.chat/i18n': patch
 '@rocket.chat/meteor': patch
 ---
 
-Fixes an issue where the encryption toggle was incorrectly reset/disabled/enabled in the Teams creation modal when Broadcast or Private was toggled, or when the user lacked unrelated permissions.
+fix(teams): correct E2EE toggle behavior in Create Team modal
+
+- Remove dependency on `set-readonly` for the E2EE toggle availability.
+- Disable and turn OFF E2EE when "Private" is OFF; keep configurable when toggling "Broadcast".
+- Align encrypted room description logic (drop broadcast-specific message).
+- Remove `Not_available_for_broadcast` i18n key across locales.
+
+Refs CORE-1326, CORE-1327.
apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (1)

8-19: Return a memoized callback to avoid unstable function identity.

If consumers place this function in deps, it will currently change every render. Wrap it in useCallback.

-import { useTranslation } from 'react-i18next';
+import { useTranslation } from 'react-i18next';
+import { useCallback } from 'react';

 export const useEncryptedRoomDescription = (roomType: 'channel' | 'team') => {
   const { t } = useTranslation();
   const e2eEnabled = useSetting('E2E_Enable');

-  return ({ isPrivate, encrypted }: { isPrivate: boolean; encrypted: boolean }) => {
+  return useCallback(({ isPrivate, encrypted }: { isPrivate: boolean; encrypted: boolean }) => {
     if (!e2eEnabled) {
       return t('Not_available_for_this_workspace');
     }
     if (!isPrivate) {
       return t('Encrypted_not_available', { roomType });
     }
     if (encrypted) {
       return t('Encrypted_messages', { roomType });
     }
     return t('Encrypted_messages_false');
-  };
+  }, [e2eEnabled, t, roomType]);
 };
apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (4)

53-55: Coerce settings to booleans to avoid unknown typing and truthy pitfalls.

Prevents surprising values if settings are non-boolean or temporarily undefined.

-const e2eEnabled = useSetting('E2E_Enable');
-const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms') && e2eEnabled;
+const e2eEnabled = Boolean(useSetting('E2E_Enable'));
+const e2eEnabledForPrivateByDefault = Boolean(useSetting('E2E_Enabled_Default_PrivateRooms')) && e2eEnabled;

97-104: Drop the cast and rely on boolean-coerced settings.

   defaultValues: {
     isPrivate: canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true,
     readOnly: false,
-    encrypted: (e2eEnabledForPrivateByDefault as boolean) ?? false,
+    encrypted: e2eEnabledForPrivateByDefault,
     broadcast: false,
     members: [],
   },

108-115: Don’t force read-only to false when broadcast turns off; only force it on when broadcast turns on.

Current code overwrites a user’s explicit read-only choice when toggling broadcast off. Typically, broadcast ⇒ read-only, but read-only can exist without broadcast. Also, consider resetting encrypted if E2E is disabled at runtime.

-useEffect(() => {
-  if (!isPrivate) {
-    setValue('encrypted', false);
-  }
-
-  setValue('readOnly', broadcast);
-}, [watch, setValue, broadcast, isPrivate]);
+useEffect(() => {
+  if (!isPrivate) {
+    setValue('encrypted', false);
+  }
+}, [isPrivate, setValue]);
+
+useEffect(() => {
+  if (broadcast) {
+    setValue('readOnly', true);
+  }
+}, [broadcast, setValue]);
+
+// Optional: keep encrypted consistent if the global E2E setting flips while the modal is open.
+useEffect(() => {
+  if (!e2eEnabled) {
+    setValue('encrypted', false);
+  }
+}, [e2eEnabled, setValue]);

129-141: Sanitize payload: guard encrypted server-side param by privacy and E2E setting.

Even though the UI enforces it, double-check on submit to avoid sending an inconsistent state.

           room: {
             readOnly,
             extraData: {
               topic,
               broadcast,
-              encrypted,
+              encrypted: isPrivate && e2eEnabled && encrypted,
             },
           },
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (1)

47-54: LGTM: unencrypted/private path under E2E enabled is validated. Minor naming nit.

Avoid shadowing Jest’s describe by renaming the local variable.

-      const describe = result.current;
-      expect(describe({ isPrivate: true, encrypted: true })).toBe('Not_available_for_this_workspace');
+      const getHint = result.current;
+      expect(getHint({ isPrivate: true, encrypted: true })).toBe('Not_available_for_this_workspace');
@@
-      const describe = result.current;
-      expect(describe({ isPrivate: false, encrypted: false })).toBe('Encrypted_not_available');
+      const getHint = result.current;
+      expect(getHint({ isPrivate: false, encrypted: false })).toBe('Encrypted_not_available');
@@
-      const describe = result.current;
-      expect(describe({ isPrivate: true, encrypted: true })).toBe('Encrypted_messages');
+      const getHint = result.current;
+      expect(getHint({ isPrivate: true, encrypted: true })).toBe('Encrypted_messages');
@@
-      const describe = result.current;
-      expect(describe({ isPrivate: true, encrypted: false })).toBe('Encrypted_messages_false');
+      const getHint = result.current;
+      expect(getHint({ isPrivate: true, encrypted: false })).toBe('Encrypted_messages_false');
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx (1)

8-20: Solid simplification: broadcast removed; logic reads clean. Optional memoization + boolean cast.

Consider casting settings to boolean and memoizing the returned function to avoid recreations on re-render.

-import { useSetting } from '@rocket.chat/ui-contexts';
+import { useSetting } from '@rocket.chat/ui-contexts';
+import { useCallback } from 'react';
@@
-  const e2eEnabled = useSetting('E2E_Enable');
+  const e2eEnabled = Boolean(useSetting('E2E_Enable'));
@@
-  return ({ isPrivate, encrypted }: { isPrivate: boolean; encrypted: boolean }) => {
+  const getEncryptedHint = useCallback(({ isPrivate, encrypted }: { isPrivate: boolean; encrypted: boolean }) => {
     if (!e2eEnabled) {
       return t('Not_available_for_this_workspace');
     }
     if (!isPrivate) {
       return t('Encrypted_not_available', { roomType });
     }
     if (encrypted) {
       return t('Encrypted_messages', { roomType });
     }
     return t('Encrypted_messages_false');
-  };
+  }, [e2eEnabled, roomType, t]);
+
+  return getEncryptedHint;
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (3)

56-56: Default E2E now depends on both settings — good. Minor: make booleans explicit to drop later casts.

-const e2eEnabled = useSetting('E2E_Enable');
-const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms') && e2eEnabled;
+const e2eEnabled = Boolean(useSetting('E2E_Enable'));
+const e2eEnabledDefaultPrivate = Boolean(useSetting('E2E_Enabled_Default_PrivateRooms'));
+const e2eEnabledForPrivateByDefault = e2eEnabled && e2eEnabledDefaultPrivate;

100-106: Use the computed boolean directly; no need for cast/??.

- encrypted: (e2eEnabledForPrivateByDefault as boolean) ?? false,
+ encrypted: e2eEnabledForPrivateByDefault,

111-117: Effect dependencies: drop watch to avoid unnecessary re-runs.

watch is a stable function and not used as a value source here; including it can cause redundant executions.

-}, [watch, setValue, broadcast, isPrivate]);
+}, [setValue, broadcast, isPrivate]);
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (5)

13-13: Remove stray ESLint disable.

This disable doesn’t guard any symbol; keep only the one before the _name param.

-// eslint-disable-next-line @typescript-eslint/naming-convention

15-21: Clarify suite labels to match components.

Minor naming mismatch can confuse readers; make the labels explicit.

-	['CreateTeamModal', CreateTeamModalOld],
-	['CreateTeamModal in NavbarV2', CreateTeamModal],
+	['CreateTeamModal (legacy)', CreateTeamModalOld],
+	['CreateTeamModal (NavbarV2)', CreateTeamModal],

119-156: Optional: add parity check with set-readonly to assert Encrypted independence from permissions.

To lock in the “E2EE not tied to set-readonly” guarantee, mirror this test with .withPermission('set-readonly') and assert Encrypted remains enabled/configurable.

it('private team: Encrypted unaffected by set-readonly permission', async () => {
  render(<CreateTeamModalComponent onClose={() => null} />, {
    wrapper: mockAppRoot()
      .withPermission('set-readonly')
      .withSetting('E2E_Enable', true)
      .withSetting('E2E_Enabled_Default_PrivateRooms', true)
      .build(),
  });
  await userEvent.click(screen.getByText('Advanced_settings'));
  const encrypted = screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement;
  expect(encrypted).toBeEnabled();
});

200-206: Fix misleading inline comments (“stays ON” → “turns ON”).

ReadOnly flips from OFF to ON when Broadcast goes ON; it doesn’t “stay” ON.

-			// Broadcast: OFF -> ON (ReadOnly stays ON + disabled)
+			// Broadcast: OFF -> ON (ReadOnly turns ON + disabled)

Apply to both occurrences.

Also applies to: 221-225


22-256: Optional: factor helpers to reduce repetition.

A tiny helper for opening Advanced settings and fetching toggles will trim repetition and ease future maintenance.

const openAdvanced = async (user = userEvent.setup()) => {
  await user.click(screen.getByText('Advanced_settings'));
  return user;
};

const getToggles = () => ({
  encrypted: screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement,
  priv: screen.getByLabelText('Teams_New_Private_Label') as HTMLInputElement,
  broadcast: screen.getByLabelText('Teams_New_Broadcast_Label') as HTMLInputElement,
  readOnly: screen.getByLabelText('Teams_New_Read_only_Label') as HTMLInputElement,
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6876409 and 05b8e20.

📒 Files selected for processing (12)
  • .changeset/rare-walls-press.md (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (5 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx (1 hunks)
  • apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (5 hunks)
  • apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (1 hunks)
  • packages/i18n/src/locales/en.i18n.json (0 hunks)
  • packages/i18n/src/locales/nb.i18n.json (0 hunks)
  • packages/i18n/src/locales/nn.i18n.json (0 hunks)
  • packages/i18n/src/locales/pt-BR.i18n.json (0 hunks)
  • packages/i18n/src/locales/sv.i18n.json (0 hunks)
💤 Files with no reviewable changes (5)
  • packages/i18n/src/locales/pt-BR.i18n.json
  • packages/i18n/src/locales/sv.i18n.json
  • packages/i18n/src/locales/en.i18n.json
  • packages/i18n/src/locales/nn.i18n.json
  • packages/i18n/src/locales/nb.i18n.json
🧰 Additional context used
🧬 Code graph analysis (3)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (1)
packages/mock-providers/src/index.ts (1)
  • mockAppRoot (3-3)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (1)
packages/ui-contexts/src/index.ts (2)
  • useSetting (69-69)
  • usePermissionWithScopedRoles (56-56)
apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (1)
packages/ui-contexts/src/index.ts (2)
  • useSetting (69-69)
  • usePermissionWithScopedRoles (56-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (20)
apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (2)

8-19: LGTM: simplified, broadcast-free description logic matches the new UI behavior.


8-19: i18n keys verified
Encrypted_messages_false requires no { roomType } (definitions across locales contain no placeholders) and Not_available_for_broadcast is fully removed.

apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (3)

116-118: LGTM: gating rules mirror product requirements.

readOnlyDisabled = broadcast || !canSetReadOnly and canChangeEncrypted = isPrivate && e2eEnabled align with the objectives.


261-271: LGTM: disabled state and hint usage correctly reflect the new rules.


282-293: LGTM: read-only toggle is disabled when broadcast is on or permission is missing.

Pairs well with the effect change proposed above.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (3)

26-26: LGTM: correct expectation when E2E is disabled.


29-36: LGTM: non-private path under E2E enabled is validated.


38-45: LGTM: encrypted/private path under E2E enabled is validated.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (4)

119-120: Clear gating: readOnly disabled on broadcast or lack of permission; E2E toggle gated by private+E2E.


264-269: Correct: E2E toggle disables solely on canChangeEncrypted.


273-274: Hint call updated to { isPrivate, encrypted } — consistent with hook changes.


285-289: Read-only toggle disabled via readOnlyDisabled — matches permission/broadcast rules.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (8)

1-4: Solid test scaffolding and providers.

Imports and the mockAppRoot usage are appropriate for isolating settings/permissions.


8-10: Good: navigation side-effects mocked.

Mocking goToRoomById prevents accidental routing during render.


22-72: E2E defaults matrix covered well.

Assertions match the intended combinations of E2E_Enable and E2E_Enabled_Default_PrivateRooms.


74-117: Private toggle gating Encrypted is validated correctly.

ON→OFF forces OFF+disabled; OFF→ON re-enables without auto-turning ON. Matches spec.


119-156: Broadcast no longer mutates Encrypted—behavior verified.

Encrypted remains user-configurable regardless of Broadcast for private teams.


158-188: Non-private teams correctly forbid Encrypted.

Encrypted stays OFF+disabled regardless of Broadcast state. Good guard.


190-207: ReadOnly forced ON and disabled when Broadcast is ON—verified for both permission states.

Matches expected UX.

Also applies to: 209-226


228-256: ReadOnly enablement when Broadcast is OFF is correct.

Disabled without permission; enabled with permission.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

UTG Post-Process Complete

No new issues were detected in the generated code and all check runs have completed. The unit test generation process has completed successfully.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Creating a PR to put the unit tests in...

The changes have been created in this pull request: View PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

🎯 Unit Test Generation Post-Process Complete

The unit test generation and CI/CD fixing process has completed after reaching the maximum number of iterations. Please review the generated tests and any remaining issues manually.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Creating a PR to put the unit tests in...

The changes have been created in this pull request: View PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Caution

CodeRabbit timed out while planning changes for apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.spec.tsx. Skipping this file.

Copy link
Member

@dougfabris dougfabris left a comment

Choose a reason for hiding this comment

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

Looks good to me!

@dougfabris dougfabris added the stat: QA assured Means it has been tested and approved by a company insider label Sep 10, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Sep 10, 2025
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: 0

♻️ Duplicate comments (1)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (1)

27-27: Switch to userEvent.setup() (v14+) to avoid flakiness.

Create a user instance and replace static userEvent.<action> calls with await user.<action>(...).

 describe.each([
   ['CreateTeamModal', CreateTeamModalOld],
   ['CreateTeamModal in NavbarV2', CreateTeamModal],
 ] as const)(
   '%s',
   (_name: string, CreateTeamModalComponent: CreateTeamModalComponentType) => {
+    let user: ReturnType<typeof userEvent.setup>;
+    beforeEach(() => {
+      user = userEvent.setup();
+    });
     it('should render with encryption option disabled and set to off when E2E_Enable=false and E2E_Enabled_Default_PrivateRooms=false', async () => {
       render(<CreateTeamModalComponent onClose={() => null} />, {
         wrapper: mockAppRoot().withSetting('E2E_Enable', false).withSetting('E2E_Enabled_Default_PrivateRooms', false).build(),
       });
 
-      await userEvent.click(screen.getByText('Advanced_settings'));
+      await user.click(screen.getByText('Advanced_settings'));

Apply the same replacement for the other occurrences on the listed lines.

Also applies to: 40-40, 53-53, 67-67, 79-79, 101-101, 124-124, 163-163, 195-195, 214-214, 233-233, 248-248

🧹 Nitpick comments (14)
apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (2)

6-6: Strengthen typing for settings.

Use generic typing to avoid accidental truthy/falsy bugs if the setting shape changes.

- const e2eEnabled = useSetting('E2E_Enable');
+ const e2eEnabled = useSetting<boolean>('E2E_Enable');

4-19: Avoid duplication between header and NavBarV2 hooks.

Both files now contain identical logic; consider a single shared implementation (e.g., a util exported from one place) to prevent future drift.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx (2)

6-6: Add explicit boolean typing to the setting.

Same rationale as the header hook.

- const e2eEnabled = useSetting('E2E_Enable');
+ const e2eEnabled = useSetting<boolean>('E2E_Enable');

4-19: Consider DRYing this with the header hook.

Re-export from one module or pull shared logic into a small pure function for consistency.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (2)

29-36: Covers non‑private path; add the encrypted=true variant for completeness.

Currently only checks encrypted=false; add a case to ensure encrypted value is ignored when not private.

Add alongside the existing test:

it('returns "Encrypted_not_available" when room is not private even if encrypted=true', () => {
  const { result } = renderHook(() => useEncryptedRoomDescriptionHook(roomType), {
    wrapper: wrapper.withSetting('E2E_Enable', true).build(),
  });
  const describeRoom = result.current;
  expect(describeRoom({ isPrivate: false, encrypted: true })).toBe('Encrypted_not_available');
});

24-24: Rename local variable to avoid shadowing Jest’s global describe.

Minor readability nit.

- const describe = result.current;
+ const describeRoom = result.current;

And update subsequent usages accordingly.

Also applies to: 33-33, 42-42, 51-51

apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (3)

97-104: Initialize encrypted only when the initial room is private to avoid a brief flicker.

Today encrypted may start true then be turned off by the effect if the initial room is public. Compute it from the initial isPrivate.

   } = useForm<CreateTeamModalInputs>({
     defaultValues: {
-      isPrivate: canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true,
+      isPrivate: canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true,
       readOnly: false,
-      encrypted: (e2eEnabledForPrivateByDefault as boolean) ?? false,
+      encrypted:
+        ((canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true) &&
+          (e2eEnabledForPrivateByDefault as boolean)) ?? false,
       broadcast: false,
       members: [],
     },
   });

108-115: Effect deps: don’t include watch; also consider reacting to e2eEnabled.

watch is stable but unnecessary here. Optional: force encrypted=false if E2E is turned off while the modal is open.

-}, [watch, setValue, broadcast, isPrivate]);
+}, [setValue, broadcast, isPrivate]);

And (optional) add:

useEffect(() => {
  if (!e2eEnabled) setValue('encrypted', false);
}, [e2eEnabled, setValue]);

301-307: A11y: avoid aria-describedby pointing to a missing element when broadcast is off.

Only set it when the hint is rendered.

- aria-describedby={`${broadcastId}-hint`}
+ aria-describedby={value ? `${broadcastId}-hint` : undefined}
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (3)

56-56: Coerce settings to booleans to avoid tri-state issues.

useSetting returns unknown; rely on explicit Boolean coercion to prevent '' | 0 | undefined from leaking into logic.

- const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms') && e2eEnabled;
+ const e2eEnabledForPrivateByDefault =
+  Boolean(useSetting('E2E_Enabled_Default_PrivateRooms')) && Boolean(e2eEnabled);

100-106: Align encrypted default with initial privacy to avoid a transient “ON while public” state.

When canOnlyCreateOneType === 'c', isPrivate defaults to false but encrypted can still default to true until the effect runs. Compute encrypted from the same initial privacy.

-      isPrivate: canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true,
+      isPrivate: canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true,
       readOnly: false,
-      encrypted: (e2eEnabledForPrivateByDefault as boolean) ?? false,
+      encrypted:
+        ((canOnlyCreateOneType ? canOnlyCreateOneType === 'p' : true) &&
+          Boolean(e2eEnabledForPrivateByDefault)) ||
+        false,
       broadcast: false,

111-118: Split effects and drop watch from deps to reduce unnecessary re-renders.

Current effect runs more often than needed and sets values unconditionally.

-useEffect(() => {
-  if (!isPrivate) {
-    setValue('encrypted', false);
-  }
-
-  setValue('readOnly', broadcast);
-}, [watch, setValue, broadcast, isPrivate]);
+useEffect(() => {
+  if (!isPrivate) {
+    setValue('encrypted', false);
+  }
+}, [isPrivate, setValue]);
+
+useEffect(() => {
+  setValue('readOnly', broadcast);
+}, [broadcast, setValue]);
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (2)

23-33: Prefer getByRole for toggles to strengthen accessibility assertions.

Using roles makes queries resilient to copy changes and matches ARIA semantics.

- const encrypted = screen.getByLabelText('Teams_New_Encrypted_Label') as HTMLInputElement;
+ const encrypted = screen.getByRole('checkbox', { name: 'Teams_New_Encrypted_Label' }) as HTMLInputElement;

Repeat similarly for Teams_New_Private_Label, Teams_New_Broadcast_Label, and Teams_New_Read_only_Label.


190-207: Test name/comment mismatch.

The inline comment says “stays ON + disabled”, which matches the assertions; the test title says “disable and turn on ReadOnly toggle” (fine) — just ensure wording is consistent if you touch it next.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d832f91 and 8cf32fd.

📒 Files selected for processing (12)
  • .changeset/rare-walls-press.md (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (5 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (1 hunks)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx (1 hunks)
  • apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (5 hunks)
  • apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (1 hunks)
  • packages/i18n/src/locales/en.i18n.json (0 hunks)
  • packages/i18n/src/locales/nb.i18n.json (0 hunks)
  • packages/i18n/src/locales/nn.i18n.json (0 hunks)
  • packages/i18n/src/locales/pt-BR.i18n.json (0 hunks)
  • packages/i18n/src/locales/sv.i18n.json (0 hunks)
💤 Files with no reviewable changes (5)
  • packages/i18n/src/locales/nb.i18n.json
  • packages/i18n/src/locales/pt-BR.i18n.json
  • packages/i18n/src/locales/en.i18n.json
  • packages/i18n/src/locales/nn.i18n.json
  • packages/i18n/src/locales/sv.i18n.json
🧰 Additional context used
🧬 Code graph analysis (3)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.spec.tsx (2)
apps/meteor/client/lib/appLayout.tsx (1)
  • render (26-28)
packages/mock-providers/src/index.ts (1)
  • mockAppRoot (3-3)
apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (1)
packages/ui-contexts/src/index.ts (2)
  • useSetting (69-69)
  • usePermissionWithScopedRoles (56-56)
apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (1)
packages/ui-contexts/src/index.ts (2)
  • useSetting (69-69)
  • usePermissionWithScopedRoles (56-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (11)
.changeset/rare-walls-press.md (1)

1-6: Changeset reads well and matches the behavior change.

Packages bumped to patch; description accurately scopes the Teams modal E2EE fixes.

apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx (2)

8-19: Good removal of broadcast gating; logic is now minimal and consistent.

Clear branches: workspace disabled → non‑private → encrypted true/false.


1-20: No stale broadcast references remain. Verified that the Not_available_for_broadcast key isn’t present anywhere and no callers pass a broadcast argument to useEncryptedRoomDescription.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx (1)

8-19: Hook simplification looks good here as well.

Matches header version; behavior aligns with PR objectives.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx (1)

26-26: LGTM: E2E disabled path covered.

apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx (3)

54-54: Correct defaulting: require both E2E enable and private‑default flag.

This fixes the earlier over‑eager default. Nice.


116-118: Gating looks right: read‑only depends on broadcast/permission; encrypted on privacy/E2E.

Matches the PR intent (no dependency on set-readonly for E2EE).


261-271: Encrypted toggle and hint wiring look correct.

Minor nit: consider typing the hook as useEncryptedRoomDescription('team') already returns translated text; good.

apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/CreateTeamModal.tsx (3)

119-121: Read-only/encryption gating looks correct.

readOnlyDisabled = broadcast || !canSetReadOnly and canChangeEncrypted = isPrivate && e2eEnabled match the intended behavior and PR objectives.


262-274: Encrypted toggle and hint wiring LGTM.

Disabling via !canChangeEncrypted and removing broadcast from getEncryptedHint align with the new contract.


285-285: Read-only toggle disable condition is consistent with channel behavior.

Matches prior feedback and keeps UX consistent.

@kodiakhq kodiakhq bot merged commit e82cfaa into develop Sep 10, 2025
50 checks passed
@kodiakhq kodiakhq bot deleted the fix/e2ee-toggle-behavior-on-teams branch September 10, 2025 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants