diff --git a/apps/design-system/__registry__/index.tsx b/apps/design-system/__registry__/index.tsx index 0a14ada3678..f8f80ed90d4 100644 --- a/apps/design-system/__registry__/index.tsx +++ b/apps/design-system/__registry__/index.tsx @@ -148,6 +148,17 @@ export const Index: Record = { subcategory: "undefined", chunks: [] }, + "alert-collapsible-demo": { + name: "alert-collapsible-demo", + type: "components:example", + registryDependencies: ["alert","collapsible","button"], + component: React.lazy(() => import("@/registry/default/example/alert-collapsible-demo")), + source: "", + files: ["registry/default/example/alert-collapsible-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, "alert-dialog-demo": { name: "alert-dialog-demo", type: "components:example", diff --git a/apps/design-system/content/docs/components/collapsible.mdx b/apps/design-system/content/docs/components/collapsible.mdx index 3f5be4bb44b..d581612ebac 100644 --- a/apps/design-system/content/docs/components/collapsible.mdx +++ b/apps/design-system/content/docs/components/collapsible.mdx @@ -1,67 +1,37 @@ --- -title: Collapsible -description: An interactive component which expands/collapses a panel. +title: Alert Collapsible +description: An alert-styled block with a collapsible content section, toggled by an icon button. component: true -featured: true -links: - doc: https://www.radix-ui.com/docs/primitives/components/collapsible - api: https://www.radix-ui.com/docs/primitives/components/collapsible#api-reference -source: - radix: true - shadcn: true --- - - -## Installation - - - - - CLI - Manual - - - -```bash -npx shadcn-ui@latest add collapsible -``` - - - - - - - -Install the following dependencies: - -```bash -npm install @radix-ui/react-collapsible -``` - -Copy and paste the following code into your project. - - - -Update the import paths to match your project setup. - - - - - - + ## Usage ```tsx -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' +import { AlertCollapsible } from 'ui' ``` ```tsx - - Can I use this in my project? - - Yes. Free to use for personal and commercial projects. No attribution required. - - + +

Content revealed when expanded.

+
+``` + +### Default open + +```tsx + +

This section is expanded by default.

+
+``` + +### Variants + +Supports the same `variant` prop as `Alert`: `default`, `destructive`, and `warning`. + +```tsx + +

Something needs attention.

+
``` diff --git a/apps/design-system/registry/default/example/alert-collapsible-demo.tsx b/apps/design-system/registry/default/example/alert-collapsible-demo.tsx new file mode 100644 index 00000000000..0aa7671fedd --- /dev/null +++ b/apps/design-system/registry/default/example/alert-collapsible-demo.tsx @@ -0,0 +1,11 @@ +import { AlertCollapsible } from 'ui' + +export default function AlertCollapsibleDemo() { + return ( + +

+ Try a different browser or disable extensions that block network requests. +

+
+ ) +} diff --git a/apps/design-system/registry/examples.ts b/apps/design-system/registry/examples.ts index 6085f8a9fa0..bffcbedee62 100644 --- a/apps/design-system/registry/examples.ts +++ b/apps/design-system/registry/examples.ts @@ -43,6 +43,12 @@ export const examples: Registry = [ registryDependencies: ['alert'], files: ['example/alert-demo.tsx'], }, + { + name: 'alert-collapsible-demo', + type: 'components:example', + registryDependencies: ['alert', 'collapsible', 'button'], + files: ['example/alert-collapsible-demo.tsx'], + }, { name: 'alert-dialog-demo', type: 'components:example', diff --git a/apps/studio/components/interfaces/SignIn/SessionTimeoutModal.tsx b/apps/studio/components/interfaces/SignIn/SessionTimeoutModal.tsx index ddca9ff4c61..4eb53c91104 100644 --- a/apps/studio/components/interfaces/SignIn/SessionTimeoutModal.tsx +++ b/apps/studio/components/interfaces/SignIn/SessionTimeoutModal.tsx @@ -1,21 +1,36 @@ +import { SupportCategories } from '@supabase/shared-types/out/constants' import * as Sentry from '@sentry/nextjs' import { useEffect } from 'react' +import { toast } from 'sonner' import { InlineLink, InlineLinkClassName } from 'components/ui/InlineLink' -import { toast } from 'sonner' -import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' +import { + AlertCollapsible, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + Button, +} from 'ui' import { SupportLink } from '../Support/SupportLink' interface SessionTimeoutModalProps { visible: boolean onClose: () => void redirectToSignIn: () => void + /** Optional context so the support form can pre-populate when opened from this dialog */ + supportContext?: { projectRef?: string; orgSlug?: string } } export const SessionTimeoutModal = ({ visible, onClose, redirectToSignIn, + supportContext, }: SessionTimeoutModalProps) => { useEffect(() => { if (visible) { @@ -23,60 +38,70 @@ export const SessionTimeoutModal = ({ } }, [visible]) + const handleClearStorage = () => { + try { + localStorage.clear() + sessionStorage.clear() + } catch (e) { + toast.error('Failed to clear browser storage') + } + window.location.reload() + } + return ( - { + if (!open) onClose() }} > -
-
    -
  • Try with a different browser
  • -
  • Disable browser extensions that block network requests
  • -
  • - -
  • -
-

- If none of these steps work, please{' '} - - Contact support - - . -

-

- Consider{' '} - - generating a HAR file - {' '} - from your session to help Support pinpoint the issue. -

-
-
+ + + Session expired + +
+

Please sign in again to continue.

+ +
+

+ Try a different browser or disable extensions that block network requests. If + the problem persists: +

+ +

+ Still stuck?{' '} + + Contact support + {' '} + and include a{' '} + + HAR file + {' '} + from your session to help us investigate. +

+
+
+
+
+
+ + Close + Sign in again + +
+ ) } diff --git a/apps/studio/components/interfaces/Support/AttachmentUpload.tsx b/apps/studio/components/interfaces/Support/AttachmentUpload.tsx index 36cd6ea6d41..99007e27d8b 100644 --- a/apps/studio/components/interfaces/Support/AttachmentUpload.tsx +++ b/apps/studio/components/interfaces/Support/AttachmentUpload.tsx @@ -1,5 +1,11 @@ +// 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, FileCode, Plus, X } from 'lucide-react' +import { InlineLink } from 'components/ui/InlineLink' import { useCallback, useEffect, @@ -10,12 +16,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 +28,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 +89,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 () => { @@ -158,10 +166,12 @@ export function AttachmentUploadDisplay({ return (
-

Attachments

+

Attachments

- Upload up to {MAX_ATTACHMENTS} screenshots that might be relevant to the issue that you're - facing + Optionally upload up to {MAX_ATTACHMENTS} relevant images or{' '} + + HAR files +

- {uploadedDataUrls.map((url, idx) => ( -
- -
- ))} + {uploadedDataUrls.map((url, idx) => { + if (url.endsWith('.har')) { + return ( +
+ + e.preventDefault()}> +
+ +

+ HAR +

+
+
+ {url} +
+ + +
+ ) + } else { + return ( +
+ +
+ ) + } + })} {!isFull && (
+ {children} + +
+ ) +) +AlertCollapsible.displayName = 'AlertCollapsible' + +export { AlertCollapsible } diff --git a/packages/ui/src/components/AlertCollapsible/index.tsx b/packages/ui/src/components/AlertCollapsible/index.tsx new file mode 100644 index 00000000000..a86ab1afc90 --- /dev/null +++ b/packages/ui/src/components/AlertCollapsible/index.tsx @@ -0,0 +1,2 @@ +export { AlertCollapsible } from './AlertCollapsible' +export type { AlertCollapsibleProps } from './AlertCollapsible' diff --git a/packages/ui/src/components/Collapsible/Collapsible.tsx b/packages/ui/src/components/Collapsible/Collapsible.tsx index 9238e573b72..37ffabc82f8 100644 --- a/packages/ui/src/components/Collapsible/Collapsible.tsx +++ b/packages/ui/src/components/Collapsible/Collapsible.tsx @@ -10,7 +10,7 @@ export interface CollapsibleProps extends RadixCollapsible.CollapsibleProps { } /** - * @deprecated Use `import { Collapsible_shadcn_ } from "ui"` instead + * @deprecated Use `import { AlertCollapsible } from "ui"` instead */ export const Collapsible = ({ open = undefined,