Skip to content

Commit

Permalink
chore: restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
juice49 committed Sep 19, 2024
1 parent 411f74f commit 0a47197
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 120 deletions.
118 changes: 0 additions & 118 deletions packages/sanity/src/core/components/ErrorActions.tsx

This file was deleted.

47 changes: 47 additions & 0 deletions packages/sanity/src/core/components/errorActions/ErrorActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {CopyIcon, SyncIcon} from '@sanity/icons'
import {Inline} from '@sanity/ui'
import {type ComponentProps, type ComponentType} from 'react'

import {Button, Tooltip} from '../../../ui-components'
import {strings} from './strings'
import {useCopyErrorDetails} from './useCopyErrorDetails'

/**
* @internal
*/
export interface ErrorActionsProps extends Pick<ComponentProps<typeof Button>, 'size'> {
error: unknown
eventId: string | null
onRetry?: () => void
}

/**
* @internal
*/
export const ErrorActions: ComponentType<ErrorActionsProps> = ({error, eventId, onRetry, size}) => {
const copyErrorDetails = useCopyErrorDetails(error, eventId)

return (
<Inline space={3}>
{onRetry && (
<Button
onClick={onRetry}
text={strings['retry.title']}
tone="primary"
icon={SyncIcon}
size={size}
/>
)}
<Tooltip content={strings['copy-error-details.description']}>
<Button
onClick={copyErrorDetails}
text={strings['copy-error-details.title']}
tone="default"
mode="ghost"
icon={CopyIcon}
size={size}
/>
</Tooltip>
</Inline>
)
}
3 changes: 3 additions & 0 deletions packages/sanity/src/core/components/errorActions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './ErrorActions'
export * from './types'
export * from './useCopyErrorDetails'
10 changes: 10 additions & 0 deletions packages/sanity/src/core/components/errorActions/strings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// These strings are not internationalized because `ErrorActions` is used inside
// `StudioErrorBoundary`, which is rendered outside of `LocaleProvider`.
export const strings = {
'retry.title': 'Retry',
'copy-error-details.description': 'These technical details may be useful for developers.',
'copy-error-details.title': 'Copy error details',
'copy-error-details.toast.get-failed': 'Failed to get error details',
'copy-error-details.toast.copy-failed': 'Failed to copy error details',
'copy-error-details.toast.succeeded': 'Copied error details to clipboard',
} as const
7 changes: 7 additions & 0 deletions packages/sanity/src/core/components/errorActions/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @internal
*/
export interface ErrorWithId {
error: unknown
eventId?: string | null
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {describe, expect, it} from '@jest/globals'
import {firstValueFrom, map, of} from 'rxjs'

import {type ErrorWithId, serializeError} from './ErrorActions'
import {type ErrorWithId} from './types'
import {serializeError} from './useCopyErrorDetails'

describe('serializeError', () => {
it('includes error properties if an instance of `Error` is provided', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {useToast} from '@sanity/ui'
import {pick} from 'lodash'
import {useCallback} from 'react'
import {catchError, EMPTY, map, of, type OperatorFunction, tap} from 'rxjs'

import {isRecord} from '../../util'
import {strings} from './strings'
import {type ErrorWithId} from './types'

const TOAST_ID = 'copyErrorDetails'

export function useCopyErrorDetails(error: unknown, eventId?: string | null): () => void {
const toast = useToast()

return useCallback(() => {
of<ErrorWithId>({error, eventId})
.pipe(
serializeError(),
catchError((serializeErrorError) => {
console.error(serializeErrorError)
toast.push({
status: 'error',
title: strings['copy-error-details.toast.get-failed'],
id: TOAST_ID,
})
return EMPTY
}),
tap((errorDetailsString) => {
navigator.clipboard.writeText(errorDetailsString)
toast.push({
status: 'success',
title: strings['copy-error-details.toast.succeeded'],
id: TOAST_ID,
})
}),
catchError((copyErrorError) => {
console.error(copyErrorError)
toast.push({
status: 'error',
title: strings['copy-error-details.toast.copy-failed'],
id: TOAST_ID,
})
return EMPTY
}),
)
.subscribe()
}, [error, eventId, toast])
}

/**
* @internal
*/
export function serializeError(): OperatorFunction<ErrorWithId, string> {
return map<ErrorWithId, string>(({error, eventId}) => {
// Extract the non-enumerable properties of the provided `error` object. This is particularly
// useful if the provided `error` value is an instance of `Error`, whose properties are
// non-enumerable.
const errorInfo = isRecord(error) ? pick(error, Object.getOwnPropertyNames(error)) : undefined
return JSON.stringify({error: errorInfo, eventId}, null, 2)
})
}
2 changes: 1 addition & 1 deletion packages/sanity/src/core/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export * from './contextMenuButton'
export * from './DefaultDocument'
export * from './documentStatus'
export * from './documentStatusIndicator'
export * from './ErrorActions'
export * from './errorActions'
export * from './globalErrorHandler'
export * from './hookCollection'
export * from './Hotkeys'
Expand Down

0 comments on commit 0a47197

Please sign in to comment.