Skip to content

Commit

Permalink
Merge branch '447-create-input-component-and-replace-local-storage-in…
Browse files Browse the repository at this point in the history
…put-with-it' into 449-create-toggle-component-and-replace-local-storage-toggle-with-it
  • Loading branch information
SgtPooki committed Nov 13, 2024
2 parents 8c237e5 + 5b0a306 commit 6215473
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 165 deletions.
90 changes: 0 additions & 90 deletions src/components/local-storage-input.tsx

This file was deleted.

65 changes: 65 additions & 0 deletions src/components/textarea-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useCallback, useEffect, useState } from 'react'
import { InputDescription } from './input-description.js'
import { InputLabel } from './input-label.js'

export interface InputProps extends Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, 'onChange'> {
label: string
placeholder?: string
value: string
validationFn?(value: string): Error | null
resetKey: number
description?: string
preSaveFormat?(value: string): any
onChange(value: string): void
}

export default ({ resetKey, onChange, label, placeholder, validationFn, value, description, preSaveFormat, ...props }: InputProps): JSX.Element => {
const [internalValue, setInternalValue] = useState(value)
const [error, setError] = useState<null | Error>(null)

useEffect(() => {
setInternalValue(value)
}, [resetKey, value])

const updateValue = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInternalValue(e.target.value)
}, [])

const saveValue = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newValue = e.target.value
try {
const err = validationFn?.(newValue)
if (err != null) {
throw err
}
setInternalValue(newValue)

onChange(preSaveFormat?.(newValue) ?? newValue)
setError(null)
} catch (err) {
setError(err as Error)
}
}, [onChange, preSaveFormat, validationFn])

props = {
...props,
className: `${props.className ?? ''} flex-column items-start`
}

return (
<div {...props}>
<InputLabel label={label} />
<InputDescription description={description} />
<textarea
className='input-reset ba br2 b--light-silver code lh-copy black-80 bg-white pa2 w-100 mt2'
id={label}
name={label}
placeholder={placeholder}
value={internalValue}
onChange={updateValue}
onBlur={saveValue}
/>
{error != null && <span className='db lh-copy red pt1 tr f6 w-100'>{error.message}</span>}
</div>
)
}
84 changes: 80 additions & 4 deletions src/context/config-context.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,92 @@
import React, { createContext, useState } from 'react'
import React, { createContext, useCallback, useEffect, useState } from 'react'
import { getConfig, type ConfigDb } from '../lib/config-db.js'
import { isConfigPage } from '../lib/is-config-page.js'
import { getUiComponentLogger } from '../lib/logger.js'

const isLoadedInIframe = window.self !== window.top

export const ConfigContext = createContext({
type ConfigKey = keyof ConfigDb
export interface ConfigContextType extends ConfigDb {
isConfigExpanded: boolean
setConfigExpanded(value: boolean): void
setConfig(key: ConfigKey, value: any): void
}

export const ConfigContext = createContext<ConfigContextType>({
isConfigExpanded: isLoadedInIframe,
setConfigExpanded: (value: boolean) => {}
setConfigExpanded: (value: boolean) => {},
setConfig: (key, value) => {},
gateways: [],
routers: [],
dnsJsonResolvers: {},
enableWss: false,
enableWebTransport: false,
enableGatewayProviders: false,
enableRecursiveGateways: false,
debug: ''
})

export const ConfigProvider = ({ children }: { children: JSX.Element[] | JSX.Element, expanded?: boolean }): JSX.Element => {
const [isConfigExpanded, setConfigExpanded] = useState(isConfigPage(window.location.hash))
const [gateways, setGateways] = useState<string[]>([])
const [routers, setRouters] = useState<string[]>([])
const [dnsJsonResolvers, setDnsJsonResolvers] = useState<Record<string, string>>({})
const [enableWss, setEnableWss] = useState(false)
const [enableWebTransport, setEnableWebTransport] = useState(false)
const [enableGatewayProviders, setEnableGatewayProviders] = useState(false)
const [enableRecursiveGateways, setEnableRecursiveGateways] = useState(false)
const [debug, setDebug] = useState('')
const isExplicitlyLoadedConfigPage = isConfigPage(window.location.hash)
/**
* We need to make sure that the configDb types are loaded with the values from IDB
*/
useEffect(() => {
void (async () => {
const config = await getConfig(getUiComponentLogger('config-context'))
setGateways(config.gateways)
setRouters(config.routers)
setDnsJsonResolvers(config.dnsJsonResolvers)
setEnableWss(config.enableWss)
setEnableWebTransport(config.enableWebTransport)
setEnableGatewayProviders(config.enableGatewayProviders)
setEnableRecursiveGateways(config.enableRecursiveGateways)
setDebug(config.debug)
})()
}, [])

/**
* Sets the config values for the context provider. To save to IDB, use the `setConfig` function from `lib/config-db.ts`.
*/
const setConfigLocal = useCallback((key: ConfigKey, value: any) => {
switch (key) {
case 'gateways':
setGateways(value)
break
case 'routers':
setRouters(value)
break
case 'dnsJsonResolvers':
setDnsJsonResolvers(value)
break
case 'enableWss':
setEnableWss(value)
break
case 'enableWebTransport':
setEnableWebTransport(value)
break
case 'enableGatewayProviders':
setEnableGatewayProviders(value)
break
case 'enableRecursiveGateways':
setEnableRecursiveGateways(value)
break
case 'debug':
setDebug(value)
break
default:
throw new Error(`Unknown config key: ${key}`)
}
}, [])

const setConfigExpandedWrapped = (value: boolean): void => {
if (isLoadedInIframe || isExplicitlyLoadedConfigPage) {
Expand All @@ -21,7 +97,7 @@ export const ConfigProvider = ({ children }: { children: JSX.Element[] | JSX.Ele
}

return (
<ConfigContext.Provider value={{ isConfigExpanded, setConfigExpanded: setConfigExpandedWrapped }}>
<ConfigContext.Provider value={{ isConfigExpanded, setConfigExpanded: setConfigExpandedWrapped, setConfig: setConfigLocal, gateways, routers, dnsJsonResolvers, enableWss, enableWebTransport, enableGatewayProviders, enableRecursiveGateways, debug }}>
{children}
</ConfigContext.Provider>
)
Expand Down
13 changes: 1 addition & 12 deletions src/lib/config-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,14 @@ export const defaultEnableGatewayProviders = true

const configDb = new GenericIDB<ConfigDb>('helia-sw', 'config')

export async function localStorageToIdb (): Promise<void> {
export async function localStorageToIdb ({ gateways, routers, dnsJsonResolvers, debug }: Pick<ConfigDb, 'gateways' | 'routers' | 'dnsJsonResolvers' | 'debug'>): Promise<void> {
if (typeof globalThis.localStorage !== 'undefined') {
await configDb.open()
const localStorage = globalThis.localStorage
const localStorageGatewaysString = localStorage.getItem(LOCAL_STORAGE_KEYS.config.gateways) ?? JSON.stringify(defaultGateways)
const localStorageRoutersString = localStorage.getItem(LOCAL_STORAGE_KEYS.config.routers) ?? JSON.stringify(defaultRouters)
const localStorageDnsResolvers = localStorage.getItem(LOCAL_STORAGE_KEYS.config.dnsJsonResolvers) ?? JSON.stringify(defaultDnsJsonResolvers)
const enableRecursiveGateways = localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableRecursiveGateways) === null ? defaultEnableRecursiveGateways : localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableRecursiveGateways) === 'true'
const enableWss = localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableWss) === null ? defaultEnableWss : localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableWss) === 'true'
const enableWebTransport = localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableWebTransport) === null ? defaultEnableWebTransport : localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableWebTransport) === 'true'
const enableGatewayProviders = localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableGatewayProviders) === null ? defaultEnableGatewayProviders : localStorage.getItem(LOCAL_STORAGE_KEYS.config.enableGatewayProviders) === 'true'
const debug = localStorage.getItem(LOCAL_STORAGE_KEYS.config.debug) ?? ''
const gateways = JSON.parse(localStorageGatewaysString)
const routers = JSON.parse(localStorageRoutersString)
const dnsJsonResolvers = JSON.parse(localStorageDnsResolvers)
enable(debug)

await configDb.put('gateways', gateways)
Expand All @@ -56,11 +49,8 @@ export async function localStorageToIdb (): Promise<void> {

export async function resetConfig (): Promise<void> {
await configDb.open()
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.gateways)
await configDb.put('gateways', defaultGateways)
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.routers)
await configDb.put('routers', defaultRouters)
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.dnsJsonResolvers)
await configDb.put('dnsJsonResolvers', defaultDnsJsonResolvers)
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.enableWss)
await configDb.put('enableWss', defaultEnableWss)
Expand All @@ -70,7 +60,6 @@ export async function resetConfig (): Promise<void> {
await configDb.put('enableRecursiveGateways', defaultEnableRecursiveGateways)
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.enableGatewayProviders)
await configDb.put('enableGatewayProviders', defaultEnableGatewayProviders)
localStorage.removeItem(LOCAL_STORAGE_KEYS.config.debug)
await configDb.put('debug', '')
configDb.close()
}
Expand Down
18 changes: 18 additions & 0 deletions src/lib/input-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const convertUrlArrayToInput = (urls: string[]): string => {
return urls.join('\n')
}

export const convertUrlInputToArray = (newlineDelimitedString: string): string[] => {
return newlineDelimitedString.length > 0 ? newlineDelimitedString.split('\n').map((u) => u.trim()) : []
}

export const convertDnsResolverObjectToInput = (dnsResolvers: Record<string, string>): string => {
return Object.entries(dnsResolvers).map(([key, url]) => `${key} ${url}`).join('\n')
}

export const convertDnsResolverInputToObject = (dnsResolverInput: string): Record<string, string> => {
return dnsResolverInput.split('\n').map((u) => u.trim().split(' ')).reduce((acc, [key, url]) => {
acc[key] = url
return acc
}, {})
}
25 changes: 1 addition & 24 deletions src/lib/local-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,12 @@ export function getLocalStorageKey (root: LocalStorageRoots, key: string): strin

export const LOCAL_STORAGE_KEYS = {
config: {
gateways: getLocalStorageKey('config', 'gateways'),
routers: getLocalStorageKey('config', 'routers'),
enableWss: getLocalStorageKey('config', 'enableWss'),
enableWebTransport: getLocalStorageKey('config', 'enableWebTransport'),
enableRecursiveGateways: getLocalStorageKey('config', 'enableRecursiveGateways'),
enableGatewayProviders: getLocalStorageKey('config', 'enableGatewayProviders'),
dnsJsonResolvers: getLocalStorageKey('config', 'dnsJsonResolvers'),
debug: getLocalStorageKey('config', 'debug')
enableGatewayProviders: getLocalStorageKey('config', 'enableGatewayProviders')
},
forms: {
requestPath: getLocalStorageKey('forms', 'requestPath')
}
}

export const convertUrlArrayToInput = (urls: string[]): string => {
return urls.join('\n')
}

export const convertUrlInputToArray = (newlineDelimitedString: string): string[] => {
return newlineDelimitedString.length > 0 ? newlineDelimitedString.split('\n').map((u) => u.trim()) : []
}

export const convertDnsResolverObjectToInput = (dnsResolvers: Record<string, string>): string => {
return Object.entries(dnsResolvers).map(([key, url]) => `${key} ${url}`).join('\n')
}

export const convertDnsResolverInputToObject = (dnsResolverInput: string): Record<string, string> => {
return dnsResolverInput.split('\n').map((u) => u.trim().split(' ')).reduce((acc, [key, url]) => {
acc[key] = url
return acc
}, {})
}
Loading

0 comments on commit 6215473

Please sign in to comment.