Reformat frontend code, fix a few new linting errors
This commit is contained in:
@@ -46,7 +46,8 @@
|
|||||||
"noUnusedTemplateLiteral": "error",
|
"noUnusedTemplateLiteral": "error",
|
||||||
"useNumberNamespace": "error",
|
"useNumberNamespace": "error",
|
||||||
"noInferrableTypes": "error",
|
"noInferrableTypes": "error",
|
||||||
"noUselessElse": "error"
|
"noUselessElse": "error",
|
||||||
|
"noDescendingSpecificity": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ const AccountDeleteButton: React.FC<Props> = (props) => {
|
|||||||
mutationFn: ({
|
mutationFn: ({
|
||||||
password,
|
password,
|
||||||
hsErase,
|
hsErase,
|
||||||
}: { password: string | null; hsErase: boolean }) =>
|
}: {
|
||||||
|
password: string | null;
|
||||||
|
hsErase: boolean;
|
||||||
|
}) =>
|
||||||
graphqlRequest({
|
graphqlRequest({
|
||||||
query: MUTATION,
|
query: MUTATION,
|
||||||
variables: { password, hsErase },
|
variables: { password, hsErase },
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import { createLink } from "@tanstack/react-router";
|
import { createLink } from "@tanstack/react-router";
|
||||||
import { Button } from "@vector-im/compound-web";
|
import { Button } from "@vector-im/compound-web";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { type PropsWithChildren, forwardRef } from "react";
|
import { forwardRef, type PropsWithChildren } from "react";
|
||||||
import styles from "./ButtonLink.module.css";
|
import styles from "./ButtonLink.module.css";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
|
|
||||||
/* Cap the block size */
|
/* Cap the block size */
|
||||||
max-block-size: calc(100vh - var(--cpd-space-4x));
|
max-block-size: calc(100vh - var(--cpd-space-4x));
|
||||||
|
/* biome-ignore lint/suspicious/noDuplicateProperties: this isn't a real duplicate */
|
||||||
max-block-size: calc(100svh - var(--cpd-space-4x));
|
max-block-size: calc(100svh - var(--cpd-space-4x));
|
||||||
|
|
||||||
/* Drawer comes in the Android style by default */
|
/* Drawer comes in the Android style by default */
|
||||||
|
|||||||
@@ -102,4 +102,4 @@ export const Title: React.FC<PropsWithChildren> = ({ children }) => (
|
|||||||
<DialogTitle className={styles.title}>{children}</DialogTitle>
|
<DialogTitle className={styles.title}>{children}</DialogTitle>
|
||||||
);
|
);
|
||||||
|
|
||||||
export { Description, Close } from "@radix-ui/react-dialog";
|
export { Close, Description } from "@radix-ui/react-dialog";
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
export { Close, Dialog, Title, Description } from "./Dialog";
|
export { Close, Description, Dialog, Title } from "./Dialog";
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
/* Fallback for browsers that do not support 100svh */
|
/* Fallback for browsers that do not support 100svh */
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
/* biome-ignore lint/suspicious/noDuplicateProperties: this isn't a real duplicate */
|
||||||
min-height: 100svh;
|
min-height: 100svh;
|
||||||
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
/* Fallback for browsers that do not support 100svh */
|
/* Fallback for browsers that do not support 100svh */
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
/* biome-ignore lint/suspicious/noDuplicateProperties: this isn't a real duplicate */
|
||||||
min-height: 100svh;
|
min-height: 100svh;
|
||||||
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ const PaginationControls: React.FC<Props> = ({
|
|||||||
{t("common.previous")}
|
{t("common.previous")}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
{count !== undefined ? (
|
{count !== undefined
|
||||||
<>{t("frontend.pagination_controls.total", { totalCount: count })}</>
|
? t("frontend.pagination_controls.total", { totalCount: count })
|
||||||
) : null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
// biome-ignore-all lint/a11y/useFocusableInteractive: this is a false positive
|
||||||
|
// biome-ignore-all lint/a11y/useAriaPropsForRole: this is a false positive
|
||||||
|
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { forwardRef } from "react";
|
import { forwardRef } from "react";
|
||||||
|
|
||||||
@@ -14,7 +17,6 @@ type Props = {
|
|||||||
|
|
||||||
const Separator = forwardRef<HTMLDivElement, Props>(
|
const Separator = forwardRef<HTMLDivElement, Props>(
|
||||||
({ kind, className, ...props }: Props, ref) => (
|
({ kind, className, ...props }: Props, ref) => (
|
||||||
// biome-ignore lint/a11y/useFocusableInteractive: this is a false positive
|
|
||||||
<div
|
<div
|
||||||
aria-orientation="horizontal"
|
aria-orientation="horizontal"
|
||||||
role="separator"
|
role="separator"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { composeStory } from "@storybook/react-vite";
|
|||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import Meta, { Unknown, Pc, Mobile, Tablet } from "./DeviceTypeIcon.stories";
|
import Meta, { Mobile, Pc, Tablet, Unknown } from "./DeviceTypeIcon.stories";
|
||||||
|
|
||||||
describe("<DeviceTypeIcon />", () => {
|
describe("<DeviceTypeIcon />", () => {
|
||||||
it("renders unknown device type", () => {
|
it("renders unknown device type", () => {
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
|
||||||
LinkBody,
|
|
||||||
Body,
|
|
||||||
Header,
|
|
||||||
Name,
|
|
||||||
Client,
|
|
||||||
Metadata,
|
|
||||||
Info,
|
|
||||||
Action,
|
Action,
|
||||||
|
Body,
|
||||||
|
Client,
|
||||||
|
Header,
|
||||||
|
Info,
|
||||||
|
LinkBody,
|
||||||
|
Metadata,
|
||||||
|
Name,
|
||||||
|
Root,
|
||||||
} from "./SessionCard";
|
} from "./SessionCard";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
import type { UseMutationResult } from "@tanstack/react-query";
|
||||||
import IconEdit from "@vector-im/compound-design-tokens/assets/web/icons/edit";
|
import IconEdit from "@vector-im/compound-design-tokens/assets/web/icons/edit";
|
||||||
import { Button, Form, IconButton, Tooltip } from "@vector-im/compound-web";
|
import { Button, Form, IconButton, Tooltip } from "@vector-im/compound-web";
|
||||||
import {
|
import {
|
||||||
@@ -11,12 +12,10 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import * as Dialog from "../Dialog";
|
import * as Dialog from "../Dialog";
|
||||||
import LoadingSpinner from "../LoadingSpinner";
|
import LoadingSpinner from "../LoadingSpinner";
|
||||||
|
|
||||||
import type { UseMutationResult } from "@tanstack/react-query";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
// This needs to be its own component because else props and refs aren't passed properly in the trigger
|
// This needs to be its own component because else props and refs aren't passed properly in the trigger
|
||||||
const EditButton = forwardRef<
|
const EditButton = forwardRef<
|
||||||
HTMLButtonElement,
|
HTMLButtonElement,
|
||||||
|
|||||||
@@ -6,12 +6,10 @@
|
|||||||
|
|
||||||
// @vitest-environment happy-dom
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { TooltipProvider } from "@vector-im/compound-web";
|
||||||
import { beforeAll, describe, expect, it } from "vitest";
|
import { beforeAll, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { makeFragmentData } from "../../gql";
|
import { makeFragmentData } from "../../gql";
|
||||||
import { mockLocale } from "../../test-utils/mockLocale";
|
import { mockLocale } from "../../test-utils/mockLocale";
|
||||||
|
|
||||||
import { TooltipProvider } from "@vector-im/compound-web";
|
|
||||||
import render from "../../test-utils/render";
|
import render from "../../test-utils/render";
|
||||||
import OAuth2SessionDetail, { FRAGMENT } from "./OAuth2SessionDetail";
|
import OAuth2SessionDetail, { FRAGMENT } from "./OAuth2SessionDetail";
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ const UserEmail: React.FC<{
|
|||||||
|
|
||||||
const onRemoveClick = useCallback(
|
const onRemoveClick = useCallback(
|
||||||
async (_e: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
|
async (_e: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
|
||||||
let password = undefined;
|
let password: string | undefined;
|
||||||
if (shouldPromptPassword) {
|
if (shouldPromptPassword) {
|
||||||
password = await promptPassword();
|
password = await promptPassword();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,9 @@ export const CONFIG_FRAGMENT = graphql(/* GraphQL */ `
|
|||||||
|
|
||||||
const ADD_EMAIL_MUTATION = graphql(/* GraphQL */ `
|
const ADD_EMAIL_MUTATION = graphql(/* GraphQL */ `
|
||||||
mutation AddEmail($email: String!, $password: String, $language: String!) {
|
mutation AddEmail($email: String!, $password: String, $language: String!) {
|
||||||
startEmailAuthentication(input: {
|
startEmailAuthentication(
|
||||||
email: $email,
|
input: { email: $email, password: $password, language: $language }
|
||||||
password: $password,
|
) {
|
||||||
language: $language
|
|
||||||
}) {
|
|
||||||
status
|
status
|
||||||
violations
|
violations
|
||||||
authentication {
|
authentication {
|
||||||
@@ -64,7 +62,11 @@ const AddEmailForm: React.FC<{
|
|||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
language,
|
language,
|
||||||
}: { email: string; password?: string; language: string }) =>
|
}: {
|
||||||
|
email: string;
|
||||||
|
password?: string;
|
||||||
|
language: string;
|
||||||
|
}) =>
|
||||||
graphqlRequest({
|
graphqlRequest({
|
||||||
query: ADD_EMAIL_MUTATION,
|
query: ADD_EMAIL_MUTATION,
|
||||||
variables: { email, password, language },
|
variables: { email, password, language },
|
||||||
@@ -92,7 +94,7 @@ const AddEmailForm: React.FC<{
|
|||||||
|
|
||||||
const formData = new FormData(e.currentTarget);
|
const formData = new FormData(e.currentTarget);
|
||||||
const email = formData.get("input") as string;
|
const email = formData.get("input") as string;
|
||||||
let password = undefined;
|
let password: string | undefined;
|
||||||
if (shouldPromptPassword) {
|
if (shouldPromptPassword) {
|
||||||
password = await promptPassword();
|
password = await promptPassword();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ type Documents = {
|
|||||||
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n": typeof types.SetDisplayNameDocument,
|
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n": typeof types.SetDisplayNameDocument,
|
||||||
"\n fragment AddEmailForm_user on User {\n hasPassword\n }\n": typeof types.AddEmailForm_UserFragmentDoc,
|
"\n fragment AddEmailForm_user on User {\n hasPassword\n }\n": typeof types.AddEmailForm_UserFragmentDoc,
|
||||||
"\n fragment AddEmailForm_siteConfig on SiteConfig {\n passwordLoginEnabled\n }\n": typeof types.AddEmailForm_SiteConfigFragmentDoc,
|
"\n fragment AddEmailForm_siteConfig on SiteConfig {\n passwordLoginEnabled\n }\n": typeof types.AddEmailForm_SiteConfigFragmentDoc,
|
||||||
"\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(input: {\n email: $email,\n password: $password,\n language: $language\n }) {\n status\n violations\n authentication {\n id\n }\n }\n }\n": typeof types.AddEmailDocument,
|
"\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(\n input: { email: $email, password: $password, language: $language }\n ) {\n status\n violations\n authentication {\n id\n }\n }\n }\n": typeof types.AddEmailDocument,
|
||||||
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": typeof types.UserEmailListDocument,
|
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": typeof types.UserEmailListDocument,
|
||||||
"\n fragment UserEmailList_user on User {\n hasPassword\n }\n": typeof types.UserEmailList_UserFragmentDoc,
|
"\n fragment UserEmailList_user on User {\n hasPassword\n }\n": typeof types.UserEmailList_UserFragmentDoc,
|
||||||
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n }\n": typeof types.UserEmailList_SiteConfigFragmentDoc,
|
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n }\n": typeof types.UserEmailList_SiteConfigFragmentDoc,
|
||||||
@@ -101,7 +101,7 @@ const documents: Documents = {
|
|||||||
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n": types.SetDisplayNameDocument,
|
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n": types.SetDisplayNameDocument,
|
||||||
"\n fragment AddEmailForm_user on User {\n hasPassword\n }\n": types.AddEmailForm_UserFragmentDoc,
|
"\n fragment AddEmailForm_user on User {\n hasPassword\n }\n": types.AddEmailForm_UserFragmentDoc,
|
||||||
"\n fragment AddEmailForm_siteConfig on SiteConfig {\n passwordLoginEnabled\n }\n": types.AddEmailForm_SiteConfigFragmentDoc,
|
"\n fragment AddEmailForm_siteConfig on SiteConfig {\n passwordLoginEnabled\n }\n": types.AddEmailForm_SiteConfigFragmentDoc,
|
||||||
"\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(input: {\n email: $email,\n password: $password,\n language: $language\n }) {\n status\n violations\n authentication {\n id\n }\n }\n }\n": types.AddEmailDocument,
|
"\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(\n input: { email: $email, password: $password, language: $language }\n ) {\n status\n violations\n authentication {\n id\n }\n }\n }\n": types.AddEmailDocument,
|
||||||
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": types.UserEmailListDocument,
|
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": types.UserEmailListDocument,
|
||||||
"\n fragment UserEmailList_user on User {\n hasPassword\n }\n": types.UserEmailList_UserFragmentDoc,
|
"\n fragment UserEmailList_user on User {\n hasPassword\n }\n": types.UserEmailList_UserFragmentDoc,
|
||||||
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n }\n": types.UserEmailList_SiteConfigFragmentDoc,
|
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n }\n": types.UserEmailList_SiteConfigFragmentDoc,
|
||||||
@@ -248,7 +248,7 @@ export function graphql(source: "\n fragment AddEmailForm_siteConfig on SiteCon
|
|||||||
/**
|
/**
|
||||||
* 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(source: "\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(input: {\n email: $email,\n password: $password,\n language: $language\n }) {\n status\n violations\n authentication {\n id\n }\n }\n }\n"): typeof import('./graphql').AddEmailDocument;
|
export function graphql(source: "\n mutation AddEmail($email: String!, $password: String, $language: String!) {\n startEmailAuthentication(\n input: { email: $email, password: $password, language: $language }\n ) {\n status\n violations\n authentication {\n id\n }\n }\n }\n"): typeof import('./graphql').AddEmailDocument;
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
import {
|
import {
|
||||||
type BackendModule,
|
type BackendModule,
|
||||||
type InitOptions,
|
type InitOptions,
|
||||||
|
default as i18n,
|
||||||
type LanguageDetectorModule,
|
type LanguageDetectorModule,
|
||||||
type ReadCallback,
|
type ReadCallback,
|
||||||
type ResourceKey,
|
type ResourceKey,
|
||||||
default as i18n,
|
|
||||||
} from "i18next";
|
} from "i18next";
|
||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
import type { QueryClient } from "@tanstack/react-query";
|
import type { QueryClient } from "@tanstack/react-query";
|
||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
import {
|
import {
|
||||||
|
createRootRouteWithContext,
|
||||||
type ErrorRouteComponent,
|
type ErrorRouteComponent,
|
||||||
Outlet,
|
Outlet,
|
||||||
createRootRouteWithContext,
|
|
||||||
} from "@tanstack/react-router";
|
} from "@tanstack/react-router";
|
||||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||||
import GenericError from "../components/GenericError";
|
import GenericError from "../components/GenericError";
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ function Index(): React.ReactElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
{/* Only display this section if the user can add email addresses to their
|
{/* Only display this section if the user can add email addresses to their
|
||||||
account *or* if they have any existing email addresses */}
|
account *or* if they have any existing email addresses */}
|
||||||
@@ -199,10 +198,7 @@ function Index(): React.ReactElement {
|
|||||||
defaultOpen
|
defaultOpen
|
||||||
title={t("frontend.account.contact_info")}
|
title={t("frontend.account.contact_info")}
|
||||||
>
|
>
|
||||||
<UserEmailList
|
<UserEmailList user={viewerSession.user} siteConfig={siteConfig} />
|
||||||
user={viewerSession.user}
|
|
||||||
siteConfig={siteConfig}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{siteConfig.emailChangeAllowed && (
|
{siteConfig.emailChangeAllowed && (
|
||||||
<AddEmailForm
|
<AddEmailForm
|
||||||
@@ -255,6 +251,5 @@ function Index(): React.ReactElement {
|
|||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ export const Route = createFileRoute({
|
|||||||
|
|
||||||
preload(planManagementIframeUri, { as: "document" });
|
preload(planManagementIframeUri, { as: "document" });
|
||||||
},
|
},
|
||||||
component: Plan,
|
component: RouteComponent,
|
||||||
});
|
});
|
||||||
|
|
||||||
function Plan(): React.ReactElement {
|
function RouteComponent(): React.ReactElement {
|
||||||
const result = useSuspenseQuery(query);
|
const result = useSuspenseQuery(query);
|
||||||
const { planManagementIframeUri } = result.data.siteConfig;
|
const { planManagementIframeUri } = result.data.siteConfig;
|
||||||
|
|
||||||
@@ -45,6 +45,14 @@ function Plan(): React.ReactElement {
|
|||||||
return <Navigate to="/" replace />;
|
return <Navigate to="/" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return <Plan planManagementIframeUri={planManagementIframeUri} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Plan({
|
||||||
|
planManagementIframeUri,
|
||||||
|
}: {
|
||||||
|
planManagementIframeUri: string;
|
||||||
|
}): React.ReactElement {
|
||||||
const ref = useRef<HTMLIFrameElement>(null);
|
const ref = useRef<HTMLIFrameElement>(null);
|
||||||
|
|
||||||
// Query the size of the iframe content and set the height
|
// Query the size of the iframe content and set the height
|
||||||
@@ -79,16 +87,8 @@ function Plan(): React.ReactElement {
|
|||||||
[calculateHeight],
|
[calculateHeight],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const attachObserver = useCallback(
|
||||||
const iframe = ref.current;
|
(iframe: HTMLIFrameElement) => {
|
||||||
if (iframe) {
|
|
||||||
attachObserver(iframe);
|
|
||||||
}
|
|
||||||
// Cleanup observer when the component unmounts
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, [observer]);
|
|
||||||
|
|
||||||
const attachObserver = (iframe: HTMLIFrameElement) => {
|
|
||||||
const iframeBody = iframe.contentWindow?.document.body;
|
const iframeBody = iframe.contentWindow?.document.body;
|
||||||
if (!iframeBody) {
|
if (!iframeBody) {
|
||||||
return;
|
return;
|
||||||
@@ -101,7 +101,18 @@ function Plan(): React.ReactElement {
|
|||||||
subtree: true,
|
subtree: true,
|
||||||
attributes: true,
|
attributes: true,
|
||||||
});
|
});
|
||||||
};
|
},
|
||||||
|
[calculateHeight, observer],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const iframe = ref.current;
|
||||||
|
if (iframe) {
|
||||||
|
attachObserver(iframe);
|
||||||
|
}
|
||||||
|
// Cleanup observer when the component unmounts
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [observer, attachObserver]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { queryOptions } from "@tanstack/react-query";
|
|
||||||
import { notFound } from "@tanstack/react-router";
|
import { notFound } from "@tanstack/react-router";
|
||||||
import { H3 } from "@vector-im/compound-web";
|
import { H3 } from "@vector-im/compound-web";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -19,11 +18,11 @@ import Separator from "../components/Separator";
|
|||||||
import BrowserSessionsOverview from "../components/UserSessionsOverview/BrowserSessionsOverview";
|
import BrowserSessionsOverview from "../components/UserSessionsOverview/BrowserSessionsOverview";
|
||||||
import { graphql } from "../gql";
|
import { graphql } from "../gql";
|
||||||
import { graphqlRequest } from "../graphql";
|
import { graphqlRequest } from "../graphql";
|
||||||
import { usePages } from "../pagination";
|
|
||||||
import {
|
import {
|
||||||
type AnyPagination,
|
type AnyPagination,
|
||||||
anyPaginationSchema,
|
anyPaginationSchema,
|
||||||
normalizePagination,
|
normalizePagination,
|
||||||
|
usePages,
|
||||||
} from "../pagination";
|
} from "../pagination";
|
||||||
import { getNinetyDaysAgo } from "../utils/dates";
|
import { getNinetyDaysAgo } from "../utils/dates";
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
|
import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { Outlet, notFound } from "@tanstack/react-router";
|
import { notFound, Outlet } from "@tanstack/react-router";
|
||||||
import { Heading } from "@vector-im/compound-web";
|
import { Heading } from "@vector-im/compound-web";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Layout from "../components/Layout";
|
import Layout from "../components/Layout";
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { queryOptions } from "@tanstack/react-query";
|
|
||||||
import { notFound } from "@tanstack/react-router";
|
import { notFound } from "@tanstack/react-router";
|
||||||
import OAuth2ClientDetail from "../components/Client/OAuth2ClientDetail";
|
import OAuth2ClientDetail from "../components/Client/OAuth2ClientDetail";
|
||||||
import Layout from "../components/Layout";
|
import Layout from "../components/Layout";
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
import { notFound, redirect } from "@tanstack/react-router";
|
import { notFound, redirect } from "@tanstack/react-router";
|
||||||
import { Alert } from "@vector-im/compound-web";
|
import { Alert } from "@vector-im/compound-web";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { queryOptions } from "@tanstack/react-query";
|
|
||||||
import Layout from "../components/Layout";
|
import Layout from "../components/Layout";
|
||||||
import { Link } from "../components/Link";
|
import { Link } from "../components/Link";
|
||||||
import { graphql } from "../gql";
|
import { graphql } from "../gql";
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
|
import {
|
||||||
import { queryOptions } from "@tanstack/react-query";
|
queryOptions,
|
||||||
import { useNavigate, useSearch } from "@tanstack/react-router";
|
useMutation,
|
||||||
import { notFound } from "@tanstack/react-router";
|
useSuspenseQuery,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
|
import { notFound, useNavigate, useSearch } from "@tanstack/react-router";
|
||||||
import IconErrorSolid from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
import IconErrorSolid from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
||||||
import IconLockSolid from "@vector-im/compound-design-tokens/assets/web/icons/lock-solid";
|
import IconLockSolid from "@vector-im/compound-design-tokens/assets/web/icons/lock-solid";
|
||||||
import { Alert, Button, Form } from "@vector-im/compound-web";
|
import { Alert, Button, Form } from "@vector-im/compound-web";
|
||||||
@@ -19,8 +21,7 @@ import Layout from "../components/Layout";
|
|||||||
import LoadingSpinner from "../components/LoadingSpinner";
|
import LoadingSpinner from "../components/LoadingSpinner";
|
||||||
import PageHeading from "../components/PageHeading";
|
import PageHeading from "../components/PageHeading";
|
||||||
import PasswordCreationDoubleInput from "../components/PasswordCreationDoubleInput";
|
import PasswordCreationDoubleInput from "../components/PasswordCreationDoubleInput";
|
||||||
import { type FragmentType, useFragment } from "../gql";
|
import { type FragmentType, graphql, useFragment } from "../gql";
|
||||||
import { graphql } from "../gql";
|
|
||||||
import { graphqlRequest } from "../graphql";
|
import { graphqlRequest } from "../graphql";
|
||||||
import { translateSetPasswordError } from "../i18n/password_changes";
|
import { translateSetPasswordError } from "../i18n/password_changes";
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
import { type ErrorComponentProps, Outlet } from "@tanstack/react-router";
|
import { type ErrorComponentProps, Outlet } from "@tanstack/react-router";
|
||||||
import IconErrorSolid from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
import IconErrorSolid from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
||||||
import { Button, Text } from "@vector-im/compound-web";
|
import { Button, Text } from "@vector-im/compound-web";
|
||||||
import * as v from "valibot";
|
|
||||||
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import * as v from "valibot";
|
||||||
import Layout from "../components/Layout";
|
import Layout from "../components/Layout";
|
||||||
import PageHeading from "../components/PageHeading";
|
import PageHeading from "../components/PageHeading";
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RouterContextProvider,
|
|
||||||
createMemoryHistory,
|
createMemoryHistory,
|
||||||
createRootRoute,
|
createRootRoute,
|
||||||
createRoute,
|
createRoute,
|
||||||
createRouter,
|
createRouter,
|
||||||
matchContext,
|
matchContext,
|
||||||
|
RouterContextProvider,
|
||||||
useRouterState,
|
useRouterState,
|
||||||
} from "@tanstack/react-router";
|
} from "@tanstack/react-router";
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
RouterProvider,
|
|
||||||
createHashHistory,
|
createHashHistory,
|
||||||
createRouter,
|
createRouter,
|
||||||
|
RouterProvider,
|
||||||
} from "@tanstack/react-router";
|
} from "@tanstack/react-router";
|
||||||
import { TooltipProvider } from "@vector-im/compound-web";
|
import { TooltipProvider } from "@vector-im/compound-web";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||||
import { HttpResponse, delay } from "msw";
|
import { delay, HttpResponse } from "msw";
|
||||||
import {
|
import {
|
||||||
mockAllowCrossSigningResetMutation,
|
mockAllowCrossSigningResetMutation,
|
||||||
mockCurrentViewerQuery,
|
mockCurrentViewerQuery,
|
||||||
|
|||||||
@@ -4,8 +4,11 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";
|
import {
|
||||||
import { createRouter } from "@tanstack/react-router";
|
createMemoryHistory,
|
||||||
|
createRouter,
|
||||||
|
RouterProvider,
|
||||||
|
} from "@tanstack/react-router";
|
||||||
import { type RenderResult, render } from "@testing-library/react";
|
import { type RenderResult, render } from "@testing-library/react";
|
||||||
import { TooltipProvider } from "@vector-im/compound-web";
|
import { TooltipProvider } from "@vector-im/compound-web";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
|
|||||||
Reference in New Issue
Block a user