1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

OAuth and browser session lists

This commit is contained in:
Quentin Gliech
2022-11-15 12:36:44 +01:00
parent 2064c11d9b
commit f195cd3567
14 changed files with 1529 additions and 86 deletions

View File

@ -127,10 +127,10 @@ impl User {
|after, before, first, last| async move {
let mut conn = database.acquire().await?;
let after_id = after
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::UserEmail))
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::BrowserSession))
.transpose()?;
let before_id = before
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::UserEmail))
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::BrowserSession))
.transpose()?;
let (has_previous_page, has_next_page, edges) =

View File

@ -0,0 +1,54 @@
// Copyright 2022 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 type { BrowserSession_session$key } from "./__generated__/BrowserSession_session.graphql";
import { graphql, useFragment } from "react-relay";
type Props = {
session: BrowserSession_session$key;
isCurrent: boolean;
};
const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
const data = useFragment(
graphql`
fragment BrowserSession_session on BrowserSession {
id
createdAt
lastAuthentication {
id
createdAt
}
}
`,
session
);
return (
<div className="p-2 my-1 bg-grey-50 dark:bg-grey-450 rounded">
{isCurrent && <div className="font-bold">Current session</div>}
<div>
Started: <span className="font-mono text-sm">{data.createdAt}</span>
</div>
<div>
Last authentication:{" "}
<span className="font-semibold">
{data.lastAuthentication?.createdAt || "never"}
</span>
</div>
</div>
);
};
export default BrowserSession;

View File

@ -0,0 +1,64 @@
// Copyright 2022 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 { graphql, usePaginationFragment } from "react-relay";
import BrowserSession from "./BrowserSession";
import { BrowserSessionList_user$key } from "./__generated__/BrowserSessionList_user.graphql";
type Props = {
user: BrowserSessionList_user$key;
currentSessionId: string;
};
const BrowserSessionList: React.FC<Props> = ({ user, currentSessionId }) => {
const { data, loadNext, hasNext } = usePaginationFragment(
graphql`
fragment BrowserSessionList_user on User
@refetchable(queryName: "BrowserSessionListQuery") {
browserSessions(first: $count, after: $cursor)
@connection(key: "BrowserSessionList_user_browserSessions") {
edges {
cursor
node {
id
...BrowserSession_session
}
}
}
}
`,
user
);
return (
<div>
<h2 className="text-lg">List of browser sessions:</h2>
{data.browserSessions.edges.map((n) => (
<BrowserSession
key={n.cursor}
session={n.node}
isCurrent={n.node.id === currentSessionId}
/>
))}
{hasNext ? (
<button className="bg-accent p-2 rounded" onClick={() => loadNext(2)}>
Load more
</button>
) : null}
</div>
);
};
export default BrowserSessionList;

View File

@ -40,7 +40,7 @@ const CompatSsoLoginList: React.FC<Props> = ({ user }) => {
);
return (
<div className="w-96">
<div>
<h2 className="text-lg">List of compatibility sessions:</h2>
{data.compatSsoLogins.edges.map((n) => (
<CompatSsoLogin login={n.node} key={n.node.id} />

View File

@ -0,0 +1,58 @@
// Copyright 2022 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 type { OAuth2Session_session$key } from "./__generated__/OAuth2Session_session.graphql";
import { graphql, useFragment } from "react-relay";
type Props = {
session: OAuth2Session_session$key;
};
const OAuth2Session: React.FC<Props> = ({ session }) => {
const data = useFragment(
graphql`
fragment OAuth2Session_session on Oauth2Session {
id
scope
client {
id
clientId
clientName
clientUri
}
}
`,
session
);
return (
<div className="p-2 my-1 bg-grey-50 dark:bg-grey-450 rounded">
<div>
Client ID:{" "}
<span className="font-mono text-sm">{data.client.clientId}</span>
</div>
{data.client.clientName && (
<div>
Client name:{" "}
<span className="font-semibold">{data.client.clientName}</span>
</div>
)}
<div>
Scope: <span className="font-mono text-sm">{data.scope}</span>
</div>
</div>
);
};
export default OAuth2Session;

View File

@ -0,0 +1,59 @@
// Copyright 2022 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 { graphql, usePaginationFragment } from "react-relay";
import OAuth2Session from "./OAuth2Session";
import { OAuth2SessionList_user$key } from "./__generated__/OAuth2SessionList_user.graphql";
type Props = {
user: OAuth2SessionList_user$key;
};
const OAuth2SessionList: React.FC<Props> = ({ user }) => {
const { data, loadNext, hasNext } = usePaginationFragment(
graphql`
fragment OAuth2SessionList_user on User
@refetchable(queryName: "OAuth2SessionListQuery") {
oauth2Sessions(first: $count, after: $cursor)
@connection(key: "OAuth2SessionList_user_oauth2Sessions") {
edges {
cursor
node {
id
...OAuth2Session_session
}
}
}
}
`,
user
);
return (
<div>
<h2 className="text-lg">List of OAuth 2.0 sessions:</h2>
{data.oauth2Sessions.edges.map((n) => (
<OAuth2Session key={n.cursor} session={n.node} />
))}
{hasNext ? (
<button className="bg-accent p-2 rounded" onClick={() => loadNext(2)}>
Load more
</button>
) : null}
</div>
);
};
export default OAuth2SessionList;

View File

@ -0,0 +1,244 @@
/**
* @generated SignedSource<<2e2beb7aa6522ccc21b080d150de618a>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest, Query } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type BrowserSessionListQuery$variables = {
count?: number | null;
cursor?: string | null;
id: string;
};
export type BrowserSessionListQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"BrowserSessionList_user">;
} | null;
};
export type BrowserSessionListQuery = {
response: BrowserSessionListQuery$data;
variables: BrowserSessionListQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "count"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "cursor"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v4 = [
{
"kind": "Variable",
"name": "after",
"variableName": "cursor"
},
{
"kind": "Variable",
"name": "first",
"variableName": "count"
}
],
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "BrowserSessionListQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "BrowserSessionList_user"
}
],
"storageKey": null
}
],
"type": "RootQuery",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "BrowserSessionListQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "BrowserSessionConnection",
"kind": "LinkedField",
"name": "browserSessions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "BrowserSessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "BrowserSession",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Authentication",
"kind": "LinkedField",
"name": "lastAuthentication",
"plural": false,
"selections": [
(v3/*: any*/),
(v5/*: any*/)
],
"storageKey": null
},
(v2/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": null,
"handle": "connection",
"key": "BrowserSessionList_user_browserSessions",
"kind": "LinkedHandle",
"name": "browserSessions"
}
],
"type": "User",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "c05f614c382cae0bed080006b43f14f3",
"id": null,
"metadata": {},
"name": "BrowserSessionListQuery",
"operationKind": "query",
"text": "query BrowserSessionListQuery(\n $count: Int\n $cursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...BrowserSessionList_user\n id\n }\n}\n\nfragment BrowserSessionList_user on User {\n browserSessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n __typename\n }\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n}\n"
}
};
})();
(node as any).hash = "5f21c429aa98b854c17d3f9eb83b81d8";
export default node;

View File

@ -0,0 +1,170 @@
/**
* @generated SignedSource<<3b7505958556a142e2d9926ae631f0e0>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment, RefetchableFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type BrowserSessionList_user$data = {
readonly browserSessions: {
readonly edges: ReadonlyArray<{
readonly cursor: string;
readonly node: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"BrowserSession_session">;
};
}>;
};
readonly id: string;
readonly " $fragmentType": "BrowserSessionList_user";
};
export type BrowserSessionList_user$key = {
readonly " $data"?: BrowserSessionList_user$data;
readonly " $fragmentSpreads": FragmentRefs<"BrowserSessionList_user">;
};
import BrowserSessionListQuery_graphql from './BrowserSessionListQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"browserSessions"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"kind": "RootArgument",
"name": "count"
},
{
"kind": "RootArgument",
"name": "cursor"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": "count",
"cursor": "cursor",
"direction": "forward",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "count",
"cursor": "cursor"
},
"backward": null,
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": BrowserSessionListQuery_graphql,
"identifierField": "id"
}
},
"name": "BrowserSessionList_user",
"selections": [
{
"alias": "browserSessions",
"args": null,
"concreteType": "BrowserSessionConnection",
"kind": "LinkedField",
"name": "__BrowserSessionList_user_browserSessions_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "BrowserSessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "BrowserSession",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "BrowserSession_session"
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "User",
"abstractKey": null
};
})();
(node as any).hash = "5f21c429aa98b854c17d3f9eb83b81d8";
export default node;

View File

@ -0,0 +1,71 @@
/**
* @generated SignedSource<<f204c3033b21cfa962537b2dd72f4469>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { Fragment, ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type BrowserSession_session$data = {
readonly createdAt: any;
readonly id: string;
readonly lastAuthentication: {
readonly createdAt: any;
readonly id: string;
} | null;
readonly " $fragmentType": "BrowserSession_session";
};
export type BrowserSession_session$key = {
readonly " $data"?: BrowserSession_session$data;
readonly " $fragmentSpreads": FragmentRefs<"BrowserSession_session">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "BrowserSession_session",
"selections": [
(v0/*: any*/),
(v1/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Authentication",
"kind": "LinkedField",
"name": "lastAuthentication",
"plural": false,
"selections": [
(v0/*: any*/),
(v1/*: any*/)
],
"storageKey": null
}
],
"type": "BrowserSession",
"abstractKey": null
};
})();
(node as any).hash = "04d6adf0b2a1bf2098938ef30f195c4a";
export default node;

View File

@ -0,0 +1,263 @@
/**
* @generated SignedSource<<816340b05858a7b5a61aca0a72c21c46>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest, Query } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type OAuth2SessionListQuery$variables = {
count?: number | null;
cursor?: string | null;
id: string;
};
export type OAuth2SessionListQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"OAuth2SessionList_user">;
} | null;
};
export type OAuth2SessionListQuery = {
response: OAuth2SessionListQuery$data;
variables: OAuth2SessionListQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "count"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "cursor"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v4 = [
{
"kind": "Variable",
"name": "after",
"variableName": "cursor"
},
{
"kind": "Variable",
"name": "first",
"variableName": "count"
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "OAuth2SessionListQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "OAuth2SessionList_user"
}
],
"storageKey": null
}
],
"type": "RootQuery",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "OAuth2SessionListQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "Oauth2SessionConnection",
"kind": "LinkedField",
"name": "oauth2Sessions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Oauth2SessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Oauth2Session",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "scope",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Oauth2Client",
"kind": "LinkedField",
"name": "client",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientId",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientUri",
"storageKey": null
}
],
"storageKey": null
},
(v2/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": null,
"handle": "connection",
"key": "OAuth2SessionList_user_oauth2Sessions",
"kind": "LinkedHandle",
"name": "oauth2Sessions"
}
],
"type": "User",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "26d1b723940d396f1af608f36ff05ce6",
"id": null,
"metadata": {},
"name": "OAuth2SessionListQuery",
"operationKind": "query",
"text": "query OAuth2SessionListQuery(\n $count: Int\n $cursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...OAuth2SessionList_user\n id\n }\n}\n\nfragment OAuth2SessionList_user on User {\n oauth2Sessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n __typename\n }\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment OAuth2Session_session on Oauth2Session {\n id\n scope\n client {\n id\n clientId\n clientName\n clientUri\n }\n}\n"
}
};
})();
(node as any).hash = "17ef23458a73705550aa33e7f73e41cf";
export default node;

View File

@ -0,0 +1,170 @@
/**
* @generated SignedSource<<8cb936a8cc1a9ab2a877a4ea92622c88>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment, RefetchableFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type OAuth2SessionList_user$data = {
readonly id: string;
readonly oauth2Sessions: {
readonly edges: ReadonlyArray<{
readonly cursor: string;
readonly node: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"OAuth2Session_session">;
};
}>;
};
readonly " $fragmentType": "OAuth2SessionList_user";
};
export type OAuth2SessionList_user$key = {
readonly " $data"?: OAuth2SessionList_user$data;
readonly " $fragmentSpreads": FragmentRefs<"OAuth2SessionList_user">;
};
import OAuth2SessionListQuery_graphql from './OAuth2SessionListQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"oauth2Sessions"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"kind": "RootArgument",
"name": "count"
},
{
"kind": "RootArgument",
"name": "cursor"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": "count",
"cursor": "cursor",
"direction": "forward",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "count",
"cursor": "cursor"
},
"backward": null,
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": OAuth2SessionListQuery_graphql,
"identifierField": "id"
}
},
"name": "OAuth2SessionList_user",
"selections": [
{
"alias": "oauth2Sessions",
"args": null,
"concreteType": "Oauth2SessionConnection",
"kind": "LinkedField",
"name": "__OAuth2SessionList_user_oauth2Sessions_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Oauth2SessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Oauth2Session",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "OAuth2Session_session"
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "User",
"abstractKey": null
};
})();
(node as any).hash = "17ef23458a73705550aa33e7f73e41cf";
export default node;

View File

@ -0,0 +1,92 @@
/**
* @generated SignedSource<<599452efb8ce96e81a5e9500668ff055>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { Fragment, ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type OAuth2Session_session$data = {
readonly client: {
readonly clientId: string;
readonly clientName: string | null;
readonly clientUri: any | null;
readonly id: string;
};
readonly id: string;
readonly scope: string;
readonly " $fragmentType": "OAuth2Session_session";
};
export type OAuth2Session_session$key = {
readonly " $data"?: OAuth2Session_session$data;
readonly " $fragmentSpreads": FragmentRefs<"OAuth2Session_session">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "OAuth2Session_session",
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "scope",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Oauth2Client",
"kind": "LinkedField",
"name": "client",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientId",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientUri",
"storageKey": null
}
],
"storageKey": null
}
],
"type": "Oauth2Session",
"abstractKey": null
};
})();
(node as any).hash = "d9fa36c7f93b7cef4d5a038d19f768b1";
export default node;

View File

@ -13,32 +13,44 @@
// limitations under the License.
import { graphql, useLazyLoadQuery } from "react-relay";
import BrowserSessionList from "../components/BrowserSessionList";
import CompatSsoLoginList from "../components/CompatSsoLoginList";
import OAuth2SessionList from "../components/OAuth2SessionList";
import type { HomeQuery } from "./__generated__/HomeQuery.graphql";
const Home: React.FC = () => {
const data = useLazyLoadQuery<HomeQuery>(
graphql`
query HomeQuery($count: Int!, $cursor: String) {
currentUser {
currentBrowserSession {
id
username
user {
id
username
...CompatSsoLoginList_user
...CompatSsoLoginList_user
...BrowserSessionList_user
...OAuth2SessionList_user
}
}
}
`,
{ count: 2 }
);
if (data.currentUser) {
if (data.currentBrowserSession) {
const session = data.currentBrowserSession;
const user = session.user;
return (
<>
<h1 className="font-bold text-2xl">
Hello {data.currentUser.username}!
</h1>
<CompatSsoLoginList user={data.currentUser} />
<h1 className="font-bold text-2xl">Hello {user.username}!</h1>
<div className="grid lg:grid-cols-3 gap-1">
<OAuth2SessionList user={user} />
<CompatSsoLoginList user={user} />
<BrowserSessionList user={user} currentSessionId={session.id} />
</div>
</>
);
} else {

View File

@ -1,5 +1,5 @@
/**
* @generated SignedSource<<874ab84c1095ab907f12b91b55f4bf2c>>
* @generated SignedSource<<b9d5536e28bde5c8929747fab28aae0e>>
* @lightSyntaxTransform
* @nogrep
*/
@ -15,10 +15,13 @@ export type HomeQuery$variables = {
cursor?: string | null;
};
export type HomeQuery$data = {
readonly currentUser: {
readonly currentBrowserSession: {
readonly id: string;
readonly username: string;
readonly " $fragmentSpreads": FragmentRefs<"CompatSsoLoginList_user">;
readonly user: {
readonly id: string;
readonly username: string;
readonly " $fragmentSpreads": FragmentRefs<"BrowserSessionList_user" | "CompatSsoLoginList_user" | "OAuth2SessionList_user">;
};
} | null;
};
export type HomeQuery = {
@ -71,6 +74,45 @@ v4 = {
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
};
return {
"fragment": {
@ -82,17 +124,39 @@ return {
{
"alias": null,
"args": null,
"concreteType": "User",
"concreteType": "BrowserSession",
"kind": "LinkedField",
"name": "currentUser",
"name": "currentBrowserSession",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "FragmentSpread",
"name": "CompatSsoLoginList_user"
"concreteType": "User",
"kind": "LinkedField",
"name": "user",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "CompatSsoLoginList_user"
},
{
"args": null,
"kind": "FragmentSpread",
"name": "BrowserSessionList_user"
},
{
"args": null,
"kind": "FragmentSpread",
"name": "OAuth2SessionList_user"
}
],
"storageKey": null
}
],
"storageKey": null
@ -110,52 +174,126 @@ return {
{
"alias": null,
"args": null,
"concreteType": "User",
"concreteType": "BrowserSession",
"kind": "LinkedField",
"name": "currentUser",
"name": "currentBrowserSession",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"alias": null,
"args": (v3/*: any*/),
"concreteType": "CompatSsoLoginConnection",
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "compatSsoLogins",
"name": "user",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "CompatSsoLoginEdge",
"args": (v3/*: any*/),
"concreteType": "CompatSsoLoginConnection",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"name": "compatSsoLogins",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "CompatSsoLogin",
"concreteType": "CompatSsoLoginEdge",
"kind": "LinkedField",
"name": "node",
"plural": false,
"name": "edges",
"plural": true,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "redirectUri",
"concreteType": "CompatSsoLogin",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "redirectUri",
"storageKey": null
},
(v4/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "CompatSession",
"kind": "LinkedField",
"name": "session",
"plural": false,
"selections": [
(v1/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deviceId",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "finishedAt",
"storageKey": null
}
],
"storageKey": null
},
(v5/*: any*/)
],
"storageKey": null
},
(v4/*: any*/),
(v6/*: any*/)
],
"storageKey": null
},
(v7/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v3/*: any*/),
"filters": null,
"handle": "connection",
"key": "CompatSsoLoginList_user_compatSsoLogins",
"kind": "LinkedHandle",
"name": "compatSsoLogins"
},
{
"alias": null,
"args": (v3/*: any*/),
"concreteType": "BrowserSessionConnection",
"kind": "LinkedField",
"name": "browserSessions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "BrowserSessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
(v6/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "CompatSession",
"concreteType": "BrowserSession",
"kind": "LinkedField",
"name": "session",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
@ -163,76 +301,124 @@ return {
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deviceId",
"concreteType": "Authentication",
"kind": "LinkedField",
"name": "lastAuthentication",
"plural": false,
"selections": [
(v1/*: any*/),
(v4/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "finishedAt",
"storageKey": null
}
(v5/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
(v7/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"args": (v3/*: any*/),
"filters": null,
"handle": "connection",
"key": "BrowserSessionList_user_browserSessions",
"kind": "LinkedHandle",
"name": "browserSessions"
},
{
"alias": null,
"args": (v3/*: any*/),
"concreteType": "Oauth2SessionConnection",
"kind": "LinkedField",
"name": "pageInfo",
"name": "oauth2Sessions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"concreteType": "Oauth2SessionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
(v6/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Oauth2Session",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "scope",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Oauth2Client",
"kind": "LinkedField",
"name": "client",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientId",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "clientUri",
"storageKey": null
}
],
"storageKey": null
},
(v5/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
(v7/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v3/*: any*/),
"filters": null,
"handle": "connection",
"key": "OAuth2SessionList_user_oauth2Sessions",
"kind": "LinkedHandle",
"name": "oauth2Sessions"
}
],
"storageKey": null
},
{
"alias": null,
"args": (v3/*: any*/),
"filters": null,
"handle": "connection",
"key": "CompatSsoLoginList_user_compatSsoLogins",
"kind": "LinkedHandle",
"name": "compatSsoLogins"
}
],
"storageKey": null
@ -240,16 +426,16 @@ return {
]
},
"params": {
"cacheID": "3543c7ada63831383f66dbeed4b1648e",
"cacheID": "c2c8afebb1acbce26f8d164d911c5833",
"id": null,
"metadata": {},
"name": "HomeQuery",
"operationKind": "query",
"text": "query HomeQuery(\n $count: Int!\n $cursor: String\n) {\n currentUser {\n id\n username\n ...CompatSsoLoginList_user\n }\n}\n\nfragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: $count, after: $cursor) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n createdAt\n deviceId\n finishedAt\n }\n}\n"
"text": "query HomeQuery(\n $count: Int!\n $cursor: String\n) {\n currentBrowserSession {\n id\n user {\n id\n username\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n}\n\nfragment BrowserSessionList_user on User {\n browserSessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n __typename\n }\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n}\n\nfragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: $count, after: $cursor) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n createdAt\n deviceId\n finishedAt\n }\n}\n\nfragment OAuth2SessionList_user on User {\n oauth2Sessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n __typename\n }\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment OAuth2Session_session on Oauth2Session {\n id\n scope\n client {\n id\n clientId\n clientName\n clientUri\n }\n}\n"
}
};
})();
(node as any).hash = "1cd5ce8ae5a912b3d7ecf0c6e3cd8469";
(node as any).hash = "f26e9c3756edccc8584de5f359fd96bd";
export default node;