You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-23 11:02:35 +03:00
add client logo to session tile and detail
This commit is contained in:
committed by
Quentin Gliech
parent
0bee1284b2
commit
0d726cd7cb
@@ -34,6 +34,7 @@ export const OAUTH2_SESSION_FRAGMENT = graphql(/* GraphQL */ `
|
||||
clientId
|
||||
clientName
|
||||
clientUri
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`);
|
||||
@@ -48,6 +49,7 @@ export type Oauth2SessionType = {
|
||||
clientId: string;
|
||||
clientName: string;
|
||||
clientUri: string;
|
||||
logoUri: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,6 +105,7 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
|
||||
createdAt={data.createdAt}
|
||||
finishedAt={data.finishedAt || undefined}
|
||||
clientName={data.client.clientName}
|
||||
clientLogoUri={data.client.logoUri || undefined}
|
||||
>
|
||||
{!data.finishedAt && <EndSessionButton endSession={onSessionEnd} />}
|
||||
</Session>
|
||||
|
||||
23
frontend/src/components/Session/ClientAvatar.module.css
Normal file
23
frontend/src/components/Session/ClientAvatar.module.css
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.avatar {
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 1 / 1;
|
||||
width: var(--mas-avatar-size);
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
51
frontend/src/components/Session/ClientAvatar.tsx
Normal file
51
frontend/src/components/Session/ClientAvatar.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Avatar } from "@vector-im/compound-web";
|
||||
import { CSSProperties } from "react";
|
||||
|
||||
import styles from "./ClientAvatar.module.css";
|
||||
|
||||
const ClientAvatar: React.FC<{
|
||||
name: string;
|
||||
logoUri?: string;
|
||||
/**
|
||||
* Render a fallback avatar using client name when truthy
|
||||
* Otherwise return null when no logoUri
|
||||
*/
|
||||
withFallback?: boolean;
|
||||
size: string;
|
||||
}> = ({ name, logoUri, withFallback, size }) => {
|
||||
// compound's lazy loading for avatars does not allow CORS requests
|
||||
if (logoUri) {
|
||||
return (
|
||||
<img
|
||||
className={styles.avatar}
|
||||
src={logoUri}
|
||||
alt={name}
|
||||
style={
|
||||
{
|
||||
"--mas-avatar-size": size,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (withFallback) {
|
||||
return <Avatar size={size} id={name} name={name} src={logoUri} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ClientAvatar;
|
||||
@@ -21,6 +21,10 @@
|
||||
}
|
||||
|
||||
.session-metadata {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--cpd-space-1x);
|
||||
color: var(--cpd-color-text-secondary);
|
||||
|
||||
&[data-finished] {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ReactNode } from "react";
|
||||
import Block from "../Block";
|
||||
import DateTime from "../DateTime";
|
||||
|
||||
import ClientAvatar from "./ClientAvatar";
|
||||
import styles from "./Session.module.css";
|
||||
|
||||
const SessionMetadata: React.FC<React.ComponentProps<typeof Body>> = (
|
||||
@@ -30,6 +31,7 @@ export type SessionProps = {
|
||||
createdAt: string;
|
||||
finishedAt?: string;
|
||||
clientName?: string;
|
||||
clientLogoUri?: string;
|
||||
isCurrent?: boolean;
|
||||
};
|
||||
const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
||||
@@ -38,6 +40,7 @@ const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
||||
createdAt,
|
||||
finishedAt,
|
||||
clientName,
|
||||
clientLogoUri,
|
||||
isCurrent,
|
||||
children,
|
||||
}) => {
|
||||
@@ -56,7 +59,6 @@ const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
||||
<H6 className={styles.sessionName} title={id}>
|
||||
{name || id}
|
||||
</H6>
|
||||
|
||||
<SessionMetadata weight="semibold">
|
||||
Signed in <DateTime datetime={createdAt} />
|
||||
</SessionMetadata>
|
||||
@@ -67,7 +69,11 @@ const Session: React.FC<React.PropsWithChildren<SessionProps>> = ({
|
||||
)}
|
||||
{!!clientName && (
|
||||
<SessionMetadata>
|
||||
Client:{" "}
|
||||
<ClientAvatar
|
||||
size="var(--cpd-space-4x)"
|
||||
name={clientName}
|
||||
logoUri={clientLogoUri}
|
||||
/>{" "}
|
||||
<SessionMetadata weight="semibold" as="span">
|
||||
{clientName}
|
||||
</SessionMetadata>
|
||||
|
||||
@@ -81,7 +81,6 @@ exports[`<Session /> > uses client name when truthy 1`] = `
|
||||
<p
|
||||
className="_font-body-sm-regular_1g2sj_45 _sessionMetadata_634806"
|
||||
>
|
||||
Client:
|
||||
|
||||
<span
|
||||
className="_font-body-sm-semibold_1g2sj_49 _sessionMetadata_634806"
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
Oauth2SessionType,
|
||||
endSessionFamily,
|
||||
} from "../OAuth2Session";
|
||||
import ClientAvatar from "../Session/ClientAvatar";
|
||||
import EndSessionButton from "../Session/EndSessionButton";
|
||||
|
||||
import SessionDetails from "./SessionDetails";
|
||||
@@ -70,7 +71,19 @@ const OAuth2SessionDetail: React.FC<Props> = ({ session }) => {
|
||||
];
|
||||
|
||||
const clientDetails = [
|
||||
{ label: "Name", value: data.client.clientName },
|
||||
{
|
||||
label: "Name",
|
||||
value: (
|
||||
<>
|
||||
<ClientAvatar
|
||||
name={data.client.clientName}
|
||||
logoUri={data.client.logoUri || undefined}
|
||||
size="var(--cpd-space-4x)"
|
||||
/>
|
||||
{data.client.clientName}
|
||||
</>
|
||||
),
|
||||
},
|
||||
{ label: "ID", value: <code>{data.client.clientId}</code> },
|
||||
{
|
||||
label: "Uri",
|
||||
|
||||
@@ -33,4 +33,8 @@
|
||||
|
||||
.detail-value {
|
||||
overflow-wrap: anywhere;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--cpd-space-1x);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ exports[`<CompatSession /> > renders a finished session 1`] = `
|
||||
<p
|
||||
className="_font-body-sm-regular_1g2sj_45 _sessionMetadata_634806"
|
||||
>
|
||||
Client:
|
||||
|
||||
<span
|
||||
className="_font-body-sm-semibold_1g2sj_49 _sessionMetadata_634806"
|
||||
@@ -74,7 +73,6 @@ exports[`<CompatSession /> > renders an active session 1`] = `
|
||||
<p
|
||||
className="_font-body-sm-regular_1g2sj_45 _sessionMetadata_634806"
|
||||
>
|
||||
Client:
|
||||
|
||||
<span
|
||||
className="_font-body-sm-semibold_1g2sj_49 _sessionMetadata_634806"
|
||||
|
||||
@@ -36,7 +36,6 @@ exports[`<OAuth2Session /> > renders a finished session 1`] = `
|
||||
<p
|
||||
className="_font-body-sm-regular_1g2sj_45 _sessionMetadata_634806"
|
||||
>
|
||||
Client:
|
||||
|
||||
<span
|
||||
className="_font-body-sm-semibold_1g2sj_49 _sessionMetadata_634806"
|
||||
@@ -74,7 +73,6 @@ exports[`<OAuth2Session /> > renders an active session 1`] = `
|
||||
<p
|
||||
className="_font-body-sm-regular_1g2sj_45 _sessionMetadata_634806"
|
||||
>
|
||||
Client:
|
||||
|
||||
<span
|
||||
className="_font-body-sm-semibold_1g2sj_49 _sessionMetadata_634806"
|
||||
|
||||
@@ -29,7 +29,7 @@ const documents = {
|
||||
types.EndCompatSessionDocument,
|
||||
"\n query CompatSessionList(\n $userId: ID!\n $state: CompatSessionState\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n state: $state\n ) {\n edges {\n node {\n id\n ...CompatSession_session\n }\n }\n\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n":
|
||||
types.CompatSessionListDocument,
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n":
|
||||
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n":
|
||||
types.OAuth2Session_SessionFragmentDoc,
|
||||
"\n mutation EndOAuth2Session($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n":
|
||||
types.EndOAuth2SessionDocument,
|
||||
@@ -65,7 +65,7 @@ const documents = {
|
||||
types.ResendVerificationEmailDocument,
|
||||
"\n query BrowserSessionQuery($id: ID!) {\n browserSession(id: $id) {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n }\n":
|
||||
types.BrowserSessionQueryDocument,
|
||||
"\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n":
|
||||
"\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n logoUri\n }\n }\n":
|
||||
types.OAuth2ClientQueryDocument,
|
||||
"\n query SessionsOverviewQuery {\n viewer {\n __typename\n\n ... on User {\n id\n ...UserSessionsOverview_user\n }\n }\n }\n":
|
||||
types.SessionsOverviewQueryDocument,
|
||||
@@ -139,8 +139,8 @@ export function graphql(
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n",
|
||||
): (typeof documents)["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n"];
|
||||
source: "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n",
|
||||
): (typeof documents)["\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -247,8 +247,8 @@ export function graphql(
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: "\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n",
|
||||
): (typeof documents)["\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n }\n }\n"];
|
||||
source: "\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n logoUri\n }\n }\n",
|
||||
): (typeof documents)["\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n id\n clientId\n clientName\n clientUri\n tosUri\n policyUri\n redirectUris\n logoUri\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -1161,6 +1161,7 @@ export type OAuth2Session_SessionFragment = {
|
||||
clientId: string;
|
||||
clientName?: string | null;
|
||||
clientUri?: any | null;
|
||||
logoUri?: any | null;
|
||||
};
|
||||
} & { " $fragmentName"?: "OAuth2Session_SessionFragment" };
|
||||
|
||||
@@ -1505,6 +1506,7 @@ export type OAuth2ClientQueryQuery = {
|
||||
tosUri?: any | null;
|
||||
policyUri?: any | null;
|
||||
redirectUris: Array<any>;
|
||||
logoUri?: any | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
@@ -1631,6 +1633,7 @@ export const OAuth2Session_SessionFragmentDoc = {
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -2688,6 +2691,7 @@ export const EndOAuth2SessionDocument = {
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -2922,6 +2926,7 @@ export const OAuth2SessionListQueryDocument = {
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -3061,6 +3066,7 @@ export const SessionQueryDocument = {
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientId" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientName" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "clientUri" } },
|
||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -4170,6 +4176,7 @@ export const OAuth2ClientQueryDocument = {
|
||||
kind: "Field",
|
||||
name: { kind: "Name", value: "redirectUris" },
|
||||
},
|
||||
{ kind: "Field", name: { kind: "Name", value: "logoUri" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -32,6 +32,7 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
tosUri
|
||||
policyUri
|
||||
redirectUris
|
||||
logoUri
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
Reference in New Issue
Block a user