mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 04:15:04 +03:00
Allow support form to attach HAR files
This commit is contained in:
1 parent
d8360abfdd
commit
9017bbf057
2 files changed
+73
-34
No files matched your search
@@ -1,5 +1,10 @@
|
||||
// End of third-party imports
|
||||
|
||||
import { useGenerateAttachmentURLsMutation } from 'data/support/generate-attachment-urls-mutation'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { compact } from 'lodash'
|
||||
import { Plus, X } from 'lucide-react'
|
||||
import { File, Plus, X } from 'lucide-react'
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -10,12 +15,8 @@ import {
|
||||
type RefObject,
|
||||
} from 'react'
|
||||
import { toast } from 'sonner'
|
||||
// End of third-party imports
|
||||
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
|
||||
import { useGenerateAttachmentURLsMutation } from 'data/support/generate-attachment-urls-mutation'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { cn } from 'ui'
|
||||
import { createSupportStorageClient } from './support-storage-client'
|
||||
|
||||
const MAX_ATTACHMENTS = 5
|
||||
@@ -26,7 +27,7 @@ const uploadAttachments = async ({ userId, files }: { userId: string; files: Fil
|
||||
const filesToUpload = Array.from(files)
|
||||
const uploadedFiles = await Promise.all(
|
||||
filesToUpload.map(async (file) => {
|
||||
const suffix = file.type.split('/')[1]
|
||||
const suffix = file.name.endsWith('.har') ? 'har' : file.type.split('/')[1]
|
||||
const prefix = `${userId}/${uuidv4()}.${suffix}`
|
||||
const options = { cacheControl: '3600' }
|
||||
|
||||
@@ -87,7 +88,13 @@ export function useAttachmentUpload() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!uploadedFiles) return
|
||||
const objectUrls = uploadedFiles.map((file) => URL.createObjectURL(file))
|
||||
const objectUrls = uploadedFiles.map((file) => {
|
||||
if (file.name.endsWith('.har')) {
|
||||
return file.name
|
||||
} else {
|
||||
return URL.createObjectURL(file)
|
||||
}
|
||||
})
|
||||
setUploadedDataUrls(objectUrls)
|
||||
|
||||
return () => {
|
||||
@@ -160,8 +167,8 @@ export function AttachmentUploadDisplay({
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<p className="text-sm text-foreground-light">Attachments</p>
|
||||
<p className="text-sm text-foreground-lighter">
|
||||
Upload up to {MAX_ATTACHMENTS} screenshots that might be relevant to the issue that you're
|
||||
facing
|
||||
Upload up to {MAX_ATTACHMENTS} images or HAR files that might be relevant to the issue
|
||||
that you're facing
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
@@ -169,29 +176,62 @@ export function AttachmentUploadDisplay({
|
||||
type="file"
|
||||
ref={uploadButtonRef}
|
||||
className="hidden"
|
||||
accept="image/png, image/jpeg"
|
||||
accept="image/png, image/jpeg, .har"
|
||||
onChange={handleFileUpload}
|
||||
/>
|
||||
<div className="flex items-center gap-x-2">
|
||||
{uploadedDataUrls.map((url, idx) => (
|
||||
<div
|
||||
key={url}
|
||||
style={{ backgroundImage: `url("${url}")` }}
|
||||
className="relative h-14 w-14 rounded bg-cover bg-center bg-no-repeat"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Remove attachment"
|
||||
className={cn(
|
||||
'flex h-4 w-4 items-center justify-center rounded-full bg-red-900',
|
||||
'absolute -top-1 -right-1 cursor-pointer'
|
||||
)}
|
||||
onClick={() => removeFileUpload(idx)}
|
||||
>
|
||||
<X aria-hidden="true" size={12} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
{uploadedDataUrls.map((url, idx) => {
|
||||
if (url.endsWith('.har')) {
|
||||
return (
|
||||
<div
|
||||
key={url}
|
||||
className="border relative h-14 w-14 rounded flex items-center justify-center"
|
||||
>
|
||||
<Tooltip>
|
||||
<TooltipTrigger className="cursor-default" onClick={(e) => e.preventDefault()}>
|
||||
<div className="flex flex-col items-center justify-center gap-y-0.5">
|
||||
<File className="text-foreground-light" size={16} />
|
||||
<p className="text-xs font-mono">HAR</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{url}</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Remove attachment"
|
||||
className={cn(
|
||||
'flex h-4 w-4 items-center justify-center rounded-full bg-red-900',
|
||||
'absolute -top-1 -right-1 cursor-pointer'
|
||||
)}
|
||||
onClick={() => removeFileUpload(idx)}
|
||||
>
|
||||
<X aria-hidden="true" size={12} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
key={url}
|
||||
style={{ backgroundImage: `url("${url}")` }}
|
||||
className="relative h-14 w-14 rounded bg-cover bg-center bg-no-repeat"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Remove attachment"
|
||||
className={cn(
|
||||
'flex h-4 w-4 items-center justify-center rounded-full bg-red-900',
|
||||
'absolute -top-1 -right-1 cursor-pointer'
|
||||
)}
|
||||
onClick={() => removeFileUpload(idx)}
|
||||
>
|
||||
<X aria-hidden="true" size={12} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})}
|
||||
{!isFull && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { ComponentType, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useAuth } from 'common'
|
||||
import { SessionTimeoutModal } from 'components/interfaces/SignIn/SessionTimeoutModal'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useAuthenticatorAssuranceLevelQuery } from 'data/profile/mfa-authenticator-assurance-level-query'
|
||||
import { useSignOut } from 'lib/auth'
|
||||
import { BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ComponentType, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { isNextPageWithLayout, type NextPageWithLayout } from 'types'
|
||||
|
||||
const MAX_TIMEOUT = 10000 // 10 seconds
|
||||
|
||||
Reference in new issue
Block a user