Skip to content

Commit

Permalink
feat: workaround getUrls
Browse files Browse the repository at this point in the history
  • Loading branch information
clement2026 committed Aug 23, 2024
1 parent 8f79b77 commit 08261de
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 78 deletions.
42 changes: 30 additions & 12 deletions ts/components/hooks/__test__/set-url.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,73 @@ import { useURL } from '@/components/hooks/use-url'
import { graphPrefsState } from '@/components/state/pref-state'

test('useURL-port', () => {
const render = renderHook(() => useURL())

for (const port of [1, 8899, 65535]) {
graphPrefsState.inputURL = `${port}`
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url).toBeTypeOf('string')
expect(url).toBe(`http://localhost:${port}/debug/pprof`)
}

for (const port of [-1, 0, -0, 65536, 999999]) {
graphPrefsState.inputURL = `${port}`
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url instanceof Error).toBeTruthy()
expect((url as Error).message).includes('out of range')
}

for (const element of [-11.1, 9090.1]) {
graphPrefsState.inputURL = `${element}`
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url instanceof Error).toBeTruthy()
expect((url as Error).message).includes('Invalid URL')
}
})

test('useURL localhost', () => {
const render = renderHook(() => useURL())

for (const element of ['localhost', 'http://localhost', 'http://localhost/']) {
graphPrefsState.inputURL = element
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url).toBeTypeOf('string')
expect(url).toBe('http://localhost')
}

graphPrefsState.inputURL = 'localhost:80'
render.rerender()
let { url } = render.result.current
expect(url).toBeTypeOf('string')
expect(url).toBe('http://localhost:80')

graphPrefsState.inputURL = 'localhost:21'
render.rerender()
url = render.result.current.url
expect(url).toBeTypeOf('string')
expect(url).toBe('http://localhost:21')

for (const element of [
'localhost/ab/c-d',
'localhost//ab//c-d',
'http://localhost/ab/c-d',
'http://localhost/ab/c-d',
]) {
graphPrefsState.inputURL = element
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url).toBeTypeOf('string')
expect(url).toBe('http://localhost/ab/c-d')
}

for (const element of ['https://localhost/ab/c-d']) {
graphPrefsState.inputURL = element
const render = renderHook(() => useURL())
let url = render.result.current
render.rerender()
const { url } = render.result.current
expect(url).toBeTypeOf('string')
expect(url).toBe('https://localhost/ab/c-d')
}
Expand Down
28 changes: 20 additions & 8 deletions ts/components/hooks/use-url.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
'use client'

import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { useSnapshot } from 'valtio/react'
import getUrls from 'get-urls'

import { graphPrefsState } from '@/components/state/pref-state'
import getUrls from 'get-urls'

export const useURL = (): string | Error => {
export const useURL = (): { url: string | Error; input: string; setInput: (input: string) => void } => {
const { inputURL } = useSnapshot(graphPrefsState)
const [url, setUrl] = useState<string | Error>(Error('Initial'))

const setInput = useCallback((input: string) => {
graphPrefsState.inputURL = input
}, [])
useEffect(() => {
let gen = generateUrl(inputURL)
setUrl(gen)
}, [inputURL, setUrl])

return url
return { url: url, input: inputURL, setInput: setInput }
}

const generateUrl = (input: string): string | Error => {
const port = Number(input)
if (Number.isInteger(port)) {
if (input === '') {
return new Error('Please input the URL of pprof endpoint')
} else if (Number.isInteger(port)) {
if (port >= 1 && port <= 65535) {
return `http://localhost:${port}/debug/pprof`
} else {
return new Error(`Port ${port} is out of range: [1, 65535]`)
}
} else {
const next = getUrls(input).values().next()
const urls = getUrls(input)
const next = urls.values().next()
if (!next.done) {
return next.value
let v = next.value
// workaround for getUrls as it may return an URL without the scheme prefix
// noinspection HttpUrlsUsage
if (!v.startsWith('http://') && !v.startsWith('https://')) {
// noinspection HttpUrlsUsage
v = `http://${v}`
}
return v
}

return new Error('Invalid URL')
Expand Down
5 changes: 2 additions & 3 deletions ts/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import { MockSwitch } from '@/components/mock-switch'
import { RecorderButton } from '@/components/recorder-button'
import { RecorderTime } from '@/components/recorder-time'
import { HomeMenu } from '@/components/home-menu'
import { URLInputBox } from '@/components/url-input-box'
import UrlPopover from '@/components/url-popover'
import UrlChip from '@/components/url-chip'

export const Navbar = () => {
return (
Expand All @@ -23,7 +22,7 @@ export const Navbar = () => {
</NextLink>
</NavbarBrand>
<ul className="flex justify-center items-center gap-1">
<UrlPopover />
<UrlChip />
<RecorderButton />
<RecorderTime />
<HomeMenu />
Expand Down
3 changes: 3 additions & 0 deletions ts/components/recorder-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { Button } from '@nextui-org/button'
import { Icon } from '@iconify/react'

import { recorderState } from '@/components/state/recorder-state'
import { useURL } from '@/components/hooks/use-url'

export const RecorderButton = () => {
const { isRecording } = useSnapshot(recorderState)
const url = useURL()
const tooltipInfo = isRecording ? 'Stop' : 'Start'

const start = useCallback(() => {
Expand Down Expand Up @@ -37,6 +39,7 @@ export const RecorderButton = () => {
isIconOnly
aria-label={tooltipInfo}
className="text-default-500 dark:text-default-foreground"
disabled={url instanceof Error}
variant={'light'}
onPress={start}
>
Expand Down
30 changes: 30 additions & 0 deletions ts/components/url-chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client'
import React from 'react'
import { Popover, PopoverContent, PopoverTrigger } from '@nextui-org/popover'
import { Chip } from '@nextui-org/chip'

import { UrlInputPopover } from '@/components/url-input-popover'
import { useURL } from '@/components/hooks/use-url'

export default function UrlChip() {
const { url } = useURL()

return (
<div className="flex flex-wrap gap-4">
<Popover backdrop={'blur'} offset={10} placement="bottom">
<PopoverTrigger>
{url instanceof Error ? (
<Chip className="cursor-pointer " color={'warning'} variant={'light'}>
{url.message}
</Chip>
) : (
<Chip className="cursor-pointer bg-foreground-100">{url}</Chip>
)}
</PopoverTrigger>
<PopoverContent className="p-2 bg-foreground-100 ">
<UrlInputPopover />
</PopoverContent>
</Popover>
</div>
)
}
19 changes: 19 additions & 0 deletions ts/components/url-detect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client'

import React, { FC } from 'react'
import { Chip } from '@nextui-org/chip'

interface UrlDetectProps {
url: string
}

export const UrlDetect: FC<UrlDetectProps> = ({ url }) => {
return (
<div className={'flex gap-1'}>
<Chip className={'text-default-500'} variant={'light'}>
{url}
</Chip>
<div />
</div>
)
}
30 changes: 0 additions & 30 deletions ts/components/url-input-box.tsx

This file was deleted.

39 changes: 39 additions & 0 deletions ts/components/url-input-popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import { Input } from '@nextui-org/input'
import React, { useMemo } from 'react'

import { useURL } from '@/components/hooks/use-url'
import { UrlDetect } from '@/components/url-detect'

export const UrlInputPopover = () => {
const { url, input, setInput } = useURL()

const isInvalid = useMemo(() => {
return url instanceof Error
}, [url])

const placeholder = '8080, localhost:8080 or http://localhost:8080/debug/pprof'
return (
<div className="flex flex-col justify-start items-start">
{/* to provide auto inferred width for <Input> */}
<div className="text-nowrap z-10 opacity-0 select-none h-[1px]">{placeholder}6chars6chars</div>

<Input
fullWidth
isClearable
className={'w-full max-w-full'}
color={isInvalid ? 'danger' : 'success'}
errorMessage={url instanceof Error ? url.message : undefined}
isInvalid={isInvalid}
placeholder={placeholder}
type="email"
value={input}
variant="bordered"
onValueChange={setInput}
/>
{typeof url === 'string' && <UrlDetect url={url} />}
<div className="text-nowrap z-10 opacity-0 select-none h-[1px]">{placeholder}6chars</div>
</div>
)
}
25 changes: 0 additions & 25 deletions ts/components/url-popover.tsx

This file was deleted.

0 comments on commit 08261de

Please sign in to comment.