Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Add ways to manage addresses for Spaces #6151

Merged
merged 21 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b2b9525
Convert RoomAliasField to Typescript
t3chguy Jun 7, 2021
8c34a84
Add way to specify address during public space creation
t3chguy Jun 7, 2021
6d2a739
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into…
t3chguy Jun 7, 2021
a7eb09a
Convert EditableItemList & AliasSettings to Typescript
t3chguy Jun 7, 2021
4725a9e
Extract useRoomState hook into hooks directory
t3chguy Jun 7, 2021
9454a4e
Convert AdvancedRoomSettingsTab to Typescript
t3chguy Jun 8, 2021
8d4ac90
Convert RoomPublishSetting and LabelledToggleSwitch to Typescript
t3chguy Jun 8, 2021
13a2f77
improve defaults for useRoomState and useStateToggle hooks
t3chguy Jun 8, 2021
5c85ee1
Make AdvancedRoomSettingsTab space-aware
t3chguy Jun 8, 2021
78debcc
Add method to disable StyledRadioGroup and wrap description in elemen…
t3chguy Jun 8, 2021
fdecba2
Make AliasSettings space-aware, remove stale unused props
t3chguy Jun 8, 2021
856a568
Improve useRoomPowerLevels hook
t3chguy Jun 8, 2021
90bb7c1
Switch Space Settings for a tabbed view with a bunch more settings ex…
t3chguy Jun 8, 2021
54241f4
delint
t3chguy Jun 8, 2021
83c30b2
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into…
t3chguy Jun 15, 2021
5130d5e
Hide addresses section for private spaces
t3chguy Jun 15, 2021
5098a30
delint
t3chguy Jun 15, 2021
5dc542f
Iterate PR
t3chguy Jun 22, 2021
1286be1
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into…
t3chguy Jun 22, 2021
83296b7
Fix typing
t3chguy Jun 22, 2021
e4542e1
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into…
t3chguy Jun 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion res/css/views/dialogs/_SettingsDialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ limitations under the License.
*/

// Not actually a component but things shared by settings components
.mx_UserSettingsDialog, .mx_RoomSettingsDialog {
.mx_UserSettingsDialog, .mx_RoomSettingsDialog, .mx_SpaceSettingsDialog {
width: 90vw;
max-width: 1000px;
// set the height too since tabbed view scrolls itself.
Expand Down
51 changes: 48 additions & 3 deletions res/css/views/dialogs/_SpaceSettingsDialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ limitations under the License.
*/

.mx_SpaceSettingsDialog {
width: 480px;
color: $primary-fg-color;

.mx_SpaceSettings_errorText {
Expand All @@ -32,8 +31,44 @@ limitations under the License.
margin-left: 16px;
}

.mx_AccessibleButton_kind_danger {
margin-top: 28px;
.mx_SettingsTab_section {
.mx_SettingsTab_section_caption {
margin-top: 12px;
margin-bottom: 20px;
}

& + .mx_SettingsTab_subheading {
border-top: 1px solid $message-body-panel-bg-color;
margin-top: 0;
padding-top: 24px;
}

.mx_RadioButton {
margin-top: 8px;
margin-bottom: 4px;

.mx_RadioButton_content {
font-weight: $font-semi-bold;
line-height: $font-18px;
color: $primary-fg-color;
}

& + span {
font-size: $font-15px;
line-height: $font-18px;
color: $secondary-fg-color;
margin-left: 26px;
}
}

.mx_SettingsTab_showAdvanced {
margin: 16px 0;
padding: 0;
}

.mx_SettingsFlag {
margin-top: 24px;
}
}

.mx_SpaceSettingsDialog_buttons {
Expand All @@ -52,4 +87,14 @@ limitations under the License.
.mx_AccessibleButton_hasKind {
padding: 8px 22px;
}

.mx_TabbedView_tabLabel {
.mx_SpaceSettingsDialog_generalIcon::before {
mask-image: url('$(res)/img/element-icons/settings.svg');
}

.mx_SpaceSettingsDialog_visibilityIcon::before {
mask-image: url('$(res)/img/element-icons/eye.svg');
}
}
}
2 changes: 1 addition & 1 deletion res/css/views/spaces/_SpaceBasicSettings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

.mx_SpaceBasicSettings {
.mx_Field {
margin: 32px 0;
margin: 24px 0;
}

.mx_SpaceBasicSettings_avatarContainer {
Expand Down
3 changes: 3 additions & 0 deletions res/img/element-icons/eye.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion src/components/views/dialogs/RoomSettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ export default class RoomSettingsDialog extends React.Component<IProps> {
ROOM_ADVANCED_TAB,
_td("Advanced"),
"mx_RoomSettingsDialog_warningIcon",
<AdvancedRoomSettingsTab roomId={this.props.roomId} closeSettingsFn={this.props.onFinished} />,
<AdvancedRoomSettingsTab
roomId={this.props.roomId}
closeSettingsFn={() => this.props.onFinished(true)}
/>,
));
}

Expand Down
173 changes: 48 additions & 125 deletions src/components/views/dialogs/SpaceSettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, {useState} from 'react';
import {Room} from "matrix-js-sdk/src/models/room";
import {MatrixClient} from "matrix-js-sdk/src/client";
import {EventType} from "matrix-js-sdk/src/@types/event";
import React, { useMemo } from 'react';
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";

import {_t} from '../../../languageHandler';
import {IDialogProps} from "./IDialogProps";
import { _t, _td } from '../../../languageHandler';
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog";
import DevtoolsDialog from "./DevtoolsDialog";
import SpaceBasicSettings from '../spaces/SpaceBasicSettings';
import {getTopic} from "../elements/RoomTopic";
import {avatarUrlForRoom} from "../../../Avatar";
import ToggleSwitch from "../elements/ToggleSwitch";
import AccessibleButton from "../elements/AccessibleButton";
import Modal from "../../../Modal";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import {useDispatcher} from "../../../hooks/useDispatcher";
import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView";
import { useDispatcher } from "../../../hooks/useDispatcher";
import TabbedView, { Tab } from "../../structures/TabbedView";
import SpaceSettingsGeneralTab from '../spaces/SpaceSettingsGeneralTab';
import SpaceSettingsVisibilityTab from "../spaces/SpaceSettingsVisibilityTab";
import SettingsStore from "../../../settings/SettingsStore";
import { UIFeature } from "../../../settings/UIFeature";
import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab";

export enum SpaceSettingsTab {
General = "SPACE_GENERAL_TAB",
Visibility = "SPACE_VISIBILITY_TAB",
Advanced = "SPACE_ADVANCED_TAB",
}

interface IProps extends IDialogProps {
matrixClient: MatrixClient;
Expand All @@ -45,63 +48,30 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
}
});

const [busy, setBusy] = useState(false);
const [error, setError] = useState("");

const userId = cli.getUserId();

const [newAvatar, setNewAvatar] = useState<File>(null); // undefined means to remove avatar
const canSetAvatar = space.currentState.maySendStateEvent(EventType.RoomAvatar, userId);
const avatarChanged = newAvatar !== null;

const [name, setName] = useState<string>(space.name);
const canSetName = space.currentState.maySendStateEvent(EventType.RoomName, userId);
const nameChanged = name !== space.name;

const currentTopic = getTopic(space);
const [topic, setTopic] = useState<string>(currentTopic);
const canSetTopic = space.currentState.maySendStateEvent(EventType.RoomTopic, userId);
const topicChanged = topic !== currentTopic;

const currentJoinRule = space.getJoinRule();
const [joinRule, setJoinRule] = useState(currentJoinRule);
const canSetJoinRule = space.currentState.maySendStateEvent(EventType.RoomJoinRules, userId);
const joinRuleChanged = joinRule !== currentJoinRule;

const onSave = async () => {
setBusy(true);
const promises = [];

if (avatarChanged) {
if (newAvatar) {
promises.push(cli.sendStateEvent(space.roomId, EventType.RoomAvatar, {
url: await cli.uploadContent(newAvatar),
}, ""));
} else {
promises.push(cli.sendStateEvent(space.roomId, EventType.RoomAvatar, {}, ""));
}
}

if (nameChanged) {
promises.push(cli.setRoomName(space.roomId, name));
}

if (topicChanged) {
promises.push(cli.setRoomTopic(space.roomId, topic));
}

if (joinRuleChanged) {
promises.push(cli.sendStateEvent(space.roomId, EventType.RoomJoinRules, { join_rule: joinRule }, ""));
}

const results = await Promise.allSettled(promises);
setBusy(false);
const failures = results.filter(r => r.status === "rejected");
if (failures.length > 0) {
console.error("Failed to save space settings: ", failures);
setError(_t("Failed to save space settings."));
}
};
const tabs = useMemo(() => {
return [
new Tab(
SpaceSettingsTab.General,
_td("General"),
"mx_SpaceSettingsDialog_generalIcon",
<SpaceSettingsGeneralTab matrixClient={cli} space={space} onFinished={onFinished} />,
),
new Tab(
SpaceSettingsTab.Visibility,
_td("Visibility"),
"mx_SpaceSettingsDialog_visibilityIcon",
<SpaceSettingsVisibilityTab matrixClient={cli} space={space} />,
),
SettingsStore.getValue(UIFeature.AdvancedSettings)
? new Tab(
SpaceSettingsTab.Advanced,
_td("Advanced"),
"mx_RoomSettingsDialog_warningIcon",
<AdvancedRoomSettingsTab roomId={space.roomId} closeSettingsFn={onFinished} />,
)
: null,
].filter(Boolean);
}, [cli, space, onFinished]);

return <BaseDialog
title={_t("Space settings")}
Expand All @@ -110,61 +80,14 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
onFinished={onFinished}
fixedWidth={false}
>
<div className="mx_SpaceSettingsDialog_content" id="mx_SpaceSettingsDialog">
<div>{ _t("Edit settings relating to your space.") }</div>

{ error && <div className="mx_SpaceRoomView_errorText">{ error }</div> }

<SpaceFeedbackPrompt onClick={() => onFinished(false)} />

<SpaceBasicSettings
avatarUrl={avatarUrlForRoom(space, 80, 80, "crop")}
avatarDisabled={busy || !canSetAvatar}
setAvatar={setNewAvatar}
name={name}
nameDisabled={busy || !canSetName}
setName={setName}
topic={topic}
topicDisabled={busy || !canSetTopic}
setTopic={setTopic}
/>

<div>
{ _t("Make this space private") }
<ToggleSwitch
checked={joinRule !== "public"}
onChange={checked => setJoinRule(checked ? "invite" : "public")}
disabled={!canSetJoinRule}
aria-label={_t("Make this space private")}
/>
</div>

<AccessibleButton
kind="danger"
onClick={() => {
defaultDispatcher.dispatch({
action: "leave_room",
room_id: space.roomId,
});
}}
>
{ _t("Leave Space") }
</AccessibleButton>

<div className="mx_SpaceSettingsDialog_buttons">
<AccessibleButton onClick={() => Modal.createDialog(DevtoolsDialog, {roomId: space.roomId})}>
{ _t("View dev tools") }
</AccessibleButton>
<AccessibleButton onClick={onFinished} disabled={busy} kind="link">
{ _t("Cancel") }
</AccessibleButton>
<AccessibleButton onClick={onSave} disabled={busy} kind="primary">
{ busy ? _t("Saving...") : _t("Save Changes") }
</AccessibleButton>
</div>
<div
className="mx_SpaceSettingsDialog_content"
id="mx_SpaceSettingsDialog"
title={_t("Settings - %(spaceName)s", { spaceName: space.name })}
>
<TabbedView tabs={tabs} />
</div>
</BaseDialog>;
};

export default SpaceSettingsDialog;

Loading