Skip to content

Commit

Permalink
[field] Improve appearance of value/diff component errors
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars committed Oct 6, 2020
1 parent 23d0920 commit 5d50383
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 21 deletions.
5 changes: 5 additions & 0 deletions packages/@sanity/field/src/@types/parts.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ declare module 'part:@sanity/base/undo-icon' {
export default UndoIcon
}

declare module 'part:@sanity/base/error-outline-icon' {
const ErrorOutlineIcon: React.ComponentType<{}>
export default ErrorOutlineIcon
}

declare module 'part:@sanity/components/avatar' {
export * from '@sanity/components/src/avatar'
}
Expand Down
22 changes: 22 additions & 0 deletions packages/@sanity/field/src/diff/changes/DiffErrorBoundary.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import 'part:@sanity/base/theme/variables-style';

.root {
display: flex;
}

.icon {
color: var(--state-danger-color);

@nest & svg {
font-size: calc(17 / 16 * 1em);

@nest &[data-sanity-icon='true'] {
font-size: calc(25 / 16 * 1em);
margin: -4px;
}
}
}

.message {
padding-left: var(--small-padding);
}
28 changes: 18 additions & 10 deletions packages/@sanity/field/src/diff/changes/DiffErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as React from 'react'
import ErrorOutlineIcon from 'part:@sanity/base/error-outline-icon'
import styles from './ValueError.css'

declare const __DEV__: boolean

Expand Down Expand Up @@ -31,17 +33,23 @@ export class DiffErrorBoundary extends React.Component<BoundaryProps, BoundarySt
render() {
const isDev = __DEV__ === true
const {error} = this.state
if (error) {
const help = isDev ? <p>Check the developer console for more information.</p> : null
return (
<div>
<h2>Error</h2>
<p>The component responsible for showing the changes of this field crashed.</p>
{help}
</div>
)
if (!error) {
return this.props.children
}

return this.props.children
const help = isDev ? <p>Check the developer console for more information.</p> : null
return (
<>
<div className={styles.root}>
<span className={styles.icon}>
<ErrorOutlineIcon />
</span>
<div className={styles.message}>
The component responsible for showing the changes to this field has crashed.
{help}
</div>
</div>
</>
)
}
}
5 changes: 5 additions & 0 deletions packages/@sanity/field/src/diff/changes/FieldChange.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
margin-bottom: 1em;
}

.error {
composes: root;
border-left-color: var(--state-danger-color);
}

.diffComponent {
}

Expand Down
15 changes: 11 additions & 4 deletions packages/@sanity/field/src/diff/changes/FieldChange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {RevertChangesButton} from './RevertChangesButton'
import {undoChange} from './undoChange'

import styles from './FieldChange.css'
import {ValueError} from './ValueError'

const FallbackDiff = () => <div>Missing diff</div>

Expand All @@ -21,14 +22,20 @@ export function FieldChange({change}: {change: FieldChangeNode}) {
[documentId, change.key, change.diff]
)

const rootClass = change.error ? styles.error : styles.root

return (
<div className={styles.root}>
<div className={rootClass}>
{change.renderHeader && <ChangeHeader titlePath={change.titlePath} />}

<div className={styles.diffComponent}>
<DiffErrorBoundary>
<DiffComponent diff={change.diff} schemaType={change.schemaType} />
</DiffErrorBoundary>
{change.error ? (
<ValueError error={change.error} />
) : (
<DiffErrorBoundary>
<DiffComponent diff={change.diff} schemaType={change.schemaType} />
</DiffErrorBoundary>
)}
</div>

<div className={styles.revertChangesButtonContainer}>
Expand Down
23 changes: 23 additions & 0 deletions packages/@sanity/field/src/diff/changes/ValueError.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@import 'part:@sanity/base/theme/variables-style';

.root {
display: flex;
align-items: center;
}

.icon {
color: var(--state-danger-color);

@nest & svg {
font-size: calc(17 / 16 * 1em);

@nest &[data-sanity-icon='true'] {
font-size: calc(25 / 16 * 1em);
margin: -4px;
}
}
}

.message {
padding-left: var(--small-padding);
}
14 changes: 12 additions & 2 deletions packages/@sanity/field/src/diff/changes/ValueError.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import * as React from 'react'
import ErrorOutlineIcon from 'part:@sanity/base/error-outline-icon'
import {FieldValueError} from '../../validation'
import styles from './ValueError.css'

export function ValueError(props: any) {
return <div>Value error</div>
export function ValueError({error}: {error: FieldValueError}) {
return (
<div className={styles.root}>
<span className={styles.icon}>
<ErrorOutlineIcon />
</span>
<span className={styles.message}>Value error: {error.message}</span>
</div>
)
}
4 changes: 2 additions & 2 deletions packages/@sanity/field/src/diff/changes/buildChangeList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
ArrayDiff,
DiffComponent
} from '../../types'
import {ValueError} from './ValueError'

export function buildDocumentChangeList(schemaType: ObjectSchemaType, diff: ObjectDiff) {
const changes = buildChangeList(schemaType, diff)
Expand Down Expand Up @@ -68,11 +67,12 @@ export function buildChangeList(
type: 'field',
diff,
path,
error,
titlePath,
schemaType,
renderHeader,
key: pathToString(path),
diffComponent: error ? ValueError : component,
diffComponent: error ? undefined : component,
childChanges:
childChanges.length === 1 && childChanges[0].type === 'group'
? childChanges[0].changes
Expand Down
2 changes: 2 additions & 0 deletions packages/@sanity/field/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
StringSegmentUnchanged as AgnosticStringSegmentUnchanged
} from '@sanity/diff'
import {Path} from './paths'
import {FieldValueError} from './validation'

/**
* History timeline / chunking
Expand Down Expand Up @@ -212,6 +213,7 @@ export interface FieldChangeNode {
diff: Diff
key: string
path: Path
error?: FieldValueError
titlePath: ChangeTitlePath
schemaType: SchemaType
renderHeader: boolean
Expand Down
16 changes: 13 additions & 3 deletions packages/@sanity/field/src/validation/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {SchemaType, ObjectSchemaType} from '../diff'

export function getValueError(value: unknown, schemaType: SchemaType) {
export interface FieldValueError {
message: string
value: unknown
}

export function getValueError(value: unknown, schemaType: SchemaType): FieldValueError | undefined {
const {jsonType} = schemaType
const valueType = Array.isArray(value) ? 'array' : typeof value

Expand All @@ -9,11 +14,16 @@ export function getValueError(value: unknown, schemaType: SchemaType) {
}

if (valueType !== jsonType) {
return {error: `Value is ${valueType}, expected ${jsonType}`, value}
return {message: `Value is ${valueType}, expected ${jsonType}`, value}
}

if (isObjectType(schemaType) && isObjectValue(value)) {
return schemaType.fields.find(field => getValueError(value[field.name], field.type))
for (const field of schemaType.fields) {
const fieldError = getValueError(value[field.name], field.type)
if (fieldError) {
return fieldError
}
}
}

return undefined
Expand Down

0 comments on commit 5d50383

Please sign in to comment.