fix: resolve type errors across the codebase
This commit is contained in:
parent
10bb4eba97
commit
12754bd0aa
@ -1,7 +1,7 @@
|
|||||||
import { XIcon } from '@primer/octicons-react'
|
import { XIcon } from '@primer/octicons-react'
|
||||||
import { type AriaToastProps, useToast, useToastRegion } from '@react-aria/toast'
|
import { AriaToastProps, useToast, useToastRegion } from '@react-aria/toast'
|
||||||
import { ToastQueue, type ToastState, useToastQueue } from '@react-stately/toast'
|
import { ToastQueue, ToastState, useToastQueue } from '@react-stately/toast'
|
||||||
import { type ReactNode, useRef } from 'react'
|
import { ReactNode, useRef } from 'react'
|
||||||
import { Button } from 'react-aria-components'
|
import { Button } from 'react-aria-components'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
import { ClientOnly } from 'remix-utils/client-only'
|
import { ClientOnly } from 'remix-utils/client-only'
|
||||||
@ -14,6 +14,8 @@ type ToastProperties = AriaToastProps<ReactNode> & {
|
|||||||
|
|
||||||
function Toast({ state, ...properties }: ToastProperties) {
|
function Toast({ state, ...properties }: ToastProperties) {
|
||||||
const reference = useRef(null)
|
const reference = useRef(null)
|
||||||
|
|
||||||
|
// @ts-expect-error: RefObject doesn't map to FocusableElement?
|
||||||
const { toastProps, titleProps, closeButtonProps } = useToast(properties, state, reference)
|
const { toastProps, titleProps, closeButtonProps } = useToast(properties, state, reference)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -52,11 +54,15 @@ export function toast(text: string) {
|
|||||||
export function Toaster() {
|
export function Toaster() {
|
||||||
const reference = useRef(null)
|
const reference = useRef(null)
|
||||||
const state = useToastQueue(toasts)
|
const state = useToastQueue(toasts)
|
||||||
|
|
||||||
|
// @ts-expect-error: React 19 has weird types for Portal vs Node
|
||||||
const { regionProps } = useToastRegion({}, state, reference)
|
const { regionProps } = useToastRegion({}, state, reference)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
{() => createPortal(
|
{
|
||||||
|
// @ts-expect-error: Portal doesn't match Node in React 19 yet
|
||||||
|
() => createPortal(
|
||||||
state.visibleToasts.length >= 0 ? (
|
state.visibleToasts.length >= 0 ? (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
|||||||
let modeGuess = 'database' // Assume database mode
|
let modeGuess = 'database' // Assume database mode
|
||||||
if (context.config.read) {
|
if (context.config.read) {
|
||||||
const config = await loadConfig()
|
const config = await loadConfig()
|
||||||
modeGuess = config.policy.mode
|
modeGuess = config.policy?.mode ?? 'database'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to load the policy, for both the frontend and for checking
|
// Attempt to load the policy, for both the frontend and for checking
|
||||||
@ -96,7 +96,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
|||||||
return {
|
return {
|
||||||
read: false,
|
read: false,
|
||||||
write: false,
|
write: false,
|
||||||
mode: modeGuess
|
mode: modeGuess,
|
||||||
|
policy: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +107,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
|||||||
return {
|
return {
|
||||||
read: true,
|
read: true,
|
||||||
write: true,
|
write: true,
|
||||||
mode: modeGuess
|
mode: modeGuess,
|
||||||
|
policy: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +116,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
|||||||
export async function action({ request }: ActionFunctionArgs) {
|
export async function action({ request }: ActionFunctionArgs) {
|
||||||
const session = await getSession(request.headers.get('Cookie'))
|
const session = await getSession(request.headers.get('Cookie'))
|
||||||
if (!session.has('hsApiKey')) {
|
if (!session.has('hsApiKey')) {
|
||||||
return json({ success: false }, {
|
return json({ success: false, error: null }, {
|
||||||
status: 401,
|
status: 401,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -129,16 +131,18 @@ export async function action({ request }: ActionFunctionArgs) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return json({ success: true, policy })
|
return json({ success: true, policy, error: null })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.debug('APIC', 'Failed to update ACL policy with error %s', error)
|
log.debug('APIC', 'Failed to update ACL policy with error %s', error)
|
||||||
|
|
||||||
|
// @ts-ignore: Shut UP we know it's a string most of the time
|
||||||
const text = JSON.parse(error.message)
|
const text = JSON.parse(error.message)
|
||||||
return json({ success: false, error: text.message }, {
|
return json({ success: false, error: text.message }, {
|
||||||
status: error instanceof HeadscaleError ? error.status : 500,
|
status: error instanceof HeadscaleError ? error.status : 500,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return json({ success: true })
|
return json({ success: true, error: null })
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
@ -154,6 +158,7 @@ export default function Page() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore: useDebounceFetcher is not typed correctly
|
||||||
if (fetcher.data.success) {
|
if (fetcher.data.success) {
|
||||||
toast('Updated tailnet ACL policy')
|
toast('Updated tailnet ACL policy')
|
||||||
} else {
|
} else {
|
||||||
@ -183,6 +188,7 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we have a failed fetcher state allow the user to try again
|
// If we have a failed fetcher state allow the user to try again
|
||||||
|
// @ts-ignore: useDebounceFetcher is not typed correctly
|
||||||
if (fetcher.data?.success === false) {
|
if (fetcher.data?.success === false) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -231,8 +237,11 @@ export default function Page() {
|
|||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{fetcher.data?.success === false
|
{
|
||||||
|
// @ts-ignore: useDebounceFetcher is not typed correctly
|
||||||
|
fetcher.data?.success === false
|
||||||
? (
|
? (
|
||||||
|
// @ts-ignore: useDebounceFetcher is not typed correctly
|
||||||
<ErrorView message={fetcher.data.error} />
|
<ErrorView message={fetcher.data.error} />
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|
||||||
@ -291,7 +300,7 @@ export default function Page() {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel id="diff">
|
<TabPanel id="diff">
|
||||||
<Differ
|
<Differ
|
||||||
left={data.policy}
|
left={data?.policy ?? ''}
|
||||||
right={acl}
|
right={acl}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -335,13 +344,13 @@ export default function Page() {
|
|||||||
<Button
|
<Button
|
||||||
isDisabled={disabled}
|
isDisabled={disabled}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setAcl(data.policy)
|
setAcl(data?.policy ?? '')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Discard Changes
|
Discard Changes
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : <Unavailable mode={data.mode} />}
|
) : <Unavailable mode={data.mode as "database" | "file"} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export interface NewProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function New(data: NewProps) {
|
export default function New(data: NewProps) {
|
||||||
const fetcher = useFetcher()
|
const fetcher = useFetcher<{ success?: boolean }>()
|
||||||
const mkeyState = useState(false)
|
const mkeyState = useState(false)
|
||||||
const [mkey, setMkey] = useState('')
|
const [mkey, setMkey] = useState('')
|
||||||
const [user, setUser] = useState('')
|
const [user, setUser] = useState('')
|
||||||
|
|||||||
@ -31,10 +31,7 @@ export default function Page() {
|
|||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<RemixLink
|
<RemixLink to="/settings/auth-keys">
|
||||||
to="/settings/auth-keys"
|
|
||||||
name="Auth Keys"
|
|
||||||
>
|
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'text-lg font-medium',
|
'text-lg font-medium',
|
||||||
'text-gray-700 dark:text-gray-300',
|
'text-gray-700 dark:text-gray-300',
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export default function AddPreAuthKey(data: Props) {
|
|||||||
onChange={() => { setReusable(!reusable) }}
|
onChange={() => { setReusable(!reusable) }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="reusable" value={reusable} />
|
<input type="hidden" name="reusable" value={reusable.toString()} />
|
||||||
<div className="flex justify-between items-center mt-6">
|
<div className="flex justify-between items-center mt-6">
|
||||||
<div>
|
<div>
|
||||||
<Dialog.Text className="font-semibold">
|
<Dialog.Text className="font-semibold">
|
||||||
@ -121,7 +121,7 @@ export default function AddPreAuthKey(data: Props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="ephemeral" value={ephemeral} />
|
<input type="hidden" name="ephemeral" value={ephemeral.toString()} />
|
||||||
<div className="mt-6 flex justify-end gap-2 mt-6">
|
<div className="mt-6 flex justify-end gap-2 mt-6">
|
||||||
<Dialog.Action
|
<Dialog.Action
|
||||||
variant="cancel"
|
variant="cancel"
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export default function AuthKeyRow({ authKey, server }: Props) {
|
|||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
className="my-4"
|
className="my-4"
|
||||||
onClick={async () => {
|
onPress={async () => {
|
||||||
await navigator.clipboard.writeText(
|
await navigator.clipboard.writeText(
|
||||||
`tailscale up --login-server ${server} --authkey ${authKey.key}`
|
`tailscale up --login-server ${server} --authkey ${authKey.key}`
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user