frontend: upgrade @tanstack/react-router

This commit is contained in:
Quentin Gliech
2024-03-18 15:09:23 +01:00
parent 09cd3f90d6
commit 90f4f98415
15 changed files with 112 additions and 84 deletions

View File

@@ -89,6 +89,10 @@ updates:
graphql-codegen:
patterns:
- "@graphql-codegen/*"
tanstack-router:
patterns:
- "@tanstack/react-router"
- "@tanstack/router-*"
types:
patterns:
- "@types/*"

View File

@@ -13,7 +13,7 @@
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-form": "^0.0.3",
"@tanstack/react-router": "^1.16.6",
"@tanstack/react-router": "^1.20.1",
"@types/ua-parser-js": "^0.7.39",
"@urql/core": "^4.2.3",
"@urql/devtools": "^2.0.3",
@@ -48,8 +48,8 @@
"@storybook/addon-essentials": "^7.6.17",
"@storybook/react": "^7.6.17",
"@storybook/react-vite": "^7.6.17",
"@tanstack/router-devtools": "^1.16.6",
"@tanstack/router-vite-plugin": "^1.16.5",
"@tanstack/router-devtools": "^1.20.1",
"@tanstack/router-vite-plugin": "^1.20.2",
"@testing-library/react": "^14.2.1",
"@types/node": "^20.11.24",
"@types/react": "^18.2.61",
@@ -8162,9 +8162,9 @@
}
},
"node_modules/@tanstack/react-router": {
"version": "1.16.6",
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.16.6.tgz",
"integrity": "sha512-d1Kjs38IF3bH7jKwihMBrdnh7BMVOHSNhJ9sltCiP4gLHcZkG7V9BwwJn5yL4V7YHIPNxdrJ3v4yrkvdrPJ0Ww==",
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.20.1.tgz",
"integrity": "sha512-WpWZ4rYC+L3DHCB4+lo9HPVoNkUy4yN9QL+1Z8QSYeUKG0ZAydrqUnL48YBKdSh3bp8FRh09R+74DTP0/lvxAw==",
"dependencies": {
"@tanstack/history": "1.15.13",
"@tanstack/react-store": "^0.2.1",
@@ -8201,13 +8201,15 @@
}
},
"node_modules/@tanstack/router-devtools": {
"version": "1.16.6",
"resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.16.6.tgz",
"integrity": "sha512-zjyLuStYA1TM4L1IfgQJ1ZCq36o3UVaLLCVmBBHukxbc6n2cKR2U11BXJW5RpkNZDyAPyGcPLEgJ2qcZCYSDcQ==",
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.20.1.tgz",
"integrity": "sha512-1t/IE6dR4rGNpdWVLl8G6DN31Uj+UUth6j9AhVox4lRA76O+/JRnpBuh/Q/59CUPN3dR5dY7vLyl96swr/1Nwg==",
"dev": true,
"dependencies": {
"@tanstack/react-router": "1.16.6",
"date-fns": "^2.29.1"
"@tanstack/react-router": "1.20.1",
"clsx": "^2.1.0",
"date-fns": "^2.29.1",
"goober": "^2.1.14"
},
"engines": {
"node": ">=12"
@@ -8238,9 +8240,9 @@
}
},
"node_modules/@tanstack/router-generator": {
"version": "1.16.5",
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.16.5.tgz",
"integrity": "sha512-np9+DASQvD4ff+FrCZ4XqRMGpVC6Y2213kma/X05mvo241yh0D5C6paUY7N7pSBPpuTlJbYKi+73cm/xRtK3Hg==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.20.0.tgz",
"integrity": "sha512-YkxVMi6q3K3V99Xo13dbP4fQDHxGUZi8Z5B7t4XZvwouAj7RDF8Tm8UcJVix8VLWaH4pt1idSXy185GWLTAiTw==",
"dev": true,
"dependencies": {
"prettier": "^3.1.1",
@@ -8255,12 +8257,12 @@
}
},
"node_modules/@tanstack/router-vite-plugin": {
"version": "1.16.5",
"resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.16.5.tgz",
"integrity": "sha512-rNfAuWIScl0KnjWOda5hzQYgHdwpLu1OljvqZa260UrCB6e32882X2Ci687+OUBfydhZT/V53XtQ+la7/AO5Rw==",
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.20.2.tgz",
"integrity": "sha512-lZ6fBwXszmzS0n9fbQUDdi0u4f6ZimDXIQhMjZEzqn9yB/IPloqN0ja0Bac78/5C7gJhsZ8YcgH8qRqqXYWGeg==",
"dev": true,
"dependencies": {
"@tanstack/router-generator": "1.16.5"
"@tanstack/router-generator": "1.20.0"
},
"engines": {
"node": ">=12"
@@ -11330,6 +11332,15 @@
"integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
"dev": true
},
"node_modules/clsx": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/coa": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
@@ -15212,6 +15223,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/goober": {
"version": "2.1.14",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz",
"integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==",
"dev": true,
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",

View File

@@ -21,7 +21,7 @@
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-form": "^0.0.3",
"@tanstack/react-router": "^1.16.6",
"@tanstack/react-router": "^1.20.1",
"@types/ua-parser-js": "^0.7.39",
"@urql/core": "^4.2.3",
"@urql/devtools": "^2.0.3",
@@ -56,8 +56,8 @@
"@storybook/addon-essentials": "^7.6.17",
"@storybook/react": "^7.6.17",
"@storybook/react-vite": "^7.6.17",
"@tanstack/router-devtools": "^1.16.6",
"@tanstack/router-vite-plugin": "^1.16.5",
"@tanstack/router-devtools": "^1.20.1",
"@tanstack/router-vite-plugin": "^1.20.2",
"@testing-library/react": "^14.2.1",
"@types/node": "^20.11.24",
"@types/react": "^18.2.61",

View File

@@ -12,7 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { LinkComponent, useLinkProps } from "@tanstack/react-router";
import {
UseLinkPropsOptions,
createLink,
useLinkProps,
} from "@tanstack/react-router";
import { Button } from "@vector-im/compound-web";
import { forwardRef } from "react";
@@ -23,24 +27,15 @@ type Props = {
destructive?: boolean;
};
export const ButtonLink: LinkComponent<Props> = forwardRef<
// XXX: createLink is broken, so we work around it by using useLinkProps directly
export const ButtonLink = forwardRef<
HTMLAnchorElement,
Parameters<typeof useLinkProps>[0] & Props
>(({ children, kind, size, destructive, Icon, ...props }, ref) => {
Props & UseLinkPropsOptions
>(({ children, ...props }, ref) => {
const linkProps = useLinkProps(props);
return (
<Button
as="a"
kind={kind}
size={size}
destructive={destructive}
disabled={props.disabled}
Icon={Icon}
ref={ref}
{...linkProps}
>
<Button as="a" {...linkProps} ref={ref}>
{children}
</Button>
);
}) as LinkComponent<Props>;
}) as ReturnType<typeof createLink<typeof Button>>;

View File

@@ -12,23 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { LinkComponent, useLinkProps } from "@tanstack/react-router";
import { createLink, useLinkProps } from "@tanstack/react-router";
import { Link as CompoundLink } from "@vector-im/compound-web";
import { forwardRef } from "react";
type Props = {
kind?: "primary" | "critical";
};
export const Link: LinkComponent<Props> = forwardRef<
HTMLAnchorElement,
Parameters<typeof useLinkProps>[0] & Props
>(({ children, kind, ...props }, ref) => {
export const Link: ReturnType<typeof createLink<typeof CompoundLink>> = ({
children,
...props
}: Parameters<typeof useLinkProps>[0]) => {
const linkProps = useLinkProps(props);
return (
<CompoundLink kind={kind} ref={ref} {...linkProps}>
{children}
</CompoundLink>
);
}) as LinkComponent<Props>;
return <CompoundLink {...linkProps}>{children}</CompoundLink>;
};

View File

@@ -12,9 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { LinkComponent, useLinkProps } from "@tanstack/react-router";
import {
UseLinkPropsOptions,
createLink,
useLinkProps,
} from "@tanstack/react-router";
import cx from "classnames";
import { forwardRef } from "react";
import { AnchorHTMLAttributes, forwardRef } from "react";
import { DeviceType } from "../../gql/graphql";
import ClientAvatar from "../Session/ClientAvatar";
@@ -26,28 +30,35 @@ export const Root: React.FC<React.PropsWithChildren> = ({ children }) => (
<section className={styles.sessionCardRoot}>{children}</section>
);
// XXX: createLink is broken, so we work around it by using useLinkProps directly
type BodyProps = React.PropsWithChildren<{
disabled?: boolean;
compact?: boolean;
}>;
export const LinkBody: LinkComponent = forwardRef<
export const LinkBody = forwardRef<
HTMLAnchorElement,
Parameters<typeof useLinkProps>[0] & BodyProps
BodyProps & UseLinkPropsOptions
>(({ children, disabled, compact, ...props }, ref) => {
const linkProps = useLinkProps({
className: cx(
styles.sessionCard,
compact && styles.compact,
disabled && styles.disabled,
),
...props,
});
const { className, ...linkProps } = useLinkProps({ disabled, ...props });
return (
<a ref={ref} {...linkProps}>
<a
className={cx(
className,
styles.sessionCard,
compact && styles.compact,
disabled && styles.disabled,
)}
{...linkProps}
ref={ref}
>
{children}
</a>
);
}) as LinkComponent;
}) as ReturnType<
typeof createLink<
React.FC<BodyProps & AnchorHTMLAttributes<HTMLAnchorElement>>
>
>;
export const Body: React.FC<BodyProps> = ({ children, compact, disabled }) => (
<div

View File

@@ -47,7 +47,7 @@ const BrowserSessionsOverview: React.FC<{
})}
</Body>
</div>
<Link to="/sessions/browsers">
<Link to="/sessions/browsers" search={{ first: 6 }}>
{t("frontend.browser_sessions_overview.view_all_button")}
</Link>
</Block>

View File

@@ -22,7 +22,7 @@ exports[`BrowserSessionsOverview > renders with no browser sessions 1`] = `
<a
class="_link_1mzip_17"
data-kind="primary"
href="/sessions/browsers"
href="/sessions/browsers?first=6"
rel="noreferrer noopener"
>
View all
@@ -53,7 +53,7 @@ exports[`BrowserSessionsOverview > renders with sessions 1`] = `
<a
class="_link_1mzip_17"
data-kind="primary"
href="/sessions/browsers"
href="/sessions/browsers?first=6"
rel="noreferrer noopener"
>
View all

View File

@@ -5,13 +5,14 @@ exports[`<CompatSession /> > renders a finished session 1`] = `
className="_sessionCardRoot_e2909e"
>
<a
aria-disabled={true}
className="_sessionCard_e2909e _disabled_e2909e"
href="/sessions/session-id"
onClick={[Function]}
onFocus={[Function]}
onMouseEnter={[Function]}
onMouseLeave={[Function]}
onTouchStart={[Function]}
role="link"
style={{}}
>
<header

View File

@@ -5,13 +5,14 @@ exports[`<OAuth2Session /> > renders a finished session 1`] = `
className="_sessionCardRoot_e2909e"
>
<a
aria-disabled={true}
className="_sessionCard_e2909e _disabled_e2909e"
href="/sessions/session-id"
onClick={[Function]}
onFocus={[Function]}
onMouseEnter={[Function]}
onMouseLeave={[Function]}
onTouchStart={[Function]}
role="link"
style={{}}
>
<header
@@ -198,13 +199,14 @@ exports[`<OAuth2Session /> > renders correct icon for a native session 1`] = `
className="_sessionCardRoot_e2909e"
>
<a
aria-disabled={true}
className="_sessionCard_e2909e _disabled_e2909e"
href="/sessions/session-id"
onClick={[Function]}
onFocus={[Function]}
onMouseEnter={[Function]}
onMouseLeave={[Function]}
onTouchStart={[Function]}
role="link"
style={{}}
>
<header

View File

@@ -49,6 +49,9 @@ const actionSchema = z
])
.catch({ action: undefined });
// XXX: we probably shouldn't have to specify the search parameters on /sessions/
const PAGE_SIZE = 6;
export const Route = createRootRouteWithContext<{
client: Client;
}>()({
@@ -62,7 +65,7 @@ export const Route = createRootRouteWithContext<{
case "sessions_list":
case "org.matrix.sessions_list":
throw redirect({ to: "/sessions" });
throw redirect({ to: "/sessions/", search: { last: PAGE_SIZE } });
case "session_view":
case "org.matrix.session_view":
@@ -71,7 +74,7 @@ export const Route = createRootRouteWithContext<{
to: "/devices/$id",
params: { id: search.device_id },
});
throw redirect({ to: "/sessions" });
throw redirect({ to: "/sessions/", search: { last: PAGE_SIZE } });
case "session_end":
case "org.matrix.session_end":
@@ -80,11 +83,11 @@ export const Route = createRootRouteWithContext<{
to: "/devices/$id",
params: { id: search.device_id },
});
throw redirect({ to: "/sessions" });
throw redirect({ to: "/sessions/", search: { last: PAGE_SIZE } });
case "org.matrix.cross_signing_reset":
throw redirect({
to: "/reset-cross-signing",
to: "/reset-cross-signing/",
search: { deepLink: true },
});
}

View File

@@ -66,7 +66,7 @@ function NotFound(): React.ReactElement {
title={t("frontend.session_detail.alert.title", { deviceId: id })}
>
{t("frontend.session_detail.alert.text")}
<Link from={Route.fullPath} to="..">
<Link from={Route.fullPath} to=".." search={{ first: 6 }}>
{t("frontend.session_detail.alert.button")}
</Link>
</Alert>

View File

@@ -133,7 +133,7 @@ function BrowserSessions(): React.ReactElement {
size="sm"
disabled={!forwardPage}
to={Route.fullPath}
search={forwardPage}
search={forwardPage || pagination}
>
{t("common.previous")}
</ButtonLink>
@@ -146,7 +146,7 @@ function BrowserSessions(): React.ReactElement {
size="sm"
disabled={!backwardPage}
to={Route.fullPath}
search={backwardPage}
search={backwardPage || pagination}
>
{t("common.next")}
</ButtonLink>

View File

@@ -176,7 +176,7 @@ function Sessions(): React.ReactElement {
size="sm"
disabled={!forwardPage}
to={Route.fullPath}
search={forwardPage}
search={forwardPage || pagination}
>
{t("common.previous")}
</ButtonLink>
@@ -189,7 +189,7 @@ function Sessions(): React.ReactElement {
size="sm"
disabled={!backwardPage}
to={Route.fullPath}
search={backwardPage}
search={backwardPage || pagination}
>
{t("common.next")}
</ButtonLink>

View File

@@ -86,7 +86,9 @@ function NotFound(): React.ReactElement {
title={t("frontend.session_detail.alert.title", { deviceId })}
>
{t("frontend.session_detail.alert.text")}
<Link to="/sessions">{t("frontend.session_detail.alert.button")}</Link>
<Link to="/sessions" search={{ first: 6 }}>
{t("frontend.session_detail.alert.button")}
</Link>
</Alert>
</Layout>
);