feat: CORS enable button...ish still now understanding this
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Globe, Loader2, RefreshCw, Trash2} from 'lucide-react'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
import {deleteS3BucketWebsite, getS3BucketWebsite, putS3BucketWebsite} from '@/api/cloudProxyClient'
|
||||
import {useAccountId} from '@/lib/accountStore'
|
||||
import type {CloudResource, S3BucketWebsiteConfiguration} from '@/types/resource'
|
||||
|
||||
interface S3BucketWebsitePanelProps {
|
||||
resource?: CloudResource
|
||||
runtimeReachable: boolean
|
||||
}
|
||||
|
||||
export function S3BucketWebsitePanel({resource, runtimeReachable}: S3BucketWebsitePanelProps) {
|
||||
const queryClient = useQueryClient()
|
||||
const accountId = useAccountId()
|
||||
const [mode, setMode] = useState<'index' | 'redirect'>('index')
|
||||
const [indexDocument, setIndexDocument] = useState('index.html')
|
||||
const [errorDocument, setErrorDocument] = useState('')
|
||||
const [hostName, setHostName] = useState('')
|
||||
const [protocol, setProtocol] = useState<'http' | 'https' | ''>('')
|
||||
const [confirmDisable, setConfirmDisable] = useState(false)
|
||||
const queryKey = ['s3-bucket-website', accountId, resource?.id]
|
||||
const websiteQuery = useQuery({
|
||||
queryKey,
|
||||
queryFn: ({signal}) => getS3BucketWebsite('aws', resource?.id ?? '', signal),
|
||||
enabled: Boolean(resource) && runtimeReachable,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const configuration = websiteQuery.data
|
||||
if (!configuration) {
|
||||
setMode('index')
|
||||
setIndexDocument('index.html')
|
||||
setErrorDocument('')
|
||||
setHostName('')
|
||||
setProtocol('')
|
||||
return
|
||||
}
|
||||
setMode(configuration.mode)
|
||||
if (configuration.mode === 'index') {
|
||||
setIndexDocument(configuration.indexDocument)
|
||||
setErrorDocument(configuration.errorDocument ?? '')
|
||||
} else {
|
||||
setHostName(configuration.hostName)
|
||||
setProtocol(configuration.protocol ?? '')
|
||||
}
|
||||
}, [websiteQuery.data, resource?.id])
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: (configuration: S3BucketWebsiteConfiguration) => putS3BucketWebsite('aws', resource?.id ?? '', configuration),
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({queryKey})
|
||||
},
|
||||
})
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: () => deleteS3BucketWebsite('aws', resource?.id ?? ''),
|
||||
onSuccess: () => {
|
||||
setConfirmDisable(false)
|
||||
void queryClient.setQueryData<S3BucketWebsiteConfiguration | null>(queryKey, null)
|
||||
void queryClient.invalidateQueries({queryKey})
|
||||
},
|
||||
})
|
||||
|
||||
if (!resource || resource.service !== 'storage' || resource.type !== 'bucket') return null
|
||||
const endpoint = `http://${resource.name}.s3-website-${resource.region ?? 'us-east-1'}.localhost:4566`
|
||||
const configuration = mode === 'index'
|
||||
? {mode, indexDocument: indexDocument.trim(), errorDocument: errorDocument.trim() || null}
|
||||
: {mode, hostName: hostName.trim(), protocol: protocol || null}
|
||||
const canSave = !saveMutation.isPending && (mode === 'index' ? Boolean(configuration.indexDocument) : Boolean(configuration.hostName))
|
||||
|
||||
return <section className="table-panel">
|
||||
<div className="dynamic-stage-header">
|
||||
<div>
|
||||
<p className="eyebrow">Static website hosting</p>
|
||||
<h3><Globe size={15}/> {websiteQuery.data ? 'Enabled' : 'Not configured'}</h3>
|
||||
<p className="muted compact-text">Website endpoint: <a href={endpoint} target="_blank" rel="noreferrer"><code>{endpoint}</code></a></p>
|
||||
</div>
|
||||
<button className="icon-btn" type="button" aria-label="Refresh website configuration" onClick={() => websiteQuery.refetch()} disabled={websiteQuery.isFetching}>
|
||||
{websiteQuery.isFetching ? <Loader2 size={13}/> : <RefreshCw size={13}/>}
|
||||
</button>
|
||||
</div>
|
||||
{websiteQuery.isLoading && <p className="muted compact-text">Loading website configuration...</p>}
|
||||
{websiteQuery.isError && <p className="error-text compact-text">{websiteQuery.error instanceof Error ? websiteQuery.error.message : 'Unable to load website configuration.'}</p>}
|
||||
<form className="resource-create-inline" onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
if (canSave) saveMutation.mutate(configuration)
|
||||
}}>
|
||||
<label className="dynamic-field" htmlFor="s3-website-mode">
|
||||
<span>Hosting mode</span>
|
||||
<select id="s3-website-mode" className="input" value={mode} onChange={(event) => setMode(event.target.value as 'index' | 'redirect')} disabled={saveMutation.isPending}>
|
||||
<option value="index">Index and error documents</option>
|
||||
<option value="redirect">Redirect all requests</option>
|
||||
</select>
|
||||
</label>
|
||||
{mode === 'index' ? <>
|
||||
<label className="dynamic-field" htmlFor="s3-website-index-document"><span>Index document</span><input id="s3-website-index-document" className="input" value={indexDocument} onChange={(event) => setIndexDocument(event.target.value)} placeholder="index.html" required disabled={saveMutation.isPending}/></label>
|
||||
<label className="dynamic-field" htmlFor="s3-website-error-document"><span>Error document</span><input id="s3-website-error-document" className="input" value={errorDocument} onChange={(event) => setErrorDocument(event.target.value)} placeholder="error.html" disabled={saveMutation.isPending}/><small>Optional.</small></label>
|
||||
</> : <>
|
||||
<label className="dynamic-field" htmlFor="s3-website-redirect-host"><span>Redirect host name</span><input id="s3-website-redirect-host" className="input" value={hostName} onChange={(event) => setHostName(event.target.value)} placeholder="www.example.com" required disabled={saveMutation.isPending}/></label>
|
||||
<label className="dynamic-field" htmlFor="s3-website-redirect-protocol"><span>Redirect protocol</span><select id="s3-website-redirect-protocol" className="input" value={protocol} onChange={(event) => setProtocol(event.target.value as 'http' | 'https' | '')} disabled={saveMutation.isPending}><option value="">Preserve request protocol</option><option value="http">HTTP</option><option value="https">HTTPS</option></select></label>
|
||||
</>}
|
||||
<button className="button primary" type="submit" disabled={!canSave}>{saveMutation.isPending ? <Loader2 size={13}/> : null}{websiteQuery.data ? 'Save changes' : 'Enable website hosting'}</button>
|
||||
</form>
|
||||
{saveMutation.isError && <p className="error-text compact-text">{saveMutation.error instanceof Error ? saveMutation.error.message : 'Unable to save website configuration.'}</p>}
|
||||
{websiteQuery.data && (confirmDisable ? <div className="apigateway-route-confirm"><span>Disable static website hosting?</span><button className="button danger compact" type="button" disabled={deleteMutation.isPending} onClick={() => deleteMutation.mutate()}>{deleteMutation.isPending ? 'Disabling' : 'Disable'}</button><button className="button compact" type="button" disabled={deleteMutation.isPending} onClick={() => setConfirmDisable(false)}>Cancel</button></div> : <button className="button danger compact" type="button" onClick={() => setConfirmDisable(true)}><Trash2 size={13}/> Disable website hosting</button>)}
|
||||
{deleteMutation.isError && <p className="error-text compact-text">{deleteMutation.error instanceof Error ? deleteMutation.error.message : 'Unable to disable website hosting.'}</p>}
|
||||
</section>
|
||||
}
|
||||
Reference in New Issue
Block a user