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

WIP my account page

This commit is contained in:
Quentin Gliech
2023-04-27 12:03:46 +02:00
parent f62d045b8c
commit 574514638e
14 changed files with 272 additions and 224 deletions

View File

@ -2,7 +2,7 @@ import { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = { const config: CodegenConfig = {
schema: "./schema.graphql", schema: "./schema.graphql",
documents: ["src/**/*.tsx", "!src/gql/**/*"], documents: ["src/**/*.{tsx,ts}", "!src/gql/**/*"],
ignoreNoDocuments: true, // for better experience with the watcher ignoreNoDocuments: true, // for better experience with the watcher
generates: { generates: {
"./src/gql/": { "./src/gql/": {

View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@urql/core": "^4.0.7", "@urql/core": "^4.0.7",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.0.3", "@urql/exchange-graphcache": "^6.0.3",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"graphql": "^16.6.0", "graphql": "^16.6.0",
@ -6440,6 +6441,18 @@
"wonka": "^6.3.2" "wonka": "^6.3.2"
} }
}, },
"node_modules/@urql/devtools": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@urql/devtools/-/devtools-2.0.3.tgz",
"integrity": "sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==",
"dependencies": {
"wonka": ">= 4.0.9"
},
"peerDependencies": {
"@urql/core": ">= 1.14.0",
"graphql": ">= 0.11.0"
}
},
"node_modules/@urql/exchange-graphcache": { "node_modules/@urql/exchange-graphcache": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.0.3.tgz", "resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.0.3.tgz",

View File

@ -18,6 +18,7 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@urql/core": "^4.0.7", "@urql/core": "^4.0.7",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.0.3", "@urql/exchange-graphcache": "^6.0.3",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"graphql": "^16.6.0", "graphql": "^16.6.0",

View File

@ -13,12 +13,66 @@
// limitations under the License. // limitations under the License.
import type { ReactElement } from "react"; import type { ReactElement } from "react";
import { atom } from "jotai";
import { useHydrateAtoms } from "jotai/utils"; import { useHydrateAtoms } from "jotai/utils";
import { clientAtom } from "jotai-urql"; import { atomWithQuery, clientAtom } from "jotai-urql";
import { client } from "./graphql"; import { client } from "./graphql";
import { graphql } from "./gql";
export const HydrateAtoms = ({ children }: { children: ReactElement }) => { export const HydrateAtoms = ({ children }: { children: ReactElement }) => {
useHydrateAtoms([[clientAtom, client]]); useHydrateAtoms([[clientAtom, client]]);
return children; return children;
}; };
const CURRENT_VIEWER_QUERY = graphql(/* GraphQL */ `
query CurrentViewerQuery {
viewer {
... on User {
id
}
... on Anonymous {
id
}
}
}
`);
const currentViewerAtom = atomWithQuery({ query: CURRENT_VIEWER_QUERY });
export const currentUserIdAtom = atom(async (get) => {
const result = await get(currentViewerAtom);
if (result.data?.viewer.__typename === "User") {
return result.data.viewer.id;
}
return null;
});
const CURRENT_VIEWER_SESSION_QUERY = graphql(/* GraphQL */ `
query CurrentViewerSessionQuery {
viewerSession {
... on BrowserSession {
id
}
... on Anonymous {
id
}
}
}
`);
const currentViewerSessionAtom = atomWithQuery({
query: CURRENT_VIEWER_SESSION_QUERY,
});
export const currentBrowserSessionIdAtom = atom(
async (get): Promise<string | null> => {
const result = await get(currentViewerSessionAtom);
if (result.data?.viewerSession.__typename === "BrowserSession") {
return result.data.viewerSession.id;
}
return null;
}
);

View File

@ -19,7 +19,7 @@ import { FragmentType, graphql, useFragment } from "../gql";
const FRAGMENT = graphql(/* GraphQL */ ` const FRAGMENT = graphql(/* GraphQL */ `
fragment BrowserSessionList_user on User { fragment BrowserSessionList_user on User {
browserSessions(first: $count, after: $cursor) { browserSessions(first: 10) {
edges { edges {
cursor cursor
node { node {

View File

@ -19,7 +19,7 @@ import { FragmentType, graphql, useFragment } from "../gql";
const FRAGMENT = graphql(/* GraphQL */ ` const FRAGMENT = graphql(/* GraphQL */ `
fragment CompatSsoLoginList_user on User { fragment CompatSsoLoginList_user on User {
compatSsoLogins(first: $count, after: $cursor) { compatSsoLogins(first: 10) {
edges { edges {
node { node {
id id

View File

@ -20,7 +20,7 @@ import { FragmentType, graphql, useFragment } from "../gql";
const FRAGMENT = graphql(/* GraphQL */ ` const FRAGMENT = graphql(/* GraphQL */ `
fragment OAuth2SessionList_user on User { fragment OAuth2SessionList_user on User {
oauth2Sessions(first: $count, after: $cursor) { oauth2Sessions(first: 10) {
edges { edges {
cursor cursor
node { node {

View File

@ -31,7 +31,6 @@ const QUERY = graphql(/* GraphQL */ `
$before: String $before: String
) { ) {
user(id: $userId) { user(id: $userId) {
__typename
id id
emails(first: $first, after: $after, last: $last, before: $before) { emails(first: $first, after: $after, last: $last, before: $before) {
edges { edges {
@ -54,12 +53,12 @@ const QUERY = graphql(/* GraphQL */ `
`); `);
type ForwardPagination = { type ForwardPagination = {
first: int; first: number;
after: string | null; after: string | null;
}; };
type BackwardPagination = { type BackwardPagination = {
last: int; last: number;
before: string | null; before: string | null;
}; };

View File

@ -13,31 +13,33 @@ import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel or swc plugin for production. * Therefore it is highly recommended to use the babel or swc plugin for production.
*/ */
const documents = { const documents = {
"\n query CurrentViewerQuery {\n viewer {\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n":
types.CurrentViewerQueryDocument,
"\n query CurrentViewerSessionQuery {\n viewerSession {\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n":
types.CurrentViewerSessionQueryDocument,
"\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n user {\n id\n }\n email {\n id\n ...UserEmail_email\n }\n }\n }\n": "\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n user {\n id\n }\n email {\n id\n ...UserEmail_email\n }\n }\n }\n":
types.AddEmailDocument, types.AddEmailDocument,
"\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n": "\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n":
types.BrowserSession_SessionFragmentDoc, types.BrowserSession_SessionFragmentDoc,
"\n fragment BrowserSessionList_user on User {\n browserSessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n": "\n fragment BrowserSessionList_user on User {\n browserSessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n":
types.BrowserSessionList_UserFragmentDoc, types.BrowserSessionList_UserFragmentDoc,
"\n fragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n createdAt\n deviceId\n finishedAt\n }\n }\n": "\n fragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n createdAt\n deviceId\n finishedAt\n }\n }\n":
types.CompatSsoLogin_LoginFragmentDoc, types.CompatSsoLogin_LoginFragmentDoc,
"\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: $count, after: $cursor) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n": "\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: 10) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n":
types.CompatSsoLoginList_UserFragmentDoc, types.CompatSsoLoginList_UserFragmentDoc,
"\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n": "\n fragment OAuth2Session_session on Oauth2Session {\n id\n scope\n client {\n id\n clientId\n clientName\n clientUri\n }\n }\n":
types.OAuth2Session_SessionFragmentDoc, types.OAuth2Session_SessionFragmentDoc,
"\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n": "\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n":
types.OAuth2SessionList_UserFragmentDoc, types.OAuth2SessionList_UserFragmentDoc,
"\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n": "\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n":
types.UserEmail_EmailFragmentDoc, types.UserEmail_EmailFragmentDoc,
"\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n __typename\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n": "\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n":
types.UserEmailListQueryDocument, types.UserEmailListQueryDocument,
"\n query CurrentUserQuery {\n viewer {\n ... on User {\n __typename\n id\n }\n }\n }\n":
types.CurrentUserQueryDocument,
"\n query AccountQuery($id: ID!) {\n user(id: $id) {\n id\n username\n }\n }\n": "\n query AccountQuery($id: ID!) {\n user(id: $id) {\n id\n username\n }\n }\n":
types.AccountQueryDocument, types.AccountQueryDocument,
"\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": "\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, types.BrowserSessionQueryDocument,
"\n query HomeQuery($count: Int!, $cursor: String) {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n": "\n query HomeQuery {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n":
types.HomeQueryDocument, types.HomeQueryDocument,
"\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 }\n }\n":
types.OAuth2ClientQueryDocument, types.OAuth2ClientQueryDocument,
@ -57,6 +59,18 @@ const documents = {
*/ */
export function graphql(source: string): unknown; export function graphql(source: string): unknown;
/**
* 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 CurrentViewerQuery {\n viewer {\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): (typeof documents)["\n query CurrentViewerQuery {\n viewer {\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
/**
* 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 CurrentViewerSessionQuery {\n viewerSession {\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): (typeof documents)["\n query CurrentViewerSessionQuery {\n viewerSession {\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -73,8 +87,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql( export function graphql(
source: "\n fragment BrowserSessionList_user on User {\n browserSessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n" source: "\n fragment BrowserSessionList_user on User {\n browserSessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n"
): (typeof documents)["\n fragment BrowserSessionList_user on User {\n browserSessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n"]; ): (typeof documents)["\n fragment BrowserSessionList_user on User {\n browserSessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -85,8 +99,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql( export function graphql(
source: "\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: $count, after: $cursor) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n" source: "\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: 10) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n"
): (typeof documents)["\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: $count, after: $cursor) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n"]; ): (typeof documents)["\n fragment CompatSsoLoginList_user on User {\n compatSsoLogins(first: 10) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -97,8 +111,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql( export function graphql(
source: "\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n" source: "\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n"
): (typeof documents)["\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n"]; ): (typeof documents)["\n fragment OAuth2SessionList_user on User {\n oauth2Sessions(first: 10) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -109,14 +123,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql( export function graphql(
source: "\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n __typename\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n" source: "\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): (typeof documents)["\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n __typename\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"]; ): (typeof documents)["\n query UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
/**
* 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 CurrentUserQuery {\n viewer {\n ... on User {\n __typename\n id\n }\n }\n }\n"
): (typeof documents)["\n query CurrentUserQuery {\n viewer {\n ... on User {\n __typename\n id\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -133,8 +141,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql( export function graphql(
source: "\n query HomeQuery($count: Int!, $cursor: String) {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n" source: "\n query HomeQuery {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n"
): (typeof documents)["\n query HomeQuery($count: Int!, $cursor: String) {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n"]; ): (typeof documents)["\n query HomeQuery {\n # eslint-disable-next-line @graphql-eslint/no-deprecated\n currentBrowserSession {\n id\n user {\n id\n username\n\n ...CompatSsoLoginList_user\n ...BrowserSessionList_user\n ...OAuth2SessionList_user\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

View File

@ -577,6 +577,26 @@ export type Viewer = Anonymous | User;
/** Represents the current viewer's session */ /** Represents the current viewer's session */
export type ViewerSession = Anonymous | BrowserSession; export type ViewerSession = Anonymous | BrowserSession;
export type CurrentViewerQueryQueryVariables = Exact<{ [key: string]: never }>;
export type CurrentViewerQueryQuery = {
__typename?: "Query";
viewer:
| { __typename?: "Anonymous"; id: string }
| { __typename?: "User"; id: string };
};
export type CurrentViewerSessionQueryQueryVariables = Exact<{
[key: string]: never;
}>;
export type CurrentViewerSessionQueryQuery = {
__typename?: "Query";
viewerSession:
| { __typename?: "Anonymous"; id: string }
| { __typename?: "BrowserSession"; id: string };
};
export type AddEmailMutationVariables = Exact<{ export type AddEmailMutationVariables = Exact<{
userId: Scalars["ID"]; userId: Scalars["ID"];
email: Scalars["String"]; email: Scalars["String"];
@ -698,7 +718,7 @@ export type UserEmailListQueryQueryVariables = Exact<{
export type UserEmailListQueryQuery = { export type UserEmailListQueryQuery = {
__typename?: "Query"; __typename?: "Query";
user?: { user?: {
__typename: "User"; __typename?: "User";
id: string; id: string;
emails: { emails: {
__typename?: "UserEmailConnection"; __typename?: "UserEmailConnection";
@ -723,13 +743,6 @@ export type UserEmailListQueryQuery = {
} | null; } | null;
}; };
export type CurrentUserQueryQueryVariables = Exact<{ [key: string]: never }>;
export type CurrentUserQueryQuery = {
__typename?: "Query";
viewer: { __typename?: "Anonymous" } | { __typename: "User"; id: string };
};
export type AccountQueryQueryVariables = Exact<{ export type AccountQueryQueryVariables = Exact<{
id: Scalars["ID"]; id: Scalars["ID"];
}>; }>;
@ -758,10 +771,7 @@ export type BrowserSessionQueryQuery = {
} | null; } | null;
}; };
export type HomeQueryQueryVariables = Exact<{ export type HomeQueryQueryVariables = Exact<{ [key: string]: never }>;
count: Scalars["Int"];
cursor?: InputMaybe<Scalars["String"]>;
}>;
export type HomeQueryQuery = { export type HomeQueryQuery = {
__typename?: "Query"; __typename?: "Query";
@ -847,18 +857,7 @@ export const BrowserSessionList_UserFragmentDoc = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {
@ -985,18 +984,7 @@ export const CompatSsoLoginList_UserFragmentDoc = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {
@ -1121,18 +1109,7 @@ export const OAuth2SessionList_UserFragmentDoc = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {
@ -1229,6 +1206,112 @@ export const UserEmail_EmailFragmentDoc = {
}, },
], ],
} as unknown as DocumentNode<UserEmail_EmailFragment, unknown>; } as unknown as DocumentNode<UserEmail_EmailFragment, unknown>;
export const CurrentViewerQueryDocument = {
kind: "Document",
definitions: [
{
kind: "OperationDefinition",
operation: "query",
name: { kind: "Name", value: "CurrentViewerQuery" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "viewer" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "InlineFragment",
typeCondition: {
kind: "NamedType",
name: { kind: "Name", value: "User" },
},
selectionSet: {
kind: "SelectionSet",
selections: [
{ kind: "Field", name: { kind: "Name", value: "id" } },
],
},
},
{
kind: "InlineFragment",
typeCondition: {
kind: "NamedType",
name: { kind: "Name", value: "Anonymous" },
},
selectionSet: {
kind: "SelectionSet",
selections: [
{ kind: "Field", name: { kind: "Name", value: "id" } },
],
},
},
],
},
},
],
},
},
],
} as unknown as DocumentNode<
CurrentViewerQueryQuery,
CurrentViewerQueryQueryVariables
>;
export const CurrentViewerSessionQueryDocument = {
kind: "Document",
definitions: [
{
kind: "OperationDefinition",
operation: "query",
name: { kind: "Name", value: "CurrentViewerSessionQuery" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "viewerSession" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "InlineFragment",
typeCondition: {
kind: "NamedType",
name: { kind: "Name", value: "BrowserSession" },
},
selectionSet: {
kind: "SelectionSet",
selections: [
{ kind: "Field", name: { kind: "Name", value: "id" } },
],
},
},
{
kind: "InlineFragment",
typeCondition: {
kind: "NamedType",
name: { kind: "Name", value: "Anonymous" },
},
selectionSet: {
kind: "SelectionSet",
selections: [
{ kind: "Field", name: { kind: "Name", value: "id" } },
],
},
},
],
},
},
],
},
},
],
} as unknown as DocumentNode<
CurrentViewerSessionQueryQuery,
CurrentViewerSessionQueryQueryVariables
>;
export const AddEmailDocument = { export const AddEmailDocument = {
kind: "Document", kind: "Document",
definitions: [ definitions: [
@ -1417,7 +1500,6 @@ export const UserEmailListQueryDocument = {
selectionSet: { selectionSet: {
kind: "SelectionSet", kind: "SelectionSet",
selections: [ selections: [
{ kind: "Field", name: { kind: "Name", value: "__typename" } },
{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "id" } },
{ {
kind: "Field", kind: "Field",
@ -1552,50 +1634,6 @@ export const UserEmailListQueryDocument = {
UserEmailListQueryQuery, UserEmailListQueryQuery,
UserEmailListQueryQueryVariables UserEmailListQueryQueryVariables
>; >;
export const CurrentUserQueryDocument = {
kind: "Document",
definitions: [
{
kind: "OperationDefinition",
operation: "query",
name: { kind: "Name", value: "CurrentUserQuery" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "viewer" },
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "InlineFragment",
typeCondition: {
kind: "NamedType",
name: { kind: "Name", value: "User" },
},
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "__typename" },
},
{ kind: "Field", name: { kind: "Name", value: "id" } },
],
},
},
],
},
},
],
},
},
],
} as unknown as DocumentNode<
CurrentUserQueryQuery,
CurrentUserQueryQueryVariables
>;
export const AccountQueryDocument = { export const AccountQueryDocument = {
kind: "Document", kind: "Document",
definitions: [ definitions: [
@ -1726,27 +1764,6 @@ export const HomeQueryDocument = {
kind: "OperationDefinition", kind: "OperationDefinition",
operation: "query", operation: "query",
name: { kind: "Name", value: "HomeQuery" }, name: { kind: "Name", value: "HomeQuery" },
variableDefinitions: [
{
kind: "VariableDefinition",
variable: {
kind: "Variable",
name: { kind: "Name", value: "count" },
},
type: {
kind: "NonNullType",
type: { kind: "NamedType", name: { kind: "Name", value: "Int" } },
},
},
{
kind: "VariableDefinition",
variable: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
type: { kind: "NamedType", name: { kind: "Name", value: "String" } },
},
],
selectionSet: { selectionSet: {
kind: "SelectionSet", kind: "SelectionSet",
selections: [ selections: [
@ -1895,18 +1912,7 @@ export const HomeQueryDocument = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {
@ -1964,18 +1970,7 @@ export const HomeQueryDocument = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {
@ -2037,18 +2032,7 @@ export const HomeQueryDocument = {
{ {
kind: "Argument", kind: "Argument",
name: { kind: "Name", value: "first" }, name: { kind: "Name", value: "first" },
value: { value: { kind: "IntValue", value: "10" },
kind: "Variable",
name: { kind: "Name", value: "count" },
},
},
{
kind: "Argument",
name: { kind: "Name", value: "after" },
value: {
kind: "Variable",
name: { kind: "Name", value: "cursor" },
},
}, },
], ],
selectionSet: { selectionSet: {

View File

@ -17,33 +17,35 @@ import { cacheExchange } from "@urql/exchange-graphcache";
import schema from "./gql/schema"; import schema from "./gql/schema";
import type { MutationAddEmailArgs } from "./gql/graphql"; import type { MutationAddEmailArgs } from "./gql/graphql";
import { devtoolsExchange } from "@urql/devtools";
const cache = cacheExchange({
schema,
updates: {
Mutation: {
addEmail: (result, args: MutationAddEmailArgs, cache, _info) => {
const key = cache.keyOfEntity({
__typename: "User",
id: args.input.userId,
});
// Invalidate the emails field on the User object so that it gets refetched
cache
.inspectFields(key)
.filter((field) => field.fieldName === "emails")
.forEach((field) => {
cache.invalidate(key, field.fieldName, field.arguments);
});
},
},
},
});
export const client = createClient({ export const client = createClient({
url: "/graphql", url: "/graphql",
// XXX: else queries don't refetch on cache invalidation for some reason // XXX: else queries don't refetch on cache invalidation for some reason
requestPolicy: "cache-and-network", requestPolicy: "cache-and-network",
exchanges: [ exchanges: import.meta.env.DEV
cacheExchange({ ? [devtoolsExchange, cache, fetchExchange]
schema, : [cache, fetchExchange],
updates: {
Mutation: {
addEmail: (result, args: MutationAddEmailArgs, cache, _info) => {
const key = cache.keyOfEntity({
__typename: "User",
id: args.input.userId,
});
// Invalidate the emails field on the User object so that it gets refetched
cache
.inspectFields(key)
.filter((field) => field.fieldName === "emails")
.forEach((field) => {
cache.invalidate(key, field.fieldName, field.arguments);
});
},
},
},
}),
fetchExchange,
],
}); });

View File

@ -24,7 +24,7 @@ import { HydrateAtoms } from "./atoms";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode> <React.StrictMode>
<Provider> <Provider>
<DevTools /> {import.meta.env.DEV && <DevTools />}
<HydrateAtoms> <HydrateAtoms>
<React.Suspense fallback={<LoadingScreen />}> <React.Suspense fallback={<LoadingScreen />}>
<Router /> <Router />

View File

@ -21,19 +21,7 @@ import { graphql } from "../gql";
import UserEmailList from "../components/UserEmailList"; import UserEmailList from "../components/UserEmailList";
import { Title } from "../components/Typography"; import { Title } from "../components/Typography";
import AddEmailForm from "../components/AddEmailForm"; import AddEmailForm from "../components/AddEmailForm";
import { currentUserIdAtom } from "../atoms";
const CURRENT_USER_QUERY = graphql(/* GraphQL */ `
query CurrentUserQuery {
viewer {
... on User {
__typename
id
}
}
}
`);
const currentUserAtom = atomWithQuery({ query: CURRENT_USER_QUERY });
const QUERY = graphql(/* GraphQL */ ` const QUERY = graphql(/* GraphQL */ `
query AccountQuery($id: ID!) { query AccountQuery($id: ID!) {
@ -61,11 +49,11 @@ const UserAccount: React.FC<{ id: string }> = ({ id }) => {
}; };
const CurrentUserAccount: React.FC = () => { const CurrentUserAccount: React.FC = () => {
const result = useAtomValue(currentUserAtom); const userId = useAtomValue(currentUserIdAtom);
if (result.data?.viewer?.__typename === "User") { if (userId !== null) {
return ( return (
<div className="w-96 mx-auto"> <div className="w-96 mx-auto">
<UserAccount id={result.data.viewer.id} /> <UserAccount id={userId} />
</div> </div>
); );
} }

View File

@ -22,7 +22,7 @@ import Typography from "../components/Typography";
import { graphql } from "../gql"; import { graphql } from "../gql";
const QUERY = graphql(/* GraphQL */ ` const QUERY = graphql(/* GraphQL */ `
query HomeQuery($count: Int!, $cursor: String) { query HomeQuery {
# eslint-disable-next-line @graphql-eslint/no-deprecated # eslint-disable-next-line @graphql-eslint/no-deprecated
currentBrowserSession { currentBrowserSession {
id id
@ -40,7 +40,6 @@ const QUERY = graphql(/* GraphQL */ `
const homeDataAtom = atomWithQuery({ const homeDataAtom = atomWithQuery({
query: QUERY, query: QUERY,
getVariables: () => ({ count: 10 }),
}); });
const Home: React.FC = () => { const Home: React.FC = () => {