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

Commit e84049c

Browse files
Kerry Archibaldsandhose
authored andcommitted
add spinners to session end buttons
1 parent b0fb328 commit e84049c

File tree

6 files changed

+78
-106
lines changed

6 files changed

+78
-106
lines changed

frontend/src/components/BrowserSession.tsx

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Button } from "@vector-im/compound-web";
1615
import { atom, useSetAtom } from "jotai";
1716
import { atomFamily } from "jotai/utils";
1817
import { atomWithMutation } from "jotai-urql";
19-
import { useTransition } from "react";
2018

2119
import { currentBrowserSessionIdAtom, currentUserIdAtom } from "../atoms";
2220
import { FragmentType, graphql, useFragment } from "../gql";
@@ -25,6 +23,7 @@ import {
2523
sessionNameFromDeviceInformation,
2624
} from "../utils/parseUserAgent";
2725

26+
import EndSessionButton from "./Session/EndSessionButton";
2827
import Session from "./Session/Session";
2928

3029
const FRAGMENT = graphql(/* GraphQL */ `
@@ -71,7 +70,6 @@ type Props = {
7170

7271
const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
7372
const data = useFragment(FRAGMENT, session);
74-
const [pending, startTransition] = useTransition();
7573
const endSession = useSetAtom(endSessionFamily(data.id));
7674

7775
// Pull those atoms to reset them when the current session is ended
@@ -80,19 +78,16 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
8078

8179
const createdAt = data.createdAt;
8280

83-
const onSessionEnd = (): void => {
84-
startTransition(() => {
85-
endSession().then(() => {
86-
if (isCurrent) {
87-
currentBrowserSessionId({
88-
requestPolicy: "network-only",
89-
});
90-
currentUserId({
91-
requestPolicy: "network-only",
92-
});
93-
}
81+
const onSessionEnd = async (): Promise<void> => {
82+
await endSession();
83+
if (isCurrent) {
84+
currentBrowserSessionId({
85+
requestPolicy: "network-only",
9486
});
95-
});
87+
currentUserId({
88+
requestPolicy: "network-only",
89+
});
90+
}
9691
};
9792

9893
const deviceInformation = parseUserAgent(data.userAgent || undefined);
@@ -107,16 +102,7 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
107102
finishedAt={data.finishedAt}
108103
isCurrent={isCurrent}
109104
>
110-
{!data.finishedAt && (
111-
<Button
112-
kind="destructive"
113-
size="sm"
114-
onClick={onSessionEnd}
115-
disabled={pending}
116-
>
117-
Sign out
118-
</Button>
119-
)}
105+
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
120106
</Session>
121107
);
122108
};

frontend/src/components/CompatSession.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Button } from "@vector-im/compound-web";
1615
import { atom, useSetAtom } from "jotai";
1716
import { atomFamily } from "jotai/utils";
1817
import { atomWithMutation } from "jotai-urql";
19-
import { useTransition } from "react";
2018

2119
import { FragmentType, graphql, useFragment } from "../gql";
2220
import { Link } from "../routing";
2321

2422
import { Session } from "./Session";
23+
import EndSessionButton from "./Session/EndSessionButton";
2524

2625
export const COMPAT_SESSION_FRAGMENT = graphql(/* GraphQL */ `
2726
fragment CompatSession_session on CompatSession {
@@ -84,14 +83,11 @@ export const simplifyUrl = (url: string): string => {
8483
const CompatSession: React.FC<{
8584
session: FragmentType<typeof COMPAT_SESSION_FRAGMENT>;
8685
}> = ({ session }) => {
87-
const [pending, startTransition] = useTransition();
8886
const data = useFragment(COMPAT_SESSION_FRAGMENT, session);
8987
const endCompatSession = useSetAtom(endCompatSessionFamily(data.id));
9088

91-
const onSessionEnd = (): void => {
92-
startTransition(() => {
93-
endCompatSession();
94-
});
89+
const onSessionEnd = async (): Promise<void> => {
90+
await endCompatSession();
9591
};
9692

9793
const sessionName = (
@@ -110,16 +106,7 @@ const CompatSession: React.FC<{
110106
finishedAt={data.finishedAt || undefined}
111107
clientName={clientName}
112108
>
113-
{!data.finishedAt && (
114-
<Button
115-
kind="destructive"
116-
size="sm"
117-
onClick={onSessionEnd}
118-
disabled={pending}
119-
>
120-
End session
121-
</Button>
122-
)}
109+
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
123110
</Session>
124111
);
125112
};

frontend/src/components/OAuth2Session.tsx

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Button } from "@vector-im/compound-web";
1615
import { atom, useSetAtom } from "jotai";
1716
import { atomFamily } from "jotai/utils";
1817
import { atomWithMutation } from "jotai-urql";
19-
import { useTransition } from "react";
2018

2119
import { FragmentType, graphql, useFragment } from "../gql";
2220
import { Link } from "../routing";
2321
import { getDeviceIdFromScope } from "../utils/deviceIdFromScope";
2422

25-
// import LoadingSpinner from "./LoadingSpinner/LoadingSpinner";
2623
import { Session } from "./Session";
24+
import EndSessionButton from "./Session/EndSessionButton";
2725

2826
export const OAUTH2_SESSION_FRAGMENT = graphql(/* GraphQL */ `
2927
fragment OAuth2Session_session on Oauth2Session {
@@ -82,19 +80,14 @@ type Props = {
8280
};
8381

8482
const OAuth2Session: React.FC<Props> = ({ session }) => {
85-
const [pending, startTransition] = useTransition();
8683
const data = useFragment(
8784
OAUTH2_SESSION_FRAGMENT,
8885
session,
8986
) as Oauth2SessionType;
9087
const endSession = useSetAtom(endSessionFamily(data.id));
9188

92-
// @TODO(kerrya) make this wait for session refresh properly
93-
// https://github.com/matrix-org/matrix-authentication-service/issues/1533
94-
const onSessionEnd = (): void => {
95-
startTransition(() => {
96-
endSession();
97-
});
89+
const onSessionEnd = async (): Promise<void> => {
90+
await endSession();
9891
};
9992

10093
const deviceId = getDeviceIdFromScope(data.scope);
@@ -111,18 +104,7 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
111104
finishedAt={data.finishedAt || undefined}
112105
clientName={data.client.clientName}
113106
>
114-
{!data.finishedAt && (
115-
<Button
116-
kind="destructive"
117-
size="sm"
118-
onClick={onSessionEnd}
119-
disabled={pending}
120-
>
121-
{/* @TODO(kerrya) put this back after pending state works properly */}
122-
{/* { pending && <LoadingSpinner />} */}
123-
End session
124-
</Button>
125-
)}
107+
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
126108
</Session>
127109
);
128110
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2023 The Matrix.org Foundation C.I.C.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { Button } from "@vector-im/compound-web";
16+
import { useState } from "react";
17+
18+
import LoadingSpinner from "../LoadingSpinner/LoadingSpinner";
19+
20+
/**
21+
* Generic end session button
22+
* Handles loading state while endSession is in progress
23+
*/
24+
const EndSessionButton: React.FC<{ endSession: () => Promise<void> }> = ({
25+
endSession,
26+
}) => {
27+
const [inProgress, setInProgress] = useState(false);
28+
const onClick = async (): Promise<void> => {
29+
setInProgress(true);
30+
try {
31+
await endSession();
32+
} catch (error) {
33+
console.error("Failed to end session", error);
34+
}
35+
setInProgress(false);
36+
};
37+
return (
38+
<Button
39+
kind="destructive"
40+
size="sm"
41+
onClick={onClick}
42+
disabled={inProgress}
43+
>
44+
{inProgress && <LoadingSpinner inline />}End session
45+
</Button>
46+
);
47+
};
48+
49+
export default EndSessionButton;

frontend/src/components/SessionDetail/CompatSessionDetail.tsx

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { H3, Button } from "@vector-im/compound-web";
15+
import { H3 } from "@vector-im/compound-web";
1616
import { useSetAtom } from "jotai";
17-
import { useTransition } from "react";
1817

1918
import { FragmentType, useFragment } from "../../gql";
2019
import BlockList from "../BlockList/BlockList";
@@ -24,6 +23,7 @@ import {
2423
simplifyUrl,
2524
} from "../CompatSession";
2625
import DateTime from "../DateTime";
26+
import EndSessionButton from "../Session/EndSessionButton";
2727

2828
import SessionDetails from "./SessionDetails";
2929

@@ -32,16 +32,11 @@ type Props = {
3232
};
3333

3434
const CompatSessionDetail: React.FC<Props> = ({ session }) => {
35-
const [pending, startTransition] = useTransition();
3635
const data = useFragment(COMPAT_SESSION_FRAGMENT, session);
3736
const endSession = useSetAtom(endCompatSessionFamily(data.id));
3837

39-
// @TODO(kerrya) make this wait for session refresh properly
40-
// https://github.com/matrix-org/matrix-authentication-service/issues/1533
41-
const onSessionEnd = (): void => {
42-
startTransition(() => {
43-
endSession();
44-
});
38+
const onSessionEnd = async (): Promise<void> => {
39+
await endSession();
4540
};
4641

4742
const finishedAt = data.finishedAt
@@ -79,18 +74,7 @@ const CompatSessionDetail: React.FC<Props> = ({ session }) => {
7974
{clientDetails.length > 0 ? (
8075
<SessionDetails title="Client" details={clientDetails} />
8176
) : null}
82-
{!data.finishedAt && (
83-
<Button
84-
kind="destructive"
85-
size="sm"
86-
onClick={onSessionEnd}
87-
disabled={pending}
88-
>
89-
{/* @TODO(kerrya) put this back after pending state works properly */}
90-
{/* { pending && <LoadingSpinner />} */}
91-
End session
92-
</Button>
93-
)}
77+
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
9478
</BlockList>
9579
</div>
9680
);

frontend/src/components/SessionDetail/OAuth2SessionDetail.tsx

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { H3, Button } from "@vector-im/compound-web";
15+
import { H3 } from "@vector-im/compound-web";
1616
import { useSetAtom } from "jotai";
17-
import { useTransition } from "react";
1817

1918
import { FragmentType, useFragment } from "../../gql";
2019
import { getDeviceIdFromScope } from "../../utils/deviceIdFromScope";
@@ -25,6 +24,7 @@ import {
2524
Oauth2SessionType,
2625
endSessionFamily,
2726
} from "../OAuth2Session";
27+
import EndSessionButton from "../Session/EndSessionButton";
2828

2929
import SessionDetails from "./SessionDetails";
3030

@@ -33,19 +33,14 @@ type Props = {
3333
};
3434

3535
const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
36-
const [pending, startTransition] = useTransition();
3736
const data = useFragment(
3837
OAUTH2_SESSION_FRAGMENT,
3938
session,
4039
) as Oauth2SessionType;
4140
const endSession = useSetAtom(endSessionFamily(data.id));
4241

43-
// @TODO(kerrya) make this wait for session refresh properly
44-
// https://github.com/matrix-org/matrix-authentication-service/issues/1533
45-
const onSessionEnd = (): void => {
46-
startTransition(() => {
47-
endSession();
48-
});
42+
const onSessionEnd = async (): Promise<void> => {
43+
await endSession();
4944
};
5045

5146
const deviceId = getDeviceIdFromScope(data.scope);
@@ -93,18 +88,7 @@ const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
9388
<H3>{deviceId || data.id}</H3>
9489
<SessionDetails title="Session" details={sessionDetails} />
9590
<SessionDetails title="Client" details={clientDetails} />
96-
{!data.finishedAt && (
97-
<Button
98-
kind="destructive"
99-
size="sm"
100-
onClick={onSessionEnd}
101-
disabled={pending}
102-
>
103-
{/* @TODO(kerrya) put this back after pending state works properly */}
104-
{/* { pending && <LoadingSpinner />} */}
105-
End session
106-
</Button>
107-
)}
91+
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
10892
</BlockList>
10993
</div>
11094
);

0 commit comments

Comments
 (0)