1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-21 23:00:50 +03:00

Frontend cleanups

Mainly:

 - better handling of GraphQL errors
 - better logout state
 - dependencies update
 - a way to end browser sessions in the GraphQL API
This commit is contained in:
Quentin Gliech
2023-06-20 15:05:48 +02:00
parent ebb87f0a5e
commit f67cc0d6d0
24 changed files with 1072 additions and 230 deletions

View File

@@ -12,13 +12,52 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { atom } from "jotai";
import { AnyVariables, CombinedError, OperationContext } from "@urql/core";
import { atom, WritableAtom } from "jotai";
import { useHydrateAtoms } from "jotai/utils";
import { atomWithQuery, clientAtom } from "jotai-urql";
import { AtomWithQuery, atomWithQuery, clientAtom } from "jotai-urql";
import type { ReactElement } from "react";
import { graphql } from "./gql";
import { client } from "./graphql";
import { err, ok, Result } from "./result";
export type GqlResult<T> = Result<T, CombinedError>;
export type GqlAtom<T> = WritableAtom<
Promise<GqlResult<T>>,
[context?: Partial<OperationContext>],
void
>;
/**
* Map the result of a query atom to a new value, making it a GqlResult
*
* @param queryAtom: An atom got from atomWithQuery
* @param mapper: A function that takes the data from the query and returns a new value
*/
export const mapQueryAtom = <Data, Variables extends AnyVariables, NewData>(
queryAtom: AtomWithQuery<Data, Variables>,
mapper: (data: Data) => NewData
): GqlAtom<NewData> => {
return atom(
async (get): Promise<GqlResult<NewData>> => {
const result = await get(queryAtom);
if (result.error) {
return err(result.error);
}
if (result.data === undefined) {
throw new Error("Query result is undefined");
}
return ok(mapper(result.data));
},
(_get, set, context) => {
set(queryAtom, context);
}
);
};
export const HydrateAtoms: React.FC<{ children: ReactElement }> = ({
children,
@@ -44,13 +83,15 @@ const CURRENT_VIEWER_QUERY = graphql(/* GraphQL */ `
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;
export const currentUserIdAtom: GqlAtom<string | null> = mapQueryAtom(
currentViewerAtom,
(data) => {
if (data.viewer.__typename === "User") {
return data.viewer.id;
}
return null;
}
return null;
});
);
const CURRENT_VIEWER_SESSION_QUERY = graphql(/* GraphQL */ `
query CurrentViewerSessionQuery {
@@ -71,11 +112,11 @@ 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;
export const currentBrowserSessionIdAtom: GqlAtom<string | null> = mapQueryAtom(
currentViewerSessionAtom,
(data) => {
if (data.viewerSession.__typename === "BrowserSession") {
return data.viewerSession.id;
}
return null;
}