fix: suppress date and button hydration warnings
This commit is contained in:
parent
0ad578e651
commit
f2747ada94
@ -7,6 +7,7 @@ export interface AttributeProps {
|
|||||||
value: string;
|
value: string;
|
||||||
isCopyable?: boolean;
|
isCopyable?: boolean;
|
||||||
link?: string;
|
link?: string;
|
||||||
|
suppressHydrationWarning?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Attribute({
|
export default function Attribute({
|
||||||
@ -14,6 +15,7 @@ export default function Attribute({
|
|||||||
value,
|
value,
|
||||||
link,
|
link,
|
||||||
isCopyable,
|
isCopyable,
|
||||||
|
suppressHydrationWarning,
|
||||||
}: AttributeProps) {
|
}: AttributeProps) {
|
||||||
return (
|
return (
|
||||||
<dl className="flex items-center w-full gap-x-1">
|
<dl className="flex items-center w-full gap-x-1">
|
||||||
@ -27,6 +29,7 @@ export default function Attribute({
|
|||||||
)}
|
)}
|
||||||
</dt>
|
</dt>
|
||||||
<dd
|
<dd
|
||||||
|
suppressHydrationWarning={suppressHydrationWarning}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-lg truncate w-full px-2.5 py-1 text-sm',
|
'rounded-lg truncate w-full px-2.5 py-1 text-sm',
|
||||||
'flex items-center gap-x-1',
|
'flex items-center gap-x-1',
|
||||||
@ -54,7 +57,12 @@ export default function Attribute({
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="truncate">{value}</p>
|
<p
|
||||||
|
suppressHydrationWarning={suppressHydrationWarning}
|
||||||
|
className="truncate"
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</p>
|
||||||
<Check className="h-4.5 w-4.5 p-1 hidden data-[copied]:block" />
|
<Check className="h-4.5 w-4.5 p-1 hidden data-[copied]:block" />
|
||||||
<Copy className="h-4.5 w-4.5 p-1 block data-[copied]:hidden" />
|
<Copy className="h-4.5 w-4.5 p-1 block data-[copied]:hidden" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -7,13 +7,13 @@ import {
|
|||||||
} from 'react-router';
|
} from 'react-router';
|
||||||
import Button from '~/components/Button';
|
import Button from '~/components/Button';
|
||||||
import Card from '~/components/Card';
|
import Card from '~/components/Card';
|
||||||
import Code from '~/components/Code';
|
|
||||||
import Footer from '~/components/Footer';
|
import Footer from '~/components/Footer';
|
||||||
import Header from '~/components/Header';
|
import Header from '~/components/Header';
|
||||||
import type { LoadContext } from '~/server';
|
import type { LoadContext } from '~/server';
|
||||||
import { Capabilities } from '~/server/web/roles';
|
import { Capabilities } from '~/server/web/roles';
|
||||||
import { User } from '~/types';
|
import { User } from '~/types';
|
||||||
import log from '~/utils/log';
|
import log from '~/utils/log';
|
||||||
|
import toast from '~/utils/toast';
|
||||||
|
|
||||||
// This loads the bare minimum for the application to function
|
// This loads the bare minimum for the application to function
|
||||||
// So we know that if context fails to load then well, oops?
|
// So we know that if context fails to load then well, oops?
|
||||||
@ -122,7 +122,7 @@ export default function Shell() {
|
|||||||
<>
|
<>
|
||||||
<Header {...data} />
|
<Header {...data} />
|
||||||
{/* Always show the outlet if we are onboarding */}
|
{/* Always show the outlet if we are onboarding */}
|
||||||
{(data.onboarding ? true : data.uiAccess) ? (
|
{(data.onboarding ? true : !data.uiAccess) ? (
|
||||||
<Outlet />
|
<Outlet />
|
||||||
) : (
|
) : (
|
||||||
<Card className="mx-auto w-fit mt-24">
|
<Card className="mx-auto w-fit mt-24">
|
||||||
@ -134,11 +134,21 @@ export default function Shell() {
|
|||||||
Connect to Tailscale with your devices to access this Tailnet. Use
|
Connect to Tailscale with your devices to access this Tailnet. Use
|
||||||
this command to help you get started:
|
this command to help you get started:
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
<Button className="pointer-events-none text-md hover:bg-initial focus:ring-0">
|
<Button
|
||||||
<Code className="pointer-events-auto bg-transparent" isCopyable>
|
className="flex text-md font-mono"
|
||||||
|
onPress={async () => {
|
||||||
|
await navigator.clipboard.writeText(
|
||||||
|
`tailscale up --login-server=${data.url}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
toast('Copied to clipboard');
|
||||||
|
}}
|
||||||
|
>
|
||||||
tailscale up --login-server={data.url}
|
tailscale up --login-server={data.url}
|
||||||
</Code>
|
|
||||||
</Button>
|
</Button>
|
||||||
|
<p className="text-xs mt-1 opacity-50 text-center">
|
||||||
|
Click this button to copy the command.
|
||||||
|
</p>
|
||||||
<p className="mt-4 text-sm opacity-50">
|
<p className="mt-4 text-sm opacity-50">
|
||||||
Your account does not have access to the UI. Please contact your
|
Your account does not have access to the UI. Please contact your
|
||||||
administrator if you believe this is a mistake.
|
administrator if you believe this is a mistake.
|
||||||
|
|||||||
@ -180,7 +180,7 @@ export default function MachineRow({
|
|||||||
isOnline={machine.online && !expired}
|
isOnline={machine.online && !expired}
|
||||||
className="w-4 h-4"
|
className="w-4 h-4"
|
||||||
/>
|
/>
|
||||||
<p>
|
<p suppressHydrationWarning>
|
||||||
{machine.online && !expired
|
{machine.online && !expired
|
||||||
? 'Connected'
|
? 'Connected'
|
||||||
: new Date(machine.lastSeen).toLocaleString()}
|
: new Date(machine.lastSeen).toLocaleString()}
|
||||||
|
|||||||
@ -310,14 +310,17 @@ export default function Page() {
|
|||||||
<Attribute name="Hostname" value={machine.name} />
|
<Attribute name="Hostname" value={machine.name} />
|
||||||
<Attribute isCopyable name="Node Key" value={machine.nodeKey} />
|
<Attribute isCopyable name="Node Key" value={machine.nodeKey} />
|
||||||
<Attribute
|
<Attribute
|
||||||
|
suppressHydrationWarning
|
||||||
name="Created"
|
name="Created"
|
||||||
value={new Date(machine.createdAt).toLocaleString()}
|
value={new Date(machine.createdAt).toLocaleString()}
|
||||||
/>
|
/>
|
||||||
<Attribute
|
<Attribute
|
||||||
|
suppressHydrationWarning
|
||||||
name="Last Seen"
|
name="Last Seen"
|
||||||
value={new Date(machine.lastSeen).toLocaleString()}
|
value={new Date(machine.lastSeen).toLocaleString()}
|
||||||
/>
|
/>
|
||||||
<Attribute
|
<Attribute
|
||||||
|
suppressHydrationWarning
|
||||||
name="Expiry"
|
name="Expiry"
|
||||||
value={expired ? new Date(machine.expiry).toLocaleString() : 'Never'}
|
value={expired ? new Date(machine.expiry).toLocaleString() : 'Never'}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -22,15 +22,19 @@ export default function AuthKeyRow({ authKey, server }: Props) {
|
|||||||
<Attribute name="Reusable" value={authKey.reusable ? 'Yes' : 'No'} />
|
<Attribute name="Reusable" value={authKey.reusable ? 'Yes' : 'No'} />
|
||||||
<Attribute name="Ephemeral" value={authKey.ephemeral ? 'Yes' : 'No'} />
|
<Attribute name="Ephemeral" value={authKey.ephemeral ? 'Yes' : 'No'} />
|
||||||
<Attribute name="Used" value={authKey.used ? 'Yes' : 'No'} />
|
<Attribute name="Used" value={authKey.used ? 'Yes' : 'No'} />
|
||||||
<Attribute name="Created" value={createdAt} />
|
<Attribute suppressHydrationWarning name="Created" value={createdAt} />
|
||||||
<Attribute name="Expiration" value={expiration} />
|
<Attribute
|
||||||
|
suppressHydrationWarning
|
||||||
|
name="Expiration"
|
||||||
|
value={expiration}
|
||||||
|
/>
|
||||||
<p className="mb-1 mt-4">
|
<p className="mb-1 mt-4">
|
||||||
To use this key, run the following command on your device:
|
To use this key, run the following command on your device:
|
||||||
</p>
|
</p>
|
||||||
<Code className="text-sm">
|
<Code className="text-sm">
|
||||||
tailscale up --login-server {server} --authkey {authKey.key}
|
tailscale up --login-server {server} --authkey {authKey.key}
|
||||||
</Code>
|
</Code>
|
||||||
<div className="flex gap-4 items-center">
|
<div suppressHydrationWarning className="flex gap-4 items-center">
|
||||||
{(authKey.used && !authKey.reusable) ||
|
{(authKey.used && !authKey.reusable) ||
|
||||||
new Date(authKey.expiration) < new Date() ? undefined : (
|
new Date(authKey.expiration) < new Date() ? undefined : (
|
||||||
<ExpireKey authKey={authKey} />
|
<ExpireKey authKey={authKey} />
|
||||||
|
|||||||
@ -42,7 +42,10 @@ export default function UserRow({ user, role }: UserRowProps) {
|
|||||||
<p>{mapRoleToName(role)}</p>
|
<p>{mapRoleToName(role)}</p>
|
||||||
</td>
|
</td>
|
||||||
<td className="pl-0.5 py-2">
|
<td className="pl-0.5 py-2">
|
||||||
<p className="text-sm text-headplane-600 dark:text-headplane-300">
|
<p
|
||||||
|
suppressHydrationWarning
|
||||||
|
className="text-sm text-headplane-600 dark:text-headplane-300"
|
||||||
|
>
|
||||||
{new Date(user.createdAt).toLocaleDateString()}
|
{new Date(user.createdAt).toLocaleDateString()}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
@ -54,7 +57,9 @@ export default function UserRow({ user, role }: UserRowProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<StatusCircle isOnline={isOnline} className="w-4 h-4" />
|
<StatusCircle isOnline={isOnline} className="w-4 h-4" />
|
||||||
<p>{isOnline ? 'Connected' : new Date(lastSeen).toLocaleString()}</p>
|
<p suppressHydrationWarning>
|
||||||
|
{isOnline ? 'Connected' : new Date(lastSeen).toLocaleString()}
|
||||||
|
</p>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="py-2 pr-0.5">
|
<td className="py-2 pr-0.5">
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import {
|
|||||||
} from 'react-router';
|
} from 'react-router';
|
||||||
import Button from '~/components/Button';
|
import Button from '~/components/Button';
|
||||||
import Card from '~/components/Card';
|
import Card from '~/components/Card';
|
||||||
import Code from '~/components/Code';
|
|
||||||
import Link from '~/components/Link';
|
import Link from '~/components/Link';
|
||||||
import Options from '~/components/Options';
|
import Options from '~/components/Options';
|
||||||
import StatusCircle from '~/components/StatusCircle';
|
import StatusCircle from '~/components/StatusCircle';
|
||||||
@ -21,6 +20,7 @@ import { Machine } from '~/types';
|
|||||||
import cn from '~/utils/cn';
|
import cn from '~/utils/cn';
|
||||||
import { useLiveData } from '~/utils/live-data';
|
import { useLiveData } from '~/utils/live-data';
|
||||||
import log from '~/utils/log';
|
import log from '~/utils/log';
|
||||||
|
import toast from '~/utils/toast';
|
||||||
|
|
||||||
export async function loader({
|
export async function loader({
|
||||||
request,
|
request,
|
||||||
@ -152,20 +152,19 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="heavy"
|
className="flex text-md font-mono"
|
||||||
className={cn(
|
onPress={async () => {
|
||||||
'my-4 px-0 w-full pointer-events-none',
|
await navigator.clipboard.writeText(
|
||||||
'hover:bg-initial focus:ring-0',
|
'curl -fsSL https://tailscale.com/install.sh | sh',
|
||||||
)}
|
);
|
||||||
>
|
|
||||||
<Code
|
toast('Copied to clipboard');
|
||||||
isCopyable
|
}}
|
||||||
className="bg-transparent pointer-events-auto mx-0"
|
|
||||||
>
|
>
|
||||||
curl -fsSL https://tailscale.com/install.sh | sh
|
curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
</Code>
|
|
||||||
</Button>
|
</Button>
|
||||||
<p className="text-end text-sm">
|
<p className="text-xs mt-1 text-headplane-600 dark:text-headplane-300 text-center">
|
||||||
|
Click this button to copy the command.{' '}
|
||||||
<Link
|
<Link
|
||||||
name="Linux installation script"
|
name="Linux installation script"
|
||||||
to="https://github.com/tailscale/tailscale/blob/main/scripts/installer.sh"
|
to="https://github.com/tailscale/tailscale/blob/main/scripts/installer.sh"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user