Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat(structure): History UI updates #7462

Draft
wants to merge 4 commits into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/sanity/src/core/form/inputs/DateInputs/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {DateInput, type DateInputProps} from './DateInput'
export {DateTimeInput, type DateTimeInputProps} from './DateTimeInput'
export {getCalendarLabels} from './utils'
3 changes: 3 additions & 0 deletions packages/sanity/src/core/form/inputs/DateInputs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export function isValidDate(date: Date): boolean {
return date instanceof Date && !isNaN(date.valueOf())
}

/**
* @internal
*/
export function getCalendarLabels(
t: (key: string, values?: Record<string, unknown>) => string,
): CalendarLabels {
Expand Down
8 changes: 5 additions & 3 deletions packages/sanity/src/core/i18n/bundles/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'calendar.weekday-names.short.wednesday': 'Wed',

/** Label for the close button label in Review Changes pane */
'changes.action.close-label': 'Close review changes',
'changes.action.close-label': 'Close history',
/** Cancel label for revert button prompt action */
'changes.action.revert-all-cancel': 'Cancel',
/** Revert all confirm label for revert button action - used on prompt button + review changes pane */
Expand Down Expand Up @@ -313,7 +313,7 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
/** Label for when the action of the change was a removal, eg a field was cleared, an array item was removed, an asset was deselected or similar */
'changes.removed-label': 'Removed',
/** Title for the Review Changes pane */
'changes.title': 'Review changes',
'changes.title': 'History',

/** --- Common components --- */
/** Tooltip text for context menu buttons */
Expand Down Expand Up @@ -359,6 +359,8 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'document-status.not-published': 'Not published',
/** Label to show in the document footer indicating the published date of the document */
'document-status.published': 'Published {{date}}',
/** Label to show in the document footer indicating the revision from date of the document */
'document-status.revision-from': 'Revision from <em>{{date}}</em>',

/** The value of the <code>_key</code> property must be a unique string. */
'form.error.duplicate-keys-alert.details.additional-description':
Expand Down Expand Up @@ -1656,7 +1658,7 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
* Label for determining since which version the changes for timeline menu dropdown are showing.
* Receives the time label as a parameter (`timestamp`).
*/
'timeline.since': 'Since: {{timestamp, datetime}}',
'timeline.since': '{{timestamp, datetime}}',
/** Label for missing change version for timeline menu dropdown are showing */
'timeline.since-version-missing': 'Since: unknown version',
/** Aria label for the action buttons in the PTE toolbar */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {RestoreIcon} from '@sanity/icons'
import {RevertIcon} from '@sanity/icons'
import {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {
type DocumentActionComponent,
Expand Down Expand Up @@ -66,14 +66,14 @@ export const HistoryRestoreAction: DocumentActionComponent = ({id, type, revisio

return {
label: t('action.restore.label'),
color: 'primary',
tone: 'caution',
onHandle: handle,
title: t(
isRevisionInitial
? 'action.restore.disabled.cannot-restore-initial'
: 'action.restore.tooltip',
),
icon: RestoreIcon,
icon: RevertIcon,
dialog,
disabled: isRevisionInitial,
}
Expand Down
32 changes: 24 additions & 8 deletions packages/sanity/src/structure/i18n/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ const structureLocaleStrings = defineLocalesResources('structure', {
/** Tooltip when publish button is waiting for validation and async tasks to complete.*/
'action.publish.waiting': 'Waiting for tasks to finish before publishing',

/** Message prompting the user to confirm that they want to restore to an earlier version*/
/** Message prompting the user to confirm that they want to restore to an earlier revision*/
'action.restore.confirm.message': 'Are you sure you want to restore this document?',
/** Fallback tooltip for when user is looking at the initial version */
'action.restore.disabled.cannot-restore-initial': "You can't restore to the initial version",
/** Fallback tooltip for when user is looking at the initial revision */
'action.restore.disabled.cannot-restore-initial': "You can't restore to the initial revision",

/** Label for the "Restore" document action */
'action.restore.label': 'Restore',
'action.restore.label': 'Revert to revision',
/** Default tooltip for the action */
'action.restore.tooltip': 'Restore to this version',
'action.restore.tooltip': 'Restore to this revision',

/** Tooltip when action is disabled because the document is not already published */
'action.unpublish.disabled.not-published': 'This document is not published',
Expand All @@ -90,7 +90,7 @@ const structureLocaleStrings = defineLocalesResources('structure', {
'This document has live edit enabled and cannot be unpublished',

/** The text for the restore button on the deleted document banner */
'banners.deleted-document-banner.restore-button.text': 'Restore most recent version',
'banners.deleted-document-banner.restore-button.text': 'Restore most recent revision',
/** The text content for the deleted document banner */
'banners.deleted-document-banner.text': 'This document has been deleted.',
/** The text content for the deprecated document type banner */
Expand Down Expand Up @@ -143,7 +143,14 @@ const structureLocaleStrings = defineLocalesResources('structure', {
'buttons.split-pane-close-button.title': 'Close split pane',
/** The title for the close group button on the split pane on the document panel header */
'buttons.split-pane-close-group-button.title': 'Close pane group',

/** The label used in the changes inspector for the from selector */
'changes.from.label': 'From',
/* The label for the history tab in the changes inspector*/
'changes.tab.history': 'History',
/* The label for the review tab in the changes inspector*/
'changes.tab.review-changes': 'Review changes',
/** The label used in the changes inspector for the to selector */
'changes.to.label': 'To',
/** The text in the "Cancel" button in the confirm delete dialog that cancels the action and closes the dialog */
'confirm-delete-dialog.cancel-button.text': 'Cancel',
/** Used in `confirm-delete-dialog.cdr-summary.title` */
Expand Down Expand Up @@ -374,7 +381,7 @@ const structureLocaleStrings = defineLocalesResources('structure', {
'<Strong>{{title}}</Strong> was restored',
/** The text when an unpublish operation succeeded */
'panes.document-operation-results.operation-success_unpublish':
'<Strong>{{title}}</Strong> was unpublished. A draft has been created from the latest published version.',
'<Strong>{{title}}</Strong> was unpublished. A draft has been created from the latest published revision.',
/** The document title shown when document title is "undefined" in operation message */
'panes.document-operation-results.operation-undefined-title': 'Untitled',
/** The title of the reconnecting toast */
Expand Down Expand Up @@ -445,6 +452,15 @@ const structureLocaleStrings = defineLocalesResources('structure', {
'structure-error.reload-button.text': 'Reload',
/** Labels the structure path of the structure error screen */
'structure-error.structure-path.label': 'Structure path',

/** The aria label for the menu button in the timeline item */
'timeline-item.menu-button.aria-label': 'Open action menu',
/** The text for the tooltip in menu button the timeline item */
'timeline-item.menu-button.tooltip': 'Actions',
/** The text for the collapse action in the timeline item menu */
'timeline-item.menu.action-collapse': 'Collapse',
/** The text for the expand action in the timeline item menu */
'timeline-item.menu.action-expand': 'Expand',
})

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => {
}

if (resolvedChangesInspector) {
openInspector(resolvedChangesInspector.name)
openInspector(resolvedChangesInspector.name, {changesInspectorTab: 'review'})
}
}, [features.reviewChanges, openInspector, resolvedChangesInspector])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {type Path} from 'sanity-diff-patch'
import {styled} from 'styled-components'

import {TooltipDelayGroupProvider} from '../../../../ui-components'
import {Pane, PaneFooter, usePaneLayout} from '../../../components'
import {Pane, PaneFooter, usePaneLayout, usePaneRouter} from '../../../components'
import {DOCUMENT_PANEL_PORTAL_ELEMENT} from '../../../constants'
import {structureLocaleNamespace} from '../../../i18n'
import {useStructureTool} from '../../../useStructureTool'
Expand Down Expand Up @@ -78,7 +78,7 @@ export function DocumentLayout() {
schemaType,
value,
} = useDocumentPane()

const {params: paneParams} = usePaneRouter()
const {features} = useStructureTool()
const {t} = useTranslation(structureLocaleNamespace)
const {collapsed: layoutCollapsed} = usePaneLayout()
Expand Down Expand Up @@ -208,7 +208,7 @@ export function DocumentLayout() {
<Flex direction="column" flex={1} height={layoutCollapsed ? undefined : 'fill'}>
<StyledChangeConnectorRoot
data-testid="change-connector-root"
isReviewChangesOpen={changesOpen}
isReviewChangesOpen={changesOpen && paneParams?.changesInspectorTab === 'review'}
onOpenReviewChanges={onHistoryOpen}
onSetFocus={onConnectorSetFocus}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import {
useMemo,
useState,
} from 'react'
import {
type DocumentActionDescription,
useFieldActions,
useTimelineSelector,
useTranslation,
} from 'sanity'
import {type DocumentActionDescription, useFieldActions, useTranslation} from 'sanity'

import {Button, TooltipDelayGroupProvider} from '../../../../../ui-components'
import {
Expand All @@ -33,7 +28,6 @@ import {type PaneMenuItem} from '../../../../types'
import {useStructureTool} from '../../../../useStructureTool'
import {ActionDialogWrapper, ActionMenuListItem} from '../../statusBar/ActionMenuButton'
import {isRestoreAction} from '../../statusBar/DocumentStatusBarActions'
import {TimelineMenu} from '../../timeline'
import {useDocumentPane} from '../../useDocumentPane'
import {DocumentHeaderTabs} from './DocumentHeaderTabs'
import {DocumentHeaderTitle} from './DocumentHeaderTitle'
Expand Down Expand Up @@ -84,9 +78,6 @@ export const DocumentPanelHeader = memo(
const contextMenuNodes = useMemo(() => menuNodes.filter(isNotMenuNodeButton), [menuNodes])
const showTabs = views.length > 1

// Subscribe to external timeline state changes
const rev = useTimelineSelector(timelineStore, (state) => state.revTime)

const {collapsed, isLast} = usePane()
// Prevent focus if this is the last (non-collapsed) pane.
const tabIndex = isLast && !collapsed ? -1 : 0
Expand Down Expand Up @@ -152,7 +143,6 @@ export const DocumentPanelHeader = memo(
/>
)
}
subActions={<TimelineMenu chunk={rev} mode="rev" placement="bottom-end" />}
actions={
<Flex align="center" gap={1}>
{unstable_languageFilter.length > 0 && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {type ObjectDiff} from '@sanity/diff'
import {AvatarStack, BoundaryElementProvider, Box, Card, Flex} from '@sanity/ui'
import {AvatarStack, BoundaryElementProvider, Box, Card, Flex, Text} from '@sanity/ui'
import {type ReactElement, useMemo, useRef} from 'react'
import {
ChangeFieldWrapper,
ChangeList,
DiffTooltip,
type DocumentChangeContextInstance,
type DocumentInspectorProps,
LoadingBlock,
NoChanges,
type ObjectSchemaType,
Expand All @@ -18,7 +17,7 @@ import {
import {DocumentChangeContext} from 'sanity/_singletons'
import {styled} from 'styled-components'

import {DocumentInspectorHeader} from '../../documentInspector'
import {structureLocaleNamespace} from '../../../../i18n'
import {TimelineMenu} from '../../timeline'
import {useDocumentPane} from '../../useDocumentPane'
import {collectLatestAuthorAnnotations} from './helpers'
Expand All @@ -30,12 +29,21 @@ const Scroller = styled(ScrollContainer)`
scroll-behavior: smooth;
`

export function ChangesInspector(props: DocumentInspectorProps): ReactElement {
const {onClose} = props
const Grid = styled(Box)`
&:not([hidden]) {
display: grid;
}
grid-template-columns: 48px 1fr;
align-items: center;
gap: 0.25em;
`

export function ChangesInspector({showChanges}: {showChanges: boolean}): ReactElement {
const {documentId, schemaType, timelineError, timelineStore, value} = useDocumentPane()
const scrollRef = useRef<HTMLDivElement | null>(null)

// Subscribe to external timeline state changes
const rev = useTimelineSelector(timelineStore, (state) => state.revTime)
const diff = useTimelineSelector(timelineStore, (state) => state.diff)
const onOlderRevision = useTimelineSelector(timelineStore, (state) => state.onOlderRevision)
const selectionState = useTimelineSelector(timelineStore, (state) => state.selectionState)
Expand All @@ -46,6 +54,7 @@ export function ChangesInspector(props: DocumentInspectorProps): ReactElement {
// Note that we are using the studio core namespace here, as changes theoretically should
// be part of Sanity core (needs to be moved from structure at some point)
const {t} = useTranslation('studio')
const {t: structureT} = useTranslation(structureLocaleNamespace)

const documentContext: DocumentChangeContextInstance = useMemo(
() => ({
Expand All @@ -67,45 +76,48 @@ export function ChangesInspector(props: DocumentInspectorProps): ReactElement {

return (
<Flex data-testid="review-changes-pane" direction="column" height="fill" overflow="hidden">
<DocumentInspectorHeader
as="header"
closeButtonLabel={t('changes.action.close-label')}
flex="none"
onClose={onClose}
title={t('changes.title')}
>
<Flex gap={1} padding={3} paddingTop={0} paddingBottom={2}>
<Box flex={1}>
<TimelineMenu mode="since" chunk={sinceTime} placement="bottom-start" />
</Box>
<Box padding={3}>
<Grid paddingX={1}>
<Text size={1} muted>
{structureT('changes.from.label')}
</Text>

<Box flex="none">
<TimelineMenu mode="since" chunk={sinceTime} placement="bottom-start" />
<Text size={1} muted>
{structureT('changes.to.label')}
</Text>
<TimelineMenu chunk={rev} mode="rev" placement="bottom-end" />
</Grid>
{changeAnnotations.length > 0 && (
<Flex width={'full'} justify={'flex-end'} padding={3} paddingBottom={0}>
<DiffTooltip
annotations={changeAnnotations}
description={t('changes.changes-by-author')}
portal
>
<AvatarStack maxLength={4} aria-label={t('changes.changes-by-author')}>
{changeAnnotations.map(({author}) => (
<UserAvatar key={author} user={author} />
<UserAvatar key={author} user={author} size={0} />
))}
</AvatarStack>
</DiffTooltip>
</Box>
</Flex>
</DocumentInspectorHeader>
</Flex>
)}
</Box>

<Card flex={1}>
<BoundaryElementProvider element={scrollRef.current}>
<Scroller data-ui="Scroller" ref={scrollRef}>
<Box flex={1} padding={4}>
<Content
diff={diff}
documentContext={documentContext}
error={timelineError}
loading={loading}
schemaType={schemaType}
/>
<Box flex={1} padding={3} paddingTop={2} height="fill">
{showChanges && (
<Content
diff={diff}
documentContext={documentContext}
error={timelineError}
loading={loading}
schemaType={schemaType}
/>
)}
</Box>
</Scroller>
</BoundaryElementProvider>
Expand Down
Loading
Loading