mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-04 22:40:29 +03:00
handle additional creators in room upgrade
This commit is contained in:
parent
6763721983
commit
1594a2ccd1
2 changed files with 139 additions and 90 deletions
|
|
@ -34,9 +34,11 @@ import { findAndReplace } from '../../utils/findAndReplace';
|
||||||
import { highlightText } from '../../styles/CustomHtml.css';
|
import { highlightText } from '../../styles/CustomHtml.css';
|
||||||
import { makeHighlightRegex } from '../../plugins/react-custom-html-parser';
|
import { makeHighlightRegex } from '../../plugins/react-custom-html-parser';
|
||||||
|
|
||||||
export const useAdditionalCreators = () => {
|
export const useAdditionalCreators = (defaultCreators?: string[]) => {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const [additionalCreators, setAdditionalCreators] = useState<string[]>([]);
|
const [additionalCreators, setAdditionalCreators] = useState<string[]>(
|
||||||
|
() => defaultCreators?.filter((id) => id !== mx.getSafeUserId()) ?? []
|
||||||
|
);
|
||||||
|
|
||||||
const addAdditionalCreator = (userId: string) => {
|
const addAdditionalCreator = (userId: string) => {
|
||||||
if (userId === mx.getSafeUserId()) return;
|
if (userId === mx.getSafeUserId()) return;
|
||||||
|
|
@ -75,11 +77,13 @@ type AdditionalCreatorInputProps = {
|
||||||
additionalCreators: string[];
|
additionalCreators: string[];
|
||||||
onSelect: (userId: string) => void;
|
onSelect: (userId: string) => void;
|
||||||
onRemove: (userId: string) => void;
|
onRemove: (userId: string) => void;
|
||||||
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
export function AdditionalCreatorInput({
|
export function AdditionalCreatorInput({
|
||||||
additionalCreators,
|
additionalCreators,
|
||||||
onSelect,
|
onSelect,
|
||||||
onRemove,
|
onRemove,
|
||||||
|
disabled,
|
||||||
}: AdditionalCreatorInputProps) {
|
}: AdditionalCreatorInputProps) {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const [menuCords, setMenuCords] = useState<RectCords>();
|
const [menuCords, setMenuCords] = useState<RectCords>();
|
||||||
|
|
@ -164,6 +168,7 @@ export function AdditionalCreatorInput({
|
||||||
radii="Pill"
|
radii="Pill"
|
||||||
after={<Icon size="50" src={Icons.Cross} />}
|
after={<Icon size="50" src={Icons.Cross} />}
|
||||||
onClick={() => onRemove(creator)}
|
onClick={() => onRemove(creator)}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Text size="B300">{creator}</Text>
|
<Text size="B300">{creator}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
|
|
@ -289,6 +294,7 @@ export function AdditionalCreatorInput({
|
||||||
radii="Pill"
|
radii="Pill"
|
||||||
onClick={handleOpenMenu}
|
onClick={handleOpenMenu}
|
||||||
aria-pressed={!!menuCords}
|
aria-pressed={!!menuCords}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Icon size="50" src={Icons.Plus} />
|
<Icon size="50" src={Icons.Plus} />
|
||||||
</Chip>
|
</Chip>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FormEventHandler, useCallback, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
color,
|
color,
|
||||||
|
|
@ -14,10 +14,9 @@ import {
|
||||||
IconButton,
|
IconButton,
|
||||||
Icon,
|
Icon,
|
||||||
Icons,
|
Icons,
|
||||||
Input,
|
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError, Method } from 'matrix-js-sdk';
|
||||||
import { RoomTombstoneEventContent } from 'matrix-js-sdk/lib/types';
|
import { RoomTombstoneEventContent } from 'matrix-js-sdk/lib/types';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||||
|
|
@ -31,6 +30,133 @@ import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
|
||||||
import { useCapabilities } from '../../../hooks/useCapabilities';
|
import { useCapabilities } from '../../../hooks/useCapabilities';
|
||||||
import { stopPropagation } from '../../../utils/keyboard';
|
import { stopPropagation } from '../../../utils/keyboard';
|
||||||
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
|
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
|
||||||
|
import {
|
||||||
|
AdditionalCreatorInput,
|
||||||
|
RoomVersionSelector,
|
||||||
|
useAdditionalCreators,
|
||||||
|
} from '../../../components/create-room';
|
||||||
|
import { useAlive } from '../../../hooks/useAlive';
|
||||||
|
import { creatorsSupported } from '../../../utils/matrix';
|
||||||
|
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||||
|
import { BreakWord } from '../../../styles/Text.css';
|
||||||
|
|
||||||
|
function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const room = useRoom();
|
||||||
|
const alive = useAlive();
|
||||||
|
const creators = useRoomCreators(room);
|
||||||
|
|
||||||
|
const capabilities = useCapabilities();
|
||||||
|
const roomVersions = capabilities['m.room_versions'];
|
||||||
|
const [selectedRoomVersion, selectRoomVersion] = useState(roomVersions?.default ?? '1');
|
||||||
|
useEffect(() => {
|
||||||
|
// capabilities load async
|
||||||
|
selectRoomVersion(roomVersions?.default ?? '1');
|
||||||
|
}, [roomVersions?.default]);
|
||||||
|
|
||||||
|
const allowAdditionalCreators = creatorsSupported(selectedRoomVersion);
|
||||||
|
const { additionalCreators, addAdditionalCreator, removeAdditionalCreator } =
|
||||||
|
useAdditionalCreators(Array.from(creators));
|
||||||
|
|
||||||
|
const [upgradeState, upgrade] = useAsyncCallback(
|
||||||
|
useCallback(
|
||||||
|
async (version: string, newAdditionalCreators?: string[]) => {
|
||||||
|
await mx.http.authedRequest(Method.Post, `/rooms/${room.roomId}/upgrade`, undefined, {
|
||||||
|
new_version: version,
|
||||||
|
additional_creators: newAdditionalCreators,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[mx, room]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const upgrading = upgradeState.status === AsyncStatus.Loading;
|
||||||
|
|
||||||
|
const handleUpgradeRoom = () => {
|
||||||
|
const version = selectedRoomVersion;
|
||||||
|
|
||||||
|
upgrade(version, allowAdditionalCreators ? additionalCreators : undefined).then(() => {
|
||||||
|
if (alive()) {
|
||||||
|
requestClose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||||
|
<OverlayCenter>
|
||||||
|
<FocusTrap
|
||||||
|
focusTrapOptions={{
|
||||||
|
initialFocus: false,
|
||||||
|
onDeactivate: requestClose,
|
||||||
|
clickOutsideDeactivates: true,
|
||||||
|
escapeDeactivates: stopPropagation,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Dialog variant="Surface">
|
||||||
|
<Header
|
||||||
|
style={{
|
||||||
|
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
|
||||||
|
borderBottomWidth: config.borderWidth.B300,
|
||||||
|
}}
|
||||||
|
variant="Surface"
|
||||||
|
size="500"
|
||||||
|
>
|
||||||
|
<Box grow="Yes">
|
||||||
|
<Text size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
||||||
|
</Box>
|
||||||
|
<IconButton size="300" onClick={requestClose} radii="300">
|
||||||
|
<Icon src={Icons.Cross} />
|
||||||
|
</IconButton>
|
||||||
|
</Header>
|
||||||
|
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||||
|
<Text priority="400" style={{ color: color.Critical.Main }}>
|
||||||
|
<b>This action is irreversible!</b>
|
||||||
|
</Text>
|
||||||
|
<Box direction="Column" gap="100">
|
||||||
|
<Text size="L400">Options</Text>
|
||||||
|
<RoomVersionSelector
|
||||||
|
versions={roomVersions?.available ? Object.keys(roomVersions.available) : ['1']}
|
||||||
|
value={selectedRoomVersion}
|
||||||
|
onChange={selectRoomVersion}
|
||||||
|
disabled={upgrading}
|
||||||
|
/>
|
||||||
|
{allowAdditionalCreators && (
|
||||||
|
<SequenceCard
|
||||||
|
style={{ padding: config.space.S300 }}
|
||||||
|
variant="SurfaceVariant"
|
||||||
|
direction="Column"
|
||||||
|
gap="500"
|
||||||
|
>
|
||||||
|
<AdditionalCreatorInput
|
||||||
|
additionalCreators={additionalCreators}
|
||||||
|
onSelect={addAdditionalCreator}
|
||||||
|
onRemove={removeAdditionalCreator}
|
||||||
|
disabled={upgrading}
|
||||||
|
/>
|
||||||
|
</SequenceCard>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{upgradeState.status === AsyncStatus.Error && (
|
||||||
|
<Text className={BreakWord} style={{ color: color.Critical.Main }} size="T200">
|
||||||
|
{(upgradeState.error as MatrixError).message}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
onClick={handleUpgradeRoom}
|
||||||
|
variant="Secondary"
|
||||||
|
disabled={upgrading}
|
||||||
|
before={upgrading && <Spinner size="200" variant="Secondary" fill="Solid" />}
|
||||||
|
>
|
||||||
|
<Text size="B400">{room.isSpaceRoom() ? 'Upgrade Space' : 'Upgrade Room'}</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Dialog>
|
||||||
|
</FocusTrap>
|
||||||
|
</OverlayCenter>
|
||||||
|
</Overlay>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
type RoomUpgradeProps = {
|
type RoomUpgradeProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
|
|
@ -47,9 +173,6 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
const roomVersion = createContent?.room_version ?? '1';
|
const roomVersion = createContent?.room_version ?? '1';
|
||||||
const predecessorRoomId = createContent?.predecessor?.room_id;
|
const predecessorRoomId = createContent?.predecessor?.room_id;
|
||||||
|
|
||||||
const capabilities = useCapabilities();
|
|
||||||
const defaultRoomVersion = capabilities['m.room_versions']?.default;
|
|
||||||
|
|
||||||
const tombstoneContent = useStateEvent(
|
const tombstoneContent = useStateEvent(
|
||||||
room,
|
room,
|
||||||
StateEvent.RoomTombstone
|
StateEvent.RoomTombstone
|
||||||
|
|
@ -80,31 +203,8 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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 [prompt, setPrompt] = useState(false);
|
||||||
|
|
||||||
const handleSubmitUpgrade: FormEventHandler<HTMLFormElement> = (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 (
|
return (
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
|
|
@ -150,8 +250,7 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
fill="Solid"
|
fill="Solid"
|
||||||
radii="300"
|
radii="300"
|
||||||
disabled={upgrading || !canUpgrade}
|
disabled={!canUpgrade}
|
||||||
before={upgrading && <Spinner size="100" variant="Secondary" fill="Solid" />}
|
|
||||||
onClick={() => setPrompt(true)}
|
onClick={() => setPrompt(true)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Upgrade</Text>
|
<Text size="B300">Upgrade</Text>
|
||||||
|
|
@ -160,63 +259,7 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{upgradeState.status === AsyncStatus.Error && (
|
{prompt && <RoomUpgradeDialog requestClose={() => setPrompt(false)} />}
|
||||||
<Text style={{ color: color.Critical.Main }} size="T200">
|
|
||||||
{(upgradeState.error as MatrixError).message}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{prompt && (
|
|
||||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
|
||||||
<OverlayCenter>
|
|
||||||
<FocusTrap
|
|
||||||
focusTrapOptions={{
|
|
||||||
initialFocus: false,
|
|
||||||
onDeactivate: () => setPrompt(false),
|
|
||||||
clickOutsideDeactivates: true,
|
|
||||||
escapeDeactivates: stopPropagation,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Dialog variant="Surface" as="form" onSubmit={handleSubmitUpgrade}>
|
|
||||||
<Header
|
|
||||||
style={{
|
|
||||||
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
|
|
||||||
borderBottomWidth: config.borderWidth.B300,
|
|
||||||
}}
|
|
||||||
variant="Surface"
|
|
||||||
size="500"
|
|
||||||
>
|
|
||||||
<Box grow="Yes">
|
|
||||||
<Text size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
|
||||||
</Box>
|
|
||||||
<IconButton size="300" onClick={() => setPrompt(false)} radii="300">
|
|
||||||
<Icon src={Icons.Cross} />
|
|
||||||
</IconButton>
|
|
||||||
</Header>
|
|
||||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
|
||||||
<Text priority="400" style={{ color: color.Critical.Main }}>
|
|
||||||
<b>This action is irreversible!</b>
|
|
||||||
</Text>
|
|
||||||
<Box direction="Column" gap="100">
|
|
||||||
<Text size="L400">Version</Text>
|
|
||||||
<Input
|
|
||||||
defaultValue={defaultRoomVersion}
|
|
||||||
name="versionInput"
|
|
||||||
variant="Background"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Button type="submit" variant="Secondary">
|
|
||||||
<Text size="B400">
|
|
||||||
{room.isSpaceRoom() ? 'Upgrade Space' : 'Upgrade Room'}
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Dialog>
|
|
||||||
</FocusTrap>
|
|
||||||
</OverlayCenter>
|
|
||||||
</Overlay>
|
|
||||||
)}
|
|
||||||
</SettingTile>
|
</SettingTile>
|
||||||
</SequenceCard>
|
</SequenceCard>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue