1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-07 17:03:01 +03:00

Adopt eslint-config-matrix-org & bump deps

This commit is contained in:
Quentin Gliech
2023-06-13 18:43:06 +02:00
parent b493f62251
commit 3672d2dbde
27 changed files with 2978 additions and 2580 deletions

View File

@@ -26,17 +26,25 @@ module.exports = {
// General rules for JS/TS files
{
extends: [
"react-app",
"react-app/jest",
"prettier",
"plugin:prettier/recommended",
"plugin:jsx-a11y/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:matrix-org/typescript",
"plugin:matrix-org/react",
"plugin:matrix-org/a11y",
],
plugins: ["jsx-a11y"],
env: {
browser: true,
node: true,
es6: true,
},
plugins: ["jsx-a11y", "matrix-org"],
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.json"],
},
files: ["*.ts", "*.tsx", "*.cjs", "*.js"],
rules: {
"matrix-org/require-copyright-header": "error",
"import/order": [
"error",
{
@@ -49,6 +57,9 @@ module.exports = {
"import/resolver": {
typescript: true,
},
react: {
version: "detect",
},
},
},

View File

@@ -1,3 +1,17 @@
// 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 { ArgTypes, Decorator, Parameters } from "@storybook/react";
import { useLayoutEffect } from "react";
import "../src/index.css";

View File

@@ -1,3 +1,17 @@
// 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 { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {

File diff suppressed because it is too large Load Diff

View File

@@ -16,16 +16,16 @@
"build-storybook": "storybook build"
},
"dependencies": {
"@emotion/react": "^11.11.0",
"@urql/core": "^4.0.7",
"@emotion/react": "^11.11.1",
"@urql/core": "^4.0.10",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.0.4",
"@urql/exchange-graphcache": "^6.1.3",
"@urql/exchange-refocus": "^1.0.2",
"@urql/exchange-request-policy": "^1.0.2",
"@vector-im/compound-web": "https://github.com/vector-im/compound-web.git",
"@vector-im/compound-web": "https://github.com/vector-im/compound-web.git#c3f760ae02499897b9315feee51310cb739e7257",
"date-fns": "^2.30.0",
"graphql": "^16.6.0",
"jotai": "^2.1.0",
"jotai": "^2.2.0",
"jotai-devtools": "^0.5.3",
"jotai-location": "^0.5.1",
"jotai-urql": "^0.7.1",
@@ -33,44 +33,45 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@graphql-codegen/cli": "^4.0.0",
"@graphql-codegen/cli": "^4.0.1",
"@graphql-codegen/client-preset": "^4.0.0",
"@graphql-codegen/urql-introspection": "^2.2.1",
"@graphql-eslint/eslint-plugin": "^3.19.1",
"@storybook/addon-actions": "^7.0.17",
"@storybook/addon-backgrounds": "^7.0.17",
"@storybook/addon-controls": "^7.0.17",
"@storybook/addon-docs": "^7.0.17",
"@storybook/addon-essentials": "^7.0.17",
"@storybook/addon-measure": "^7.0.17",
"@storybook/addon-outline": "^7.0.17",
"@storybook/addon-toolbars": "^7.0.17",
"@storybook/addon-viewport": "^7.0.17",
"@storybook/react": "^7.0.17",
"@storybook/react-vite": "^7.0.17",
"@types/node": "^20.2.3",
"@types/react": "^18.2.7",
"@types/react-dom": "^18.2.4",
"@storybook/addon-actions": "^7.0.20",
"@storybook/addon-backgrounds": "^7.0.20",
"@storybook/addon-controls": "^7.0.20",
"@storybook/addon-docs": "^7.0.20",
"@storybook/addon-essentials": "^7.0.20",
"@storybook/addon-measure": "^7.0.20",
"@storybook/addon-outline": "^7.0.20",
"@storybook/addon-toolbars": "^7.0.20",
"@storybook/addon-viewport": "^7.0.20",
"@storybook/react": "^7.0.20",
"@storybook/react-vite": "^7.0.20",
"@types/node": "^20.3.1",
"@types/react": "^18.2.12",
"@types/react-dom": "^18.2.5",
"@types/react-test-renderer": "^18.0.0",
"@vitejs/plugin-react": "^4.0.0",
"@vitest/coverage-c8": "^0.31.1",
"@vitest/coverage-c8": "^0.32.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.41.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-matrix-org": "^1.1.0",
"eslint-plugin-prettier": "^4.2.1",
"postcss": "^8.4.23",
"prettier": "^2.8.8",
"postcss": "^8.4.24",
"prettier": "2.8.0",
"react-test-renderer": "^18.2.0",
"storybook": "^7.0.17",
"storybook": "^7.0.20",
"tailwindcss": "^3.3.2",
"typescript": "^5.0.4",
"vite": "^4.3.8",
"typescript": "5.0.4",
"vite": "^4.3.9",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-graphql-codegen": "^3.2.2",
"vite-plugin-svgr": "^3.2.0",
"vitest": "^0.31.1"
"vitest": "^0.32.0"
}
}

View File

@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/** @type {import('postcss-load-config').Config */
// @ts-check
/** @type {import('postcss-load-config').Config} */
module.exports = {
plugins: [require("tailwindcss"), require("autoprefixer")],

View File

@@ -126,7 +126,7 @@ const InnerRouter: React.FC = () => {
}
};
const Router = () => (
const Router: React.FC = () => (
<Layout>
<Suspense fallback={<LoadingSpinner />}>
<InnerRouter />
@@ -149,7 +149,7 @@ export const Link: React.FC<
return (
<a
href={path}
onClick={(e: React.MouseEvent) => {
onClick={(e: React.MouseEvent): void => {
// Local links should be handled by the internal routers
// external links do not require a transition
if (!path.startsWith("http")) {

View File

@@ -20,7 +20,9 @@ import type { ReactElement } from "react";
import { graphql } from "./gql";
import { client } from "./graphql";
export const HydrateAtoms = ({ children }: { children: ReactElement }) => {
export const HydrateAtoms: React.FC<{ children: ReactElement }> = ({
children,
}) => {
useHydrateAtoms([[clientAtom, client]]);
return children;
};

View File

@@ -49,7 +49,7 @@ const AddEmailForm: React.FC<{ userId: string; onAdd?: () => void }> = ({
const [addEmailResult, addEmail] = useAtom(addUserEmailAtom);
const [pending, startTransition] = useTransition();
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
const formData = new FormData(e.currentTarget);

View File

@@ -24,7 +24,7 @@ const meta = {
Title,
Subtitle,
Body,
} as Record<string, React.ComponentType<any>>,
} as Record<string, React.ComponentType<unknown>>,
tags: ["autodocs"],
} satisfies Meta<typeof Block>;

View File

@@ -100,7 +100,7 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => {
const setPagination = useSetAtom(currentPaginationAtom);
const [prevPage, nextPage] = useAtomValue(paginationFamily(userId));
const paginate = (pagination: Pagination) => {
const paginate = (pagination: Pagination): void => {
startTransition(() => {
setPagination(pagination);
});
@@ -112,8 +112,8 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => {
<BlockList>
<Title>List of browser sessions:</Title>
<PaginationControls
onPrev={prevPage ? () => paginate(prevPage) : null}
onNext={nextPage ? () => paginate(nextPage) : null}
onPrev={prevPage ? (): void => paginate(prevPage) : null}
onNext={nextPage ? (): void => paginate(nextPage) : null}
disabled={pending}
/>
{data.edges.map((n) => (

View File

@@ -83,7 +83,7 @@ const CompatSession: React.FC<{
const data = useFragment(SESSION_FRAGMENT, session);
const endCompatSession = useSetAtom(endCompatSessionFamily(data.id));
const onSessionEnd = () => {
const onSessionEnd = (): void => {
startTransition(() => {
endCompatSession();
});

View File

@@ -98,7 +98,7 @@ const CompatSsoLoginList: React.FC<{ userId: string }> = ({ userId }) => {
const setPagination = useSetAtom(currentPaginationAtom);
const [prevPage, nextPage] = useAtomValue(paginationFamily(userId));
const paginate = (pagination: Pagination) => {
const paginate = (pagination: Pagination): void => {
startTransition(() => {
setPagination(pagination);
});
@@ -110,8 +110,8 @@ const CompatSsoLoginList: React.FC<{ userId: string }> = ({ userId }) => {
<BlockList>
<Title>List of compatibility sessions:</Title>
<PaginationControls
onPrev={prevPage ? () => paginate(prevPage) : null}
onNext={nextPage ? () => paginate(nextPage) : null}
onPrev={prevPage ? (): void => paginate(prevPage) : null}
onNext={nextPage ? (): void => paginate(nextPage) : null}
disabled={pending}
/>
{data.edges.map((n) => (

View File

@@ -26,11 +26,11 @@ type Props = {
now?: Date;
};
const DateTime = ({
const DateTime: React.FC<Props> = ({
datetime: datetimeProps,
now: nowProps,
className,
}: Props) => {
}) => {
const datetime =
typeof datetimeProps === "string" ? parseISO(datetimeProps) : datetimeProps;
const now = nowProps || new Date();

View File

@@ -19,6 +19,6 @@ import LoadingScreen from "./LoadingScreen";
it("render <LoadingScreen />", () => {
const component = create(<LoadingScreen />);
let tree = component.toJSON();
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

View File

@@ -92,7 +92,7 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
const data = useFragment(FRAGMENT, session);
const endSession = useSetAtom(endSessionFamily(data.id));
const onSessionEnd = () => {
const onSessionEnd = (): void => {
startTransition(() => {
endSession();
});

View File

@@ -103,7 +103,7 @@ const OAuth2SessionList: React.FC<Props> = ({ userId }) => {
const setPagination = useSetAtom(currentPaginationAtom);
const [prevPage, nextPage] = useAtomValue(paginationFamily(userId));
const paginate = (pagination: Pagination) => {
const paginate = (pagination: Pagination): void => {
startTransition(() => {
setPagination(pagination);
});
@@ -115,8 +115,8 @@ const OAuth2SessionList: React.FC<Props> = ({ userId }) => {
<BlockList>
<Title>List of OAuth 2.0 sessions:</Title>
<PaginationControls
onPrev={prevPage ? () => paginate(prevPage) : null}
onNext={nextPage ? () => paginate(nextPage) : null}
onPrev={prevPage ? (): void => paginate(prevPage) : null}
onNext={nextPage ? (): void => paginate(nextPage) : null}
disabled={pending}
/>
{data.edges.map((n) => (

View File

@@ -33,7 +33,7 @@ const PaginationControls: React.FC<Props> = ({
kind="secondary"
size="sm"
disabled={disabled || !onPrev}
onClick={() => onPrev?.()}
onClick={(): void => onPrev?.()}
>
Previous
</Button>
@@ -42,7 +42,7 @@ const PaginationControls: React.FC<Props> = ({
kind="secondary"
size="sm"
disabled={disabled || !onNext}
onClick={() => onNext?.()}
onClick={(): void => onNext?.()}
>
Next
</Button>

View File

@@ -42,13 +42,13 @@ const classMap: Record<Variant, string> = {
micro: "text-xs",
};
const Typography = ({
const Typography: React.FC<Props> = ({
variant,
children,
bold,
justified,
className: extraClassName,
}: Props) => {
}) => {
const element = elementMap[variant];
const boldClass = bold ? "font-semibold" : "";
const justifiedClass = justified ? "text-justify" : "";
@@ -58,28 +58,27 @@ const Typography = ({
type SimpleProps = { children: React.ReactNode };
export const Bold = ({ children }: SimpleProps) => (
export const Bold: React.FC<SimpleProps> = ({ children }) => (
<strong className="font-semibold">{children}</strong>
);
export const Code = ({ children }: SimpleProps) => (
export const Code: React.FC<SimpleProps> = ({ children }) => (
<code className="font-mono text-sm">{children}</code>
);
export const Title = ({ children }: SimpleProps) => (
export const Title: React.FC<SimpleProps> = ({ children }) => (
<Typography variant="title" children={children} />
);
export const Subtitle = ({ children }: SimpleProps) => (
export const Subtitle: React.FC<SimpleProps> = ({ children }) => (
<Typography variant="subtitle" children={children} />
);
export const Body = ({
children,
justified,
}: {
export const Body: React.FC<{
children: React.ReactNode;
justified?: boolean;
}) => <Typography variant="body" children={children} justified={justified} />;
}> = ({ children, justified }) => (
<Typography variant="body" children={children} justified={justified} />
);
export default Typography;

View File

@@ -170,7 +170,7 @@ const UserEmail: React.FC<{
const removeEmail = useSetAtom(removeEmailFamily(data.id));
const formRef = useRef<HTMLFormElement>(null);
const onFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const onFormSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const code = formData.get("code") as string;
@@ -188,7 +188,7 @@ const UserEmail: React.FC<{
});
};
const onResendClick = () => {
const onResendClick = (): void => {
startTransition(() => {
resendVerificationEmail().then(() => {
formRef.current?.code.focus();
@@ -196,7 +196,7 @@ const UserEmail: React.FC<{
});
};
const onRemoveClick = () => {
const onRemoveClick = (): void => {
startTransition(() => {
removeEmail().then(() => {
// Call the onRemove callback if provided
@@ -205,7 +205,7 @@ const UserEmail: React.FC<{
});
};
const onSetPrimaryClick = () => {
const onSetPrimaryClick = (): void => {
startTransition(() => {
setPrimaryEmail().then(() => {
// Call the onSetPrimary callback if provided

View File

@@ -136,14 +136,14 @@ const UserEmailList: React.FC<{
// XXX: we may not want to directly use that atom here, but rather have a local state
const latestAddedEmail = useAtomValue(latestAddedEmailAtom);
const paginate = (pagination: Pagination) => {
const paginate = (pagination: Pagination): void => {
startTransition(() => {
setPagination(pagination);
});
};
// When removing an email, we want to refresh the list and go back to the first page
const onRemove = () => {
const onRemove = (): void => {
startTransition(() => {
setPagination(FIRST_PAGE);
refreshList();
@@ -151,7 +151,7 @@ const UserEmailList: React.FC<{
};
// When adding an email, we want to refresh the list and go to the last page
const onAdd = () => {
const onAdd = (): void => {
startTransition(() => {
setPagination(LAST_PAGE);
refreshList();
@@ -162,8 +162,8 @@ const UserEmailList: React.FC<{
<BlockList>
<PaginationControls
count={result.data?.user?.emails?.totalCount ?? 0}
onPrev={prevPage ? () => paginate(prevPage) : null}
onNext={nextPage ? () => paginate(nextPage) : null}
onPrev={prevPage ? (): void => paginate(prevPage) : null}
onNext={nextPage ? (): void => paginate(nextPage) : null}
disabled={pending}
/>
{result.data?.user?.emails?.edges?.map((edge) => (

22
frontend/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
// 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.
declare module "*.svg" {
const ReactComponent: React.FunctionComponent<
React.SVGAttributes<SVGElement>
>;
export default ReactComponent;
}
declare module "*.module.css";

View File

@@ -78,133 +78,133 @@ export function graphql(source: string): unknown;
*/
export function graphql(
source: "\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): (typeof documents)["\n query CurrentViewerQuery {\n viewer {\n __typename\n ... on User {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
): typeof documents["\n query CurrentViewerQuery {\n viewer {\n __typename\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 __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"
): (typeof documents)["\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n }\n\n ... on Anonymous {\n id\n }\n }\n }\n"];
): typeof documents["\n query CurrentViewerSessionQuery {\n viewerSession {\n __typename\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.
*/
export function graphql(
source: "\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): (typeof documents)["\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
): typeof documents["\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n email {\n id\n ...UserEmail_email\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 fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"
): (typeof documents)["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\n }\n }\n"];
): typeof documents["\n fragment BrowserSession_session on BrowserSession {\n id\n createdAt\n lastAuthentication {\n id\n createdAt\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 BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): (typeof documents)["\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
): typeof documents["\n query BrowserSessionList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\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 fragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n ...CompatSsoLogin_session\n createdAt\n deviceId\n finishedAt\n }\n }\n"
): (typeof documents)["\n fragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n ...CompatSsoLogin_session\n createdAt\n deviceId\n finishedAt\n }\n }\n"];
): typeof documents["\n fragment CompatSsoLogin_login on CompatSsoLogin {\n id\n redirectUri\n createdAt\n session {\n id\n ...CompatSsoLogin_session\n createdAt\n deviceId\n finishedAt\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 fragment CompatSsoLogin_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n }\n"
): (typeof documents)["\n fragment CompatSsoLogin_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n }\n"];
): typeof documents["\n fragment CompatSsoLogin_session on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\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 mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n ...CompatSsoLogin_session\n }\n }\n }\n"
): (typeof documents)["\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n ...CompatSsoLogin_session\n }\n }\n }\n"];
): typeof documents["\n mutation EndCompatSession($id: ID!) {\n endCompatSession(input: { compatSessionId: $id }) {\n status\n compatSession {\n id\n ...CompatSsoLogin_session\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 CompatSsoLoginList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSsoLogins(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): (typeof documents)["\n query CompatSsoLoginList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSsoLogins(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
): typeof documents["\n query CompatSsoLoginList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n compatSsoLogins(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n node {\n id\n ...CompatSsoLogin_login\n }\n }\n\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 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"];
): 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"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n mutation EndSession($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n"
): (typeof documents)["\n mutation EndSession($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\n }\n }\n }\n"];
): typeof documents["\n mutation EndSession($id: ID!) {\n endOauth2Session(input: { oauth2SessionId: $id }) {\n status\n oauth2Session {\n id\n ...OAuth2Session_session\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 OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"
): (typeof documents)["\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n"];
): typeof documents["\n query OAuth2SessionListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n oauth2Sessions(\n first: $first\n after: $after\n last: $last\n before: $before\n ) {\n edges {\n cursor\n node {\n id\n ...OAuth2Session_session\n }\n }\n\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 fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n"
): (typeof documents)["\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\n }\n"];
): typeof documents["\n fragment UserEmail_email on UserEmail {\n id\n email\n createdAt\n confirmedAt\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 mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): (typeof documents)["\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
): typeof documents["\n mutation VerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\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 mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"
): (typeof documents)["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n"];
): typeof documents["\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\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 mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n"
): (typeof documents)["\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n"];
): typeof documents["\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\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 mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n"
): (typeof documents)["\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n"];
): typeof documents["\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\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 UserEmailListQuery(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\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\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\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 UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n"
): (typeof documents)["\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\n id\n }\n }\n }\n"];
): typeof documents["\n query UserPrimaryEmail($userId: ID!) {\n user(id: $userId) {\n id\n primaryEmail {\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 UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n }\n }\n"
): (typeof documents)["\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\n }\n }\n"];
): typeof documents["\n query UserGreeting($userId: ID!) {\n user(id: $userId) {\n id\n username\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 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"
): (typeof documents)["\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"];
): typeof documents["\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"];
/**
* 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"];
): 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"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { atom, Atom } from "jotai";
import { atom, Atom, WritableAtom } from "jotai";
import { PageInfo } from "./gql/graphql";
@@ -49,7 +49,13 @@ export const isBackwardPagination = (
// This atom sets the default page size for pagination.
export const pageSizeAtom = atom(6);
export const atomForCurrentPagination = () => {
type Action = typeof FIRST_PAGE | typeof LAST_PAGE | Pagination;
export const atomForCurrentPagination = (): WritableAtom<
Pagination,
[Action],
void
> => {
const dataAtom = atom<typeof EMPTY | Pagination>(EMPTY);
const currentPaginationAtom = atom(
@@ -64,7 +70,7 @@ export const atomForCurrentPagination = () => {
return data;
},
(get, set, action: Pagination | typeof FIRST_PAGE | typeof LAST_PAGE) => {
(get, set, action: Action) => {
if (action === FIRST_PAGE) {
set(dataAtom, EMPTY);
} else if (action === LAST_PAGE) {
@@ -78,7 +84,7 @@ export const atomForCurrentPagination = () => {
}
);
currentPaginationAtom.onMount = (setAtom) => {
currentPaginationAtom.onMount = (setAtom): void => {
setAtom(FIRST_PAGE);
};

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// @ts-check
/** @type {import('tailwindcss').Config} */
module.exports = {

View File

@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// @ts-check
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
const base = require("./tailwind.config.cjs");
/** @type {import('tailwindcss').Config} */

View File

@@ -10,6 +10,9 @@
".storybook/main.ts",
"vite.config.ts",
".eslintrc.cjs",
"tailwind.config.cjs"
"postcss.config.cjs",
"tailwind.config.cjs",
"tailwind.templates.config.cjs",
"codegen.ts"
]
}