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

Commit d38a1fa

Browse files
author
Kerry
authored
fallback to event text in location body when map unavailable (#7982)
* center icon better Signed-off-by: Kerry Archibald <[email protected]> * remove debug Signed-off-by: Kerry Archibald <[email protected]> * retrigger all builds Signed-off-by: Kerry Archibald <[email protected]> * set assetType on share event Signed-off-by: Kerry Archibald <[email protected]> * use pin marker on map for pin drop share Signed-off-by: Kerry Archibald <[email protected]> * lint Signed-off-by: Kerry Archibald <[email protected]> * test events Signed-off-by: Kerry Archibald <[email protected]> * pin drop helper text Signed-off-by: Kerry Archibald <[email protected]> * use generic location type Signed-off-by: Kerry Archibald <[email protected]> * add navigationcontrol when in pin mode Signed-off-by: Kerry Archibald <[email protected]> * allow pin drop without location permissions Signed-off-by: Kerry Archibald <[email protected]> * remove geolocate control when pin dropping without geo perms Signed-off-by: Kerry Archibald <[email protected]> * test locationpicker Signed-off-by: Kerry Archibald <[email protected]> * test marker type, tidy Signed-off-by: Kerry Archibald <[email protected]> * move findMapStyleUrl Signed-off-by: Kerry Archibald <[email protected]> * fallback to event content when cant render map Signed-off-by: Kerry Archibald <[email protected]> * update mocks in location picker, show same messages as timeline Signed-off-by: Kerry Archibald <[email protected]> * style error message in location share menu Signed-off-by: Kerry Archibald <[email protected]> * i18n Signed-off-by: Kerry Archibald <[email protected]> * forgotten copyright Signed-off-by: Kerry Archibald <[email protected]> * add copyright Signed-off-by: Kerry Archibald <[email protected]> * update style Signed-off-by: Kerry Archibald <[email protected]> * icon bigger Signed-off-by: Kerry Archibald <[email protected]>
1 parent 9082e07 commit d38a1fa

File tree

15 files changed

+485
-68
lines changed

15 files changed

+485
-68
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@import "./_font-weights.scss";
66
@import "./_spacing.scss";
77
@import "./components/views/location/_LocationShareMenu.scss";
8+
@import "./components/views/location/_MapError.scss";
89
@import "./components/views/location/_ShareDialogButtons.scss";
910
@import "./components/views/location/_ShareType.scss";
1011
@import "./components/views/spaces/_QuickThemeSwitcher.scss";
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright 2022 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+
.mx_MapError {
18+
padding: 100px $spacing-32 0;
19+
text-align: center;
20+
21+
p {
22+
margin: $spacing-16 0 $spacing-32;
23+
}
24+
}
25+
26+
.mx_MapError_heading {
27+
padding-top: $spacing-24;
28+
}
29+
30+
.mx_MapError_icon {
31+
height: 58px;
32+
33+
path {
34+
fill: $secondary-content;
35+
}
36+
}

res/css/views/location/_LocationPicker.scss

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ limitations under the License.
2121
position: relative;
2222
overflow: hidden;
2323

24+
// when there are errors loading the map
25+
// the canvas is still inserted
26+
// and can overlap error message/close buttons
27+
// hide it
28+
&.mx_LocationPicker_hasError {
29+
.maplibregl-canvas-container, .maplibregl-control-container {
30+
display: none;
31+
}
32+
}
33+
2434
#mx_LocationPicker_map {
2535
height: 100%;
2636
border-radius: 8px;
@@ -94,11 +104,6 @@ limitations under the License.
94104

95105
background-color: $header-panel-bg-color;
96106
}
97-
98-
.mx_LocationPicker_error {
99-
color: red;
100-
margin: auto;
101-
}
102107
}
103108

104109
.mx_MLocationBody_markerIcon {

src/components/views/location/LocationPicker.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ import MemberAvatar from '../avatars/MemberAvatar';
2626
import MatrixClientContext from '../../../contexts/MatrixClientContext';
2727
import Modal from '../../../Modal';
2828
import ErrorDialog from '../dialogs/ErrorDialog';
29-
import { findMapStyleUrl } from '../messages/MLocationBody';
3029
import { tileServerFromWellKnown } from '../../../utils/WellKnownUtils';
30+
import { findMapStyleUrl } from './findMapStyleUrl';
3131
import { LocationShareType } from './shareLocation';
3232
import { Icon as LocationIcon } from '../../../../res/img/element-icons/location.svg';
33+
import { LocationShareError } from './LocationShareErrors';
3334
import AccessibleButton from '../elements/AccessibleButton';
34-
35+
import { MapError } from './MapError';
3536
export interface ILocationPickerProps {
3637
sender: RoomMember;
3738
shareType: LocationShareType;
@@ -48,7 +49,7 @@ interface IPosition {
4849
}
4950
interface IState {
5051
position?: IPosition;
51-
error: Error;
52+
error?: LocationShareError;
5253
}
5354

5455
/*
@@ -104,10 +105,10 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
104105
this.map.on('error', (e) => {
105106
logger.error(
106107
"Failed to load map: check map_style_url in config.json "
107-
+ "has a valid URL and API key",
108+
+ "has a valid URL and API key",
108109
e.error,
109110
);
110-
this.setState({ error: e.error });
111+
this.setState({ error: LocationShareError.MapStyleUrlNotReachable });
111112
});
112113

113114
this.map.on('load', () => {
@@ -129,7 +130,10 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
129130
}
130131
} catch (e) {
131132
logger.error("Failed to render map", e);
132-
this.setState({ error: e });
133+
const errorType = e?.message === LocationShareError.MapStyleUrlNotConfigured ?
134+
LocationShareError.MapStyleUrlNotConfigured :
135+
LocationShareError.Default;
136+
this.setState({ error: errorType });
133137
}
134138
}
135139

@@ -213,10 +217,13 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
213217
};
214218

215219
render() {
216-
const error = this.state.error ?
217-
<div data-test-id='location-picker-error' className="mx_LocationPicker_error">
218-
{ _t("Failed to load map") }
219-
</div> : null;
220+
if (this.state.error) {
221+
return <div className="mx_LocationPicker mx_LocationPicker_hasError">
222+
<MapError
223+
error={this.state.error}
224+
onFinished={this.props.onFinished} />
225+
</div>;
226+
}
220227

221228
return (
222229
<div className="mx_LocationPicker">
@@ -227,7 +234,6 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
227234
</span>
228235
</div>
229236
}
230-
{ error }
231237
<div className="mx_LocationPicker_footer">
232238
<form onSubmit={this.onOk}>
233239

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright 2022 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 { _t } from "../../../languageHandler";
18+
19+
export enum LocationShareError {
20+
MapStyleUrlNotConfigured = 'MapStyleUrlNotConfigured',
21+
MapStyleUrlNotReachable = 'MapStyleUrlNotReachable',
22+
Default = 'Default'
23+
}
24+
25+
export const getLocationShareErrorMessage = (errorType?: LocationShareError): string => {
26+
switch (errorType) {
27+
case LocationShareError.MapStyleUrlNotConfigured:
28+
return _t('This homeserver is not configured to display maps.');
29+
case LocationShareError.MapStyleUrlNotReachable:
30+
default:
31+
return _t(`This homeserver is not configured correctly to display maps, `
32+
+ `or the configured map server may be unreachable.`);
33+
}
34+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright 2022 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+
19+
import { Icon as WarningBadge } from '../../../../res/img/element-icons/warning-badge.svg';
20+
import { _t } from '../../../languageHandler';
21+
import AccessibleButton from '../elements/AccessibleButton';
22+
import Heading from '../typography/Heading';
23+
import { getLocationShareErrorMessage, LocationShareError } from './LocationShareErrors';
24+
25+
interface Props {
26+
onFinished: () => void;
27+
error: LocationShareError;
28+
}
29+
30+
export const MapError: React.FC<Props> = ({
31+
onFinished, error,
32+
}) => (<div data-test-id='location-picker-error' className="mx_MapError">
33+
<WarningBadge className="mx_MapError_icon" />
34+
<Heading className="mx_MapError_heading" size='h3'>{ _t("Unable to load map") }</Heading>
35+
<p>
36+
{ getLocationShareErrorMessage(error) }
37+
</p>
38+
<AccessibleButton element='button' kind="primary" onClick={onFinished}>{ _t("OK") }</AccessibleButton>
39+
</div>);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2022 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 { logger } from "matrix-js-sdk/src/logger";
18+
19+
import SdkConfig from "../../../SdkConfig";
20+
import { getTileServerWellKnown } from "../../../utils/WellKnownUtils";
21+
import { LocationShareError } from "./LocationShareErrors";
22+
23+
/**
24+
* Look up what map tile server style URL was provided in the homeserver's
25+
* .well-known location, or, failing that, in our local config, or, failing
26+
* that, defaults to the same tile server listed by matrix.org.
27+
*/
28+
export function findMapStyleUrl(): string {
29+
const mapStyleUrl = (
30+
getTileServerWellKnown()?.map_style_url ??
31+
SdkConfig.get().map_style_url
32+
);
33+
34+
if (!mapStyleUrl) {
35+
logger.error("'map_style_url' missing from homeserver .well-known area, and " +
36+
"missing from from config.json.");
37+
throw new Error(LocationShareError.MapStyleUrlNotConfigured);
38+
}
39+
40+
return mapStyleUrl;
41+
}

src/components/views/messages/MLocationBody.tsx

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
} from 'matrix-js-sdk/src/@types/location';
2727
import { ClientEvent, IClientWellKnown } from 'matrix-js-sdk/src/client';
2828

29-
import SdkConfig from '../../../SdkConfig';
3029
import { replaceableComponent } from "../../../utils/replaceableComponent";
3130
import { IBodyProps } from "./IBodyProps";
3231
import { _t } from '../../../languageHandler';
@@ -36,8 +35,10 @@ import LocationViewDialog from '../location/LocationViewDialog';
3635
import TooltipTarget from '../elements/TooltipTarget';
3736
import { Alignment } from '../elements/Tooltip';
3837
import AccessibleButton from '../elements/AccessibleButton';
39-
import { getTileServerWellKnown, tileServerFromWellKnown } from '../../../utils/WellKnownUtils';
38+
import { tileServerFromWellKnown } from '../../../utils/WellKnownUtils';
4039
import MatrixClientContext from '../../../contexts/MatrixClientContext';
40+
import { findMapStyleUrl } from '../location/findMapStyleUrl';
41+
import { getLocationShareErrorMessage, LocationShareError } from '../location/LocationShareErrors';
4142

4243
interface IState {
4344
error: Error;
@@ -117,14 +118,16 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
117118
};
118119

119120
render(): React.ReactElement<HTMLDivElement> {
120-
return <LocationBodyContent
121-
mxEvent={this.props.mxEvent}
122-
bodyId={this.bodyId}
123-
markerId={this.markerId}
124-
error={this.state.error}
125-
tooltip={_t("Expand map")}
126-
onClick={this.onClick}
127-
/>;
121+
return this.state.error ?
122+
<LocationBodyFallbackContent error={this.state.error} event={this.props.mxEvent} /> :
123+
<LocationBodyContent
124+
mxEvent={this.props.mxEvent}
125+
bodyId={this.bodyId}
126+
markerId={this.markerId}
127+
error={this.state.error}
128+
tooltip={_t("Expand map")}
129+
onClick={this.onClick}
130+
/>;
128131
}
129132
}
130133

@@ -146,6 +149,23 @@ interface ILocationBodyContentProps {
146149
onZoomOut?: () => void;
147150
}
148151

152+
export const LocationBodyFallbackContent: React.FC<{ event: MatrixEvent, error: Error }> = ({ error, event }) => {
153+
const errorType = error?.message as LocationShareError;
154+
const message = `${_t('Unable to load map')}: ${getLocationShareErrorMessage(errorType)}`;
155+
156+
const locationFallback = isSelfLocation(event.getContent()) ?
157+
(_t('Shared their location: ') + event.getContent()?.body) :
158+
(_t('Shared a location: ') + event.getContent()?.body);
159+
160+
return <div className="mx_EventTile_body">
161+
<span className={errorType !== LocationShareError.MapStyleUrlNotConfigured ? "mx_EventTile_tileError" : ''}>
162+
{ message }
163+
</span>
164+
<br />
165+
{ locationFallback }
166+
</div>;
167+
};
168+
149169
export function LocationBodyContent(props: ILocationBodyContentProps):
150170
React.ReactElement<HTMLDivElement> {
151171
const mapDiv = <div
@@ -166,13 +186,6 @@ export function LocationBodyContent(props: ILocationBodyContentProps):
166186
);
167187

168188
return <div className="mx_MLocationBody">
169-
{
170-
props.error
171-
? <div className="mx_EventTile_tileError mx_EventTile_body">
172-
{ _t("Failed to load map") }
173-
</div>
174-
: null
175-
}
176189
{
177190
props.tooltip
178191
? <TooltipTarget
@@ -225,27 +238,6 @@ function ZoomButtons(props: IZoomButtonsProps): React.ReactElement<HTMLDivElemen
225238
</div>;
226239
}
227240

228-
/**
229-
* Look up what map tile server style URL was provided in the homeserver's
230-
* .well-known location, or, failing that, in our local config, or, failing
231-
* that, defaults to the same tile server listed by matrix.org.
232-
*/
233-
export function findMapStyleUrl(): string {
234-
const mapStyleUrl = (
235-
getTileServerWellKnown()?.map_style_url ??
236-
SdkConfig.get().map_style_url
237-
);
238-
239-
if (!mapStyleUrl) {
240-
throw new Error(
241-
"'map_style_url' missing from homeserver .well-known area, and " +
242-
"missing from from config.json.",
243-
);
244-
}
245-
246-
return mapStyleUrl;
247-
}
248-
249241
export function createMap(
250242
coords: GeolocationCoordinates,
251243
interactive: boolean,
@@ -279,7 +271,7 @@ export function createMap(
279271
+ "valid URL and API key",
280272
e.error,
281273
);
282-
onError(e.error);
274+
onError(new Error(LocationShareError.MapStyleUrlNotReachable));
283275
});
284276

285277
return map;

0 commit comments

Comments
 (0)