fix room setting crash in knock_restricted join rule (#2323)
authorAjay Bura <32841439+ajbura@users.noreply.github.com>
Tue, 13 May 2025 08:48:52 +0000 (14:18 +0530)
committerGitHub <noreply@github.com>
Tue, 13 May 2025 08:48:52 +0000 (14:18 +0530)
* fix room setting crash in knock_restricted join rule

* only show knock & space member join rule for space children

* fix knock restricted icon and label

src/app/components/JoinRulesSwitcher.tsx
src/app/features/common-settings/general/RoomJoinRules.tsx

index e78c19cec3639183cb0a407aaf211c3e1dadd848..9507317a0c8d371f453c2d8bea8ea5ef724c4f12 100644 (file)
@@ -17,12 +17,16 @@ import { JoinRule } from 'matrix-js-sdk';
 import FocusTrap from 'focus-trap-react';
 import { stopPropagation } from '../utils/keyboard';
 
-type JoinRuleIcons = Record<JoinRule, IconSrc>;
+export type ExtraJoinRules = 'knock_restricted';
+export type ExtendedJoinRules = JoinRule | ExtraJoinRules;
+
+type JoinRuleIcons = Record<ExtendedJoinRules, IconSrc>;
 export const useRoomJoinRuleIcon = (): JoinRuleIcons =>
   useMemo(
     () => ({
       [JoinRule.Invite]: Icons.HashLock,
       [JoinRule.Knock]: Icons.HashLock,
+      knock_restricted: Icons.Hash,
       [JoinRule.Restricted]: Icons.Hash,
       [JoinRule.Public]: Icons.HashGlobe,
       [JoinRule.Private]: Icons.HashLock,
@@ -34,6 +38,7 @@ export const useSpaceJoinRuleIcon = (): JoinRuleIcons =>
     () => ({
       [JoinRule.Invite]: Icons.SpaceLock,
       [JoinRule.Knock]: Icons.SpaceLock,
+      knock_restricted: Icons.Space,
       [JoinRule.Restricted]: Icons.Space,
       [JoinRule.Public]: Icons.SpaceGlobe,
       [JoinRule.Private]: Icons.SpaceLock,
@@ -41,12 +46,13 @@ export const useSpaceJoinRuleIcon = (): JoinRuleIcons =>
     []
   );
 
-type JoinRuleLabels = Record<JoinRule, string>;
+type JoinRuleLabels = Record<ExtendedJoinRules, string>;
 export const useRoomJoinRuleLabel = (): JoinRuleLabels =>
   useMemo(
     () => ({
       [JoinRule.Invite]: 'Invite Only',
       [JoinRule.Knock]: 'Knock & Invite',
+      knock_restricted: 'Space Members or Knock',
       [JoinRule.Restricted]: 'Space Members',
       [JoinRule.Public]: 'Public',
       [JoinRule.Private]: 'Invite Only',
@@ -54,7 +60,7 @@ export const useRoomJoinRuleLabel = (): JoinRuleLabels =>
     []
   );
 
-type JoinRulesSwitcherProps<T extends JoinRule[]> = {
+type JoinRulesSwitcherProps<T extends ExtendedJoinRules[]> = {
   icons: JoinRuleIcons;
   labels: JoinRuleLabels;
   rules: T;
@@ -63,7 +69,7 @@ type JoinRulesSwitcherProps<T extends JoinRule[]> = {
   disabled?: boolean;
   changing?: boolean;
 };
-export function JoinRulesSwitcher<T extends JoinRule[]>({
+export function JoinRulesSwitcher<T extends ExtendedJoinRules[]>({
   icons,
   labels,
   rules,
@@ -79,7 +85,7 @@ export function JoinRulesSwitcher<T extends JoinRule[]>({
   };
 
   const handleChange = useCallback(
-    (selectedRule: JoinRule) => {
+    (selectedRule: ExtendedJoinRules) => {
       setCords(undefined);
       onChange(selectedRule);
     },
@@ -131,7 +137,7 @@ export function JoinRulesSwitcher<T extends JoinRule[]>({
         fill="Soft"
         radii="300"
         outlined
-        before={<Icon size="100" src={icons[value]} />}
+        before={<Icon size="100" src={icons[value] ?? icons[JoinRule.Restricted]} />}
         after={
           changing ? (
             <Spinner size="100" variant="Secondary" fill="Soft" />
@@ -142,7 +148,7 @@ export function JoinRulesSwitcher<T extends JoinRule[]>({
         onClick={handleOpenMenu}
         disabled={disabled}
       >
-        <Text size="B300">{labels[value]}</Text>
+        <Text size="B300">{labels[value] ?? 'Unsupported'}</Text>
       </Button>
     </PopOut>
   );
index 158ca25b541421fe3c88716a11c62cf2c4ac35e1..ebd4cad50d66387a36eedde070ab125a74a160ab 100644 (file)
@@ -4,6 +4,7 @@ import { JoinRule, MatrixError, RestrictedAllowType } from 'matrix-js-sdk';
 import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
 import { IPowerLevels, powerLevelAPI } from '../../../hooks/usePowerLevels';
 import {
+  ExtendedJoinRules,
   JoinRulesSwitcher,
   useRoomJoinRuleIcon,
   useRoomJoinRuleLabel,
@@ -32,6 +33,7 @@ export function RoomJoinRules({ powerLevels }: RoomJoinRulesProps) {
   const mx = useMatrixClient();
   const room = useRoom();
   const roomVersion = parseInt(room.getVersion(), 10);
+  const allowKnockRestricted = roomVersion >= 10;
   const allowRestricted = roomVersion >= 8;
   const allowKnock = roomVersion >= 7;
   const space = useSpaceOptionally();
@@ -47,18 +49,21 @@ export function RoomJoinRules({ powerLevels }: RoomJoinRulesProps) {
   const content = joinRuleEvent?.getContent<RoomJoinRulesEventContent>();
   const rule: JoinRule = content?.join_rule ?? JoinRule.Invite;
 
-  const joinRules: Array<JoinRule> = useMemo(() => {
-    const r: JoinRule[] = [JoinRule.Invite];
+  const joinRules: Array<ExtendedJoinRules> = useMemo(() => {
+    const r: ExtendedJoinRules[] = [JoinRule.Invite];
     if (allowKnock) {
       r.push(JoinRule.Knock);
     }
     if (allowRestricted && space) {
       r.push(JoinRule.Restricted);
     }
+    if (allowKnockRestricted && space) {
+      r.push('knock_restricted');
+    }
     r.push(JoinRule.Public);
 
     return r;
-  }, [allowRestricted, allowKnock, space]);
+  }, [allowKnockRestricted, allowRestricted, allowKnock, space]);
 
   const icons = useRoomJoinRuleIcon();
   const spaceIcons = useSpaceJoinRuleIcon();
@@ -66,9 +71,9 @@ export function RoomJoinRules({ powerLevels }: RoomJoinRulesProps) {
 
   const [submitState, submit] = useAsyncCallback(
     useCallback(
-      async (joinRule: JoinRule) => {
+      async (joinRule: ExtendedJoinRules) => {
         const allow: RestrictedRoomAllowContent[] = [];
-        if (joinRule === JoinRule.Restricted) {
+        if (joinRule === JoinRule.Restricted || joinRule === 'knock_restricted') {
           const parents = getStateEvents(room, StateEvent.SpaceParent).map((event) =>
             event.getStateKey()
           );
@@ -82,7 +87,7 @@ export function RoomJoinRules({ powerLevels }: RoomJoinRulesProps) {
         }
 
         const c: RoomJoinRulesEventContent = {
-          join_rule: joinRule,
+          join_rule: joinRule as JoinRule,
         };
         if (allow.length > 0) c.allow = allow;
         await mx.sendStateEvent(room.roomId, StateEvent.RoomJoinRules as any, c);