diff --git a/src/app/features/room-settings/general/General.tsx b/src/app/features/room-settings/general/General.tsx
index 6d66406..1033c30 100644
--- a/src/app/features/room-settings/general/General.tsx
+++ b/src/app/features/room-settings/general/General.tsx
@@ -8,6 +8,7 @@ import { RoomEncryption } from './RoomEncryption';
import { RoomHistoryVisibility } from './RoomHistoryVisibility';
import { RoomJoinRules } from './RoomJoinRules';
import { RoomLocalAddresses, RoomPublishedAddresses } from './RoomAddress';
+import { RoomUpgrade } from './RoomUpgrade';
type GeneralProps = {
requestClose: () => void;
@@ -48,6 +49,10 @@ export function General({ requestClose }: GeneralProps) {
+
+ Advance Options
+
+
diff --git a/src/app/features/room-settings/general/RoomUpgrade.tsx b/src/app/features/room-settings/general/RoomUpgrade.tsx
new file mode 100644
index 0000000..fa1fa85
--- /dev/null
+++ b/src/app/features/room-settings/general/RoomUpgrade.tsx
@@ -0,0 +1,217 @@
+import React, { FormEventHandler, useCallback, useState } from 'react';
+import {
+ Button,
+ color,
+ Spinner,
+ Text,
+ Overlay,
+ OverlayBackdrop,
+ OverlayCenter,
+ Dialog,
+ Header,
+ config,
+ Box,
+ IconButton,
+ Icon,
+ Icons,
+ Input,
+} from 'folds';
+import FocusTrap from 'focus-trap-react';
+import { MatrixError } from 'matrix-js-sdk';
+import { RoomCreateEventContent, RoomTombstoneEventContent } from 'matrix-js-sdk/lib/types';
+import { SequenceCard } from '../../../components/sequence-card';
+import { SequenceCardStyle } from '../styles.css';
+import { SettingTile } from '../../../components/setting-tile';
+import { useRoom } from '../../../hooks/useRoom';
+import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
+import { IPowerLevels, powerLevelAPI } from '../../../hooks/usePowerLevels';
+import { StateEvent } from '../../../../types/matrix/room';
+import { useMatrixClient } from '../../../hooks/useMatrixClient';
+import { useStateEvent } from '../../../hooks/useStateEvent';
+import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
+import { useCapabilities } from '../../../hooks/useCapabilities';
+import { stopPropagation } from '../../../utils/keyboard';
+
+type RoomUpgradeProps = {
+ powerLevels: IPowerLevels;
+ requestClose: () => void;
+};
+export function RoomUpgrade({ powerLevels, requestClose }: RoomUpgradeProps) {
+ const mx = useMatrixClient();
+ const room = useRoom();
+ const { navigateRoom } = useRoomNavigate();
+ const createContent = useStateEvent(
+ room,
+ StateEvent.RoomCreate
+ )?.getContent();
+ const roomVersion = createContent?.room_version ?? 1;
+ const predecessorRoomId = createContent?.predecessor?.room_id;
+
+ const capabilities = useCapabilities();
+ const defaultRoomVersion = capabilities['m.room_versions']?.default;
+
+ const tombstoneContent = useStateEvent(
+ room,
+ StateEvent.RoomTombstone
+ )?.getContent();
+ const replacementRoom = tombstoneContent?.replacement_room;
+
+ const userPowerLevel = powerLevelAPI.getPowerLevel(powerLevels, mx.getSafeUserId());
+ const canUpgrade = powerLevelAPI.canSendStateEvent(
+ powerLevels,
+ StateEvent.RoomTombstone,
+ userPowerLevel
+ );
+
+ const handleOpenRoom = () => {
+ if (replacementRoom) {
+ requestClose();
+ navigateRoom(replacementRoom);
+ }
+ };
+
+ const handleOpenOldRoom = () => {
+ if (predecessorRoomId) {
+ requestClose();
+ navigateRoom(predecessorRoomId, createContent.predecessor?.event_id);
+ }
+ };
+
+ const [upgradeState, upgrade] = useAsyncCallback(
+ useCallback(
+ async (version: string) => {
+ await mx.upgradeRoom(room.roomId, version);
+ },
+ [mx, room]
+ )
+ );
+
+ const upgrading = upgradeState.status === AsyncStatus.Loading;
+
+ const [prompt, setPrompt] = useState(false);
+
+ const handleSubmitUpgrade: FormEventHandler = (evt) => {
+ evt.preventDefault();
+
+ const target = evt.target as HTMLFormElement | undefined;
+ const versionInput = target?.versionInput as HTMLInputElement | undefined;
+ const version = versionInput?.value.trim();
+ if (!version) return;
+
+ upgrade(version);
+ setPrompt(false);
+ };
+
+ return (
+
+
+ {predecessorRoomId && (
+
+ )}
+ {replacementRoom ? (
+
+ ) : (
+ }
+ onClick={() => setPrompt(true)}
+ >
+ Upgrade
+
+ )}
+
+ }
+ >
+ {upgradeState.status === AsyncStatus.Error && (
+
+ {(upgradeState.error as MatrixError).message}
+
+ )}
+
+ {prompt && (
+ }>
+
+ setPrompt(false),
+ clickOutsideDeactivates: true,
+ escapeDeactivates: stopPropagation,
+ }}
+ >
+
+
+
+
+ )}
+
+
+ );
+}