Skip to content

Commit 77b618e

Browse files
committed
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into anoa/new_spinner
* 'develop' of github.com:matrix-org/matrix-react-sdk: bandaid make js-sdk import happy? ts-ignore because something is made of fail js-sdk imports suck Iterate on the new room list resize handle Welcome no longer needs any props unexport things which need not exporting Instead of passing sso and cas urls to Welcome, route via start_sso and start_cas Move to mx_sso_hs_url and co for sso persistance to not conflict with guest creds Fix Welcome.html URLs improve typing Add account and room-account data hooks Create a StaticNotificationState for representative purposes Add StyledRadioGroup to simplify use of StyledRadioButton and use in Appearance Tab
2 parents e790a31 + 113dfc5 commit 77b618e

File tree

11 files changed

+200
-56
lines changed

11 files changed

+200
-56
lines changed

res/css/views/rooms/_RoomSublist2.scss

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -257,24 +257,23 @@ limitations under the License.
257257
cursor: ns-resize;
258258
border-radius: 3px;
259259

260-
// Update the render() function for RoomSublist2 if this changes
261-
height: 3px;
260+
// Update RESIZE_HANDLE_HEIGHT if this changes
261+
height: 4px;
262262

263263
// This is positioned directly below the 'show more' button.
264264
position: absolute;
265265
bottom: 0;
266266

267-
// Together, these make the bar 48px wide
268-
left: calc(50% - 24px);
269-
right: calc(50% - 24px);
267+
// Together, these make the bar 64px wide
268+
left: calc(50% - 32px);
269+
right: calc(50% - 32px);
270270
}
271271

272-
// TODO: Use less sketchy selector by replacing the resize component entirely
273-
// This causes flickering.
274-
.mx_RoomSublist2_showNButton:hover + .react-resizable-handle,
275-
.react-resizable-handle:hover {
276-
opacity: 0.8;
277-
background-color: $primary-fg-color;
272+
&:hover, &.mx_RoomSublist2_hasMenuOpen {
273+
.react-resizable-handle {
274+
opacity: 0.8;
275+
background-color: $primary-fg-color;
276+
}
278277
}
279278
}
280279

src/BasePlatform.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
2525
import {Action} from "./dispatcher/actions";
2626
import {hideToast as hideUpdateToast} from "./toasts/UpdateToast";
2727

28-
export const HOMESERVER_URL_KEY = "mx_hs_url";
29-
export const ID_SERVER_URL_KEY = "mx_is_url";
28+
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
29+
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
3030

3131
export enum UpdateCheckStatus {
3232
Checking = "CHECKING",
@@ -221,7 +221,7 @@ export default abstract class BasePlatform {
221221

222222
setLanguage(preferredLangs: string[]) {}
223223

224-
getSSOCallbackUrl(fragmentAfterLogin: string): URL {
224+
protected getSSOCallbackUrl(fragmentAfterLogin: string): URL {
225225
const url = new URL(window.location.href);
226226
url.hash = fragmentAfterLogin || "";
227227
return url;
@@ -235,9 +235,9 @@ export default abstract class BasePlatform {
235235
*/
236236
startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
237237
// persist hs url and is url for when the user is returned to the app with the login token
238-
localStorage.setItem(HOMESERVER_URL_KEY, mxClient.getHomeserverUrl());
238+
localStorage.setItem(SSO_HOMESERVER_URL_KEY, mxClient.getHomeserverUrl());
239239
if (mxClient.getIdentityServerUrl()) {
240-
localStorage.setItem(ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl());
240+
localStorage.setItem(SSO_ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl());
241241
}
242242
const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin);
243243
window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO

src/Lifecycle.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers";
4141
import {Mjolnir} from "./mjolnir/Mjolnir";
4242
import DeviceListener from "./DeviceListener";
4343
import {Jitsi} from "./widgets/Jitsi";
44-
import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "./BasePlatform";
44+
import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "./BasePlatform";
45+
46+
const HOMESERVER_URL_KEY = "mx_hs_url";
47+
const ID_SERVER_URL_KEY = "mx_is_url";
4548

4649
/**
4750
* Called at startup, to attempt to build a logged-in Matrix session. It tries
@@ -164,8 +167,8 @@ export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) {
164167
return Promise.resolve(false);
165168
}
166169

167-
const homeserver = localStorage.getItem(HOMESERVER_URL_KEY);
168-
const identityServer = localStorage.getItem(ID_SERVER_URL_KEY);
170+
const homeserver = localStorage.getItem(SSO_HOMESERVER_URL_KEY);
171+
const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY);
169172
if (!homeserver) {
170173
console.warn("Cannot log in with token: can't determine HS URL to use");
171174
return Promise.resolve(false);

src/components/structures/MatrixChat.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ limitations under the License.
1818
*/
1919

2020
import React, { createRef } from 'react';
21+
// @ts-ignore - XXX: no idea why this import fails
22+
import * as Matrix from "matrix-js-sdk";
2123
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
2224
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
2325
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
@@ -1612,6 +1614,19 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
16121614
});
16131615
} else if (screen === 'directory') {
16141616
dis.fire(Action.ViewRoomDirectory);
1617+
} else if (screen === "start_sso" || screen === "start_cas") {
1618+
// TODO if logged in, skip SSO
1619+
let cli = MatrixClientPeg.get();
1620+
if (!cli) {
1621+
const {hsUrl, isUrl} = this.props.serverConfig;
1622+
cli = Matrix.createClient({
1623+
baseUrl: hsUrl,
1624+
idBaseUrl: isUrl,
1625+
});
1626+
}
1627+
1628+
const type = screen === "start_sso" ? "sso" : "cas";
1629+
PlatformPeg.get().startSingleSignOn(cli, type, this.getFragmentAfterLogin());
16151630
} else if (screen === 'groups') {
16161631
dis.dispatch({
16171632
action: 'view_my_groups',
@@ -1915,17 +1930,19 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
19151930
this.onLoggedIn();
19161931
};
19171932

1918-
render() {
1919-
// console.log(`Rendering MatrixChat with view ${this.state.view}`);
1920-
1933+
getFragmentAfterLogin() {
19211934
let fragmentAfterLogin = "";
19221935
if (this.props.initialScreenAfterLogin &&
19231936
// XXX: workaround for https://github.com/vector-im/riot-web/issues/11643 causing a login-loop
19241937
!["welcome", "login", "register"].includes(this.props.initialScreenAfterLogin.screen)
19251938
) {
19261939
fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`;
19271940
}
1941+
return fragmentAfterLogin;
1942+
}
19281943

1944+
render() {
1945+
const fragmentAfterLogin = this.getFragmentAfterLogin();
19291946
let view;
19301947

19311948
if (this.state.view === Views.LOADING) {
@@ -2004,7 +2021,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
20042021
}
20052022
} else if (this.state.view === Views.WELCOME) {
20062023
const Welcome = sdk.getComponent('auth.Welcome');
2007-
view = <Welcome {...this.getServerProperties()} fragmentAfterLogin={fragmentAfterLogin} />;
2024+
view = <Welcome />;
20082025
} else if (this.state.view === Views.REGISTER) {
20092026
const Registration = sdk.getComponent('structures.auth.Registration');
20102027
view = (

src/components/structures/auth/SoftLogout.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg";
2525
import {sendLoginRequest} from "../../../Login";
2626
import AuthPage from "../../views/auth/AuthPage";
2727
import SSOButton from "../../views/elements/SSOButton";
28-
import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "../../../BasePlatform";
28+
import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform";
2929

3030
const LOGIN_VIEW = {
3131
LOADING: 1,
@@ -158,8 +158,8 @@ export default class SoftLogout extends React.Component {
158158
async trySsoLogin() {
159159
this.setState({busy: true});
160160

161-
const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY);
162-
const isUrl = localStorage.getItem(ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl();
161+
const hsUrl = localStorage.getItem(SSO_HOMESERVER_URL_KEY);
162+
const isUrl = localStorage.getItem(SSO_ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl();
163163
const loginType = "m.login.token";
164164
const loginParams = {
165165
token: this.props.realQueryParams['loginToken'],

src/components/views/auth/Welcome.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ import React from 'react';
1818
import * as sdk from '../../../index';
1919
import SdkConfig from '../../../SdkConfig';
2020
import AuthPage from "./AuthPage";
21-
import * as Matrix from "matrix-js-sdk";
2221
import {_td} from "../../../languageHandler";
23-
import PlatformPeg from "../../../PlatformPeg";
2422

2523
// translatable strings for Welcome pages
2624
_td("Sign in with SSO");
@@ -39,24 +37,15 @@ export default class Welcome extends React.PureComponent {
3937
pageUrl = 'welcome.html';
4038
}
4139

42-
const {hsUrl, isUrl} = this.props.serverConfig;
43-
const tmpClient = Matrix.createClient({
44-
baseUrl: hsUrl,
45-
idBaseUrl: isUrl,
46-
});
47-
const plaf = PlatformPeg.get();
48-
const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl(),
49-
this.props.fragmentAfterLogin);
50-
5140
return (
5241
<AuthPage>
5342
<div className="mx_Welcome">
5443
<EmbeddedPage
5544
className="mx_WelcomePage"
5645
url={pageUrl}
5746
replaceMap={{
58-
"$riot:ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"),
59-
"$riot:casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"),
47+
"$riot:ssoUrl": "#/start_sso",
48+
"$riot:casUrl": "#/start_cas",
6049
}}
6150
/>
6251
<LanguageSelector />
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright 2020 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from "react";
18+
import classNames from "classnames";
19+
20+
import StyledRadioButton from "./StyledRadioButton";
21+
22+
interface IDefinition<T extends string> {
23+
value: T;
24+
className?: string;
25+
disabled?: boolean;
26+
label: React.ReactChild;
27+
description?: React.ReactChild;
28+
}
29+
30+
interface IProps<T extends string> {
31+
name: string;
32+
className?: string;
33+
definitions: IDefinition<T>[];
34+
value?: T; // if not provided no options will be selected
35+
onChange(newValue: T);
36+
}
37+
38+
function StyledRadioGroup<T extends string>({name, definitions, value, className, onChange}: IProps<T>) {
39+
const _onChange = e => {
40+
onChange(e.target.value);
41+
};
42+
43+
return <React.Fragment>
44+
{definitions.map(d => <React.Fragment>
45+
<StyledRadioButton
46+
key={d.value}
47+
className={classNames(className, d.className)}
48+
onChange={_onChange}
49+
checked={d.value === value}
50+
name={name}
51+
value={d.value}
52+
disabled={d.disabled}
53+
>
54+
{d.label}
55+
</StyledRadioButton>
56+
{d.description}
57+
</React.Fragment>)}
58+
</React.Fragment>;
59+
}
60+
61+
export default StyledRadioGroup;

src/components/views/rooms/NotificationBadge.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ export default class NotificationBadge extends React.PureComponent<IProps, IStat
141141
}
142142
}
143143

144+
export class StaticNotificationState extends EventEmitter implements INotificationState {
145+
constructor(public symbol: string, public count: number, public color: NotificationColor) {
146+
super();
147+
}
148+
149+
public static forCount(count: number, color: NotificationColor): StaticNotificationState {
150+
return new StaticNotificationState(null, count, color);
151+
}
152+
153+
public static forSymbol(symbol: string, color: NotificationColor): StaticNotificationState {
154+
return new StaticNotificationState(symbol, 0, color);
155+
}
156+
}
157+
144158
export class RoomNotificationState extends EventEmitter implements IDestroyable, INotificationState {
145159
private _symbol: string;
146160
private _count: number;

src/components/views/rooms/RoomSublist2.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { TagID } from "../../../stores/room-list/models";
4343
*******************************************************************/
4444

4545
const SHOW_N_BUTTON_HEIGHT = 32; // As defined by CSS
46-
const RESIZE_HANDLE_HEIGHT = 3; // As defined by CSS
46+
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
4747

4848
const MAX_PADDING_HEIGHT = SHOW_N_BUTTON_HEIGHT + RESIZE_HANDLE_HEIGHT;
4949

@@ -70,6 +70,7 @@ interface IProps {
7070
interface IState {
7171
notificationState: ListNotificationState;
7272
menuDisplayed: boolean;
73+
isResizing: boolean;
7374
}
7475

7576
export default class RoomSublist2 extends React.Component<IProps, IState> {
@@ -82,6 +83,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
8283
this.state = {
8384
notificationState: new ListNotificationState(this.props.isInvite, this.props.tagId),
8485
menuDisplayed: false,
86+
isResizing: false,
8587
};
8688
this.state.notificationState.setRooms(this.props.rooms);
8789
}
@@ -111,6 +113,14 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
111113
this.forceUpdate(); // because the layout doesn't trigger a re-render
112114
};
113115

116+
private onResizeStart = () => {
117+
this.setState({isResizing: true});
118+
};
119+
120+
private onResizeStop = () => {
121+
this.setState({isResizing: false});
122+
};
123+
114124
private onShowAllClick = () => {
115125
this.props.layout.visibleTiles = this.props.layout.tilesWithPadding(this.numTiles, MAX_PADDING_HEIGHT);
116126
this.forceUpdate(); // because the layout doesn't trigger a re-render
@@ -359,7 +369,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
359369
const maxTilesFactored = layout.tilesWithResizerBoxFactor(tiles.length);
360370
const showMoreBtnClasses = classNames({
361371
'mx_RoomSublist2_showNButton': true,
362-
'mx_RoomSublist2_isCutting': layout.visibleTiles < maxTilesFactored,
372+
'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored,
363373
});
364374

365375
// If we're hiding rooms, show a 'show more' button to the user. This button
@@ -438,6 +448,8 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
438448
resizeHandles={handles}
439449
onResize={this.onResize}
440450
className="mx_RoomSublist2_resizeBox"
451+
onResizeStart={this.onResizeStart}
452+
onResizeStop={this.onResizeStop}
441453
>
442454
{visibleTiles}
443455
{showNButton}

src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import StyledCheckbox from '../../../elements/StyledCheckbox';
3333
import SettingsFlag from '../../../elements/SettingsFlag';
3434
import Field from '../../../elements/Field';
3535
import EventTilePreview from '../../../elements/EventTilePreview';
36+
import StyledRadioGroup from "../../../elements/StyledRadioGroup";
3637

3738
interface IProps {
3839
}
@@ -116,8 +117,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
116117
};
117118
}
118119

119-
private onThemeChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
120-
const newTheme = e.target.value;
120+
private onThemeChange = (newTheme: string): void => {
121121
if (this.state.theme === newTheme) return;
122122

123123
// doing getValue in the .catch will still return the value we failed to set,
@@ -277,19 +277,18 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
277277
<div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_themeSection">
278278
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
279279
{systemThemeSection}
280-
<div className="mx_ThemeSelectors" onChange={this.onThemeChange}>
281-
{orderedThemes.map(theme => {
282-
return <StyledRadioButton
283-
key={theme.id}
284-
value={theme.id}
285-
name="theme"
286-
disabled={this.state.useSystemTheme}
287-
checked={!this.state.useSystemTheme && theme.id === this.state.theme}
288-
className={"mx_ThemeSelector_" + theme.id}
289-
>
290-
{theme.name}
291-
</StyledRadioButton>;
292-
})}
280+
<div className="mx_ThemeSelectors">
281+
<StyledRadioGroup
282+
name="theme"
283+
definitions={orderedThemes.map(t => ({
284+
value: t.id,
285+
label: t.name,
286+
disabled: this.state.useSystemTheme,
287+
className: "mx_ThemeSelector_" + t.id,
288+
}))}
289+
onChange={this.onThemeChange}
290+
value={this.state.useSystemTheme ? undefined : this.state.theme}
291+
/>
293292
</div>
294293
{customThemeForm}
295294
<SettingsFlag name="useCompactLayout" level={SettingLevel.ACCOUNT} useCheckbox={true} />

0 commit comments

Comments
 (0)