Skip to content

Commit

Permalink
fix(tasks): show pending tasks in document footer (#5894)
Browse files Browse the repository at this point in the history
* fix(tasks): show pending tasks in document footer

* fix(tasks): add button to open tasks

* fix(tasks): remove comment

* fix(tasks): move out of document

* fix(tasks): add conditional to tasks footer

* fix(tasks): fix ts error

* fix(tasks): update pr with comments

* fix(tasks): keep task sidebar open if clicked on badge

* fix(tasks): pluralize task text

* fix(tasks): change React.ReactNode for ReactNode and remove data-as from button

---------

Co-authored-by: Pedro Bonamin <pedrobonamin@gmail.com>
  • Loading branch information
ninaandal and pedrobonamin committed Mar 12, 2024
1 parent 9254565 commit 177bc79
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 37 deletions.
26 changes: 26 additions & 0 deletions packages/sanity/src/core/config/configPropertyReducers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {type AssetSource, type SchemaTypeDefinition} from '@sanity/types'
import {type ReactNode} from 'react'

import {type LocaleConfigContext, type LocaleDefinition, type LocaleResourceBundle} from '../i18n'
import {type Template, type TemplateItem} from '../templates'
Expand Down Expand Up @@ -308,6 +309,31 @@ export const documentCommentsEnabledReducer = (opts: {
return result
}

export const internalTasksReducer = (opts: {
config: PluginOptions
}): {footerAction: ReactNode} | undefined => {
const {config} = opts
const flattenedConfig = flattenConfig(config, [])

const result = flattenedConfig.reduce(
(acc: {footerAction: ReactNode} | undefined, {config: innerConfig}) => {
const resolver = innerConfig.__internal_tasks

if (!resolver) return acc
if (typeof resolver === 'object' && resolver.footerAction) return resolver

throw new Error(
`Expected \`__internal__tasks\` to be an object with footerAction, but received ${getPrintableType(
resolver,
)}`,
)
},
undefined,
)

return result
}

export const partialIndexingEnabledReducer = (opts: {
config: PluginOptions
initialValue: boolean
Expand Down
6 changes: 6 additions & 0 deletions packages/sanity/src/core/config/prepareConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
initialDocumentActions,
initialDocumentBadges,
initialLanguageFilter,
internalTasksReducer,
newDocumentOptionsResolver,
newSearchEnabledReducer,
partialIndexingEnabledReducer,
Expand Down Expand Up @@ -472,6 +473,10 @@ function resolveSource({
templates,
auth,
i18n: i18n.source,
// eslint-disable-next-line camelcase
__internal_tasks: internalTasksReducer({
config,
}),
document: {
actions: (partialContext) =>
resolveConfigProperty({
Expand Down Expand Up @@ -533,6 +538,7 @@ function resolveSource({
},
},
},

form: {
file: {
assetSources: resolveConfigProperty({
Expand Down
7 changes: 7 additions & 0 deletions packages/sanity/src/core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ export interface PluginOptions {
tools?: Tool[] | ComposableOption<Tool[], ConfigContext>
form?: SanityFormConfig

__internal_tasks?: {
footerAction: ReactNode
}

studio?: {
/**
* Components for the studio.
Expand Down Expand Up @@ -653,6 +657,9 @@ export interface Source {
}
}

/** @internal */
__internal_tasks?: {footerAction: ReactNode}

/**
* Form-related functionality.
* @hidden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export interface DocumentPaneContextValue {
isDeleted: boolean
isPermissionsLoading: boolean
unstable_languageFilter: DocumentLanguageFilterComponent[]
__internal_tasks?: {
footerAction: React.ReactNode
}
}

/** @internal */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import {isActionEnabled} from '@sanity/schema/_internal'
import {
type ObjectSchemaType,
Expand Down Expand Up @@ -62,12 +63,15 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => {
const schema = useSchema()
const templates = useTemplates()
const {
actions: documentActions,
badges: documentBadges,
unstable_fieldActions: fieldActionsResolver,
unstable_languageFilter: languageFilterResolver,
inspectors: inspectorsResolver,
} = useSource().document
__internal_tasks,
document: {
actions: documentActions,
badges: documentBadges,
unstable_fieldActions: fieldActionsResolver,
unstable_languageFilter: languageFilterResolver,
inspectors: inspectorsResolver,
},
} = useSource()
const presenceStore = usePresenceStore()
const paneRouter = usePaneRouter()
const setPaneParams = paneRouter.setParams
Expand Down Expand Up @@ -583,6 +587,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => {
focusPath,
inspector: currentInspector || null,
inspectors,
__internal_tasks,
onBlur: handleBlur,
onChange: handleChange,
onFocus: handleFocus,
Expand Down Expand Up @@ -622,6 +627,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => {
unstable_languageFilter: languageFilter,
}),
[
__internal_tasks,
actions,
activeViewId,
badges,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import {Flex, Hotkeys, LayerProvider, Stack, Text} from '@sanity/ui'
import {memo, useMemo, useState} from 'react'
import {type DocumentActionDescription, useTimelineSelector} from 'sanity'
Expand All @@ -17,6 +18,7 @@ interface DocumentStatusBarActionsInnerProps {

function DocumentStatusBarActionsInner(props: DocumentStatusBarActionsInnerProps) {
const {disabled, showMenu, states} = props
const {__internal_tasks} = useDocumentPane()
const [firstActionState, ...menuActionStates] = states
const [buttonElement, setButtonElement] = useState<HTMLButtonElement | null>(null)

Expand All @@ -42,6 +44,7 @@ function DocumentStatusBarActionsInner(props: DocumentStatusBarActionsInnerProps

return (
<Flex align="center" gap={1}>
{__internal_tasks && __internal_tasks.footerAction}
{firstActionState && (
<LayerProvider zOffset={200}>
<Tooltip disabled={!tooltipContent} content={tooltipContent} placement="top">
Expand Down
26 changes: 0 additions & 26 deletions packages/sanity/src/tasks/plugin/TasksBadge.tsx

This file was deleted.

44 changes: 44 additions & 0 deletions packages/sanity/src/tasks/plugin/TasksFooterOpenTasks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {useCallback, useMemo} from 'react'

import {Button} from '../../ui-components'
import {useTasks, useTasksEnabled} from '../src'

/**
* Button that shows how many pending tasks are assigned to the current document.
* Clicking it will open the task sidebar, showing the open tasks related to the document.
*
* todo: just show the tab with tasks related to the document
* @internal
*/
export function TasksFooterOpenTasks() {
const {data, activeDocument, toggleOpen, isOpen} = useTasks()
const {enabled} = useTasksEnabled()

const pendingTasks = useMemo(
() =>
data.filter((item) => {
return item.target?.document._ref === activeDocument?.documentId && item.status === 'open'
}),
[activeDocument, data],
)

const handleOnClick = useCallback(() => {
if (isOpen) {
return
}
toggleOpen()
}, [isOpen, toggleOpen])

if (pendingTasks.length === 0 || !enabled) return null

const pluralizedTask = `task${pendingTasks.length > 1 ? 's' : ''}`

return (
<Button
mode="bleed"
tooltipProps={{content: `Open ${pluralizedTask}`}}
text={`${pendingTasks.length} open ${pluralizedTask}`}
onClick={handleOnClick}
/>
)
}
9 changes: 4 additions & 5 deletions packages/sanity/src/tasks/plugin/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {definePlugin, type ObjectInputProps} from 'sanity'

import {DocumentBadge} from './TasksBadge'
import {TasksDocumentInputLayout} from './TasksDocumentInputLayout'
import {TasksFooterOpenTasks} from './TasksFooterOpenTasks'
import {TasksStudioActiveToolLayout} from './TasksStudioActiveToolLayout'
import {TasksStudioLayout} from './TasksStudioLayout'
import {TasksStudioNavbar} from './TasksStudioNavbar'
Expand All @@ -12,10 +12,9 @@ import {TasksStudioNavbar} from './TasksStudioNavbar'
*/
export const tasks = definePlugin({
name: 'sanity/tasks',
document: {
badges: (prev) => {
return (prev || []).concat(DocumentBadge)
},
// eslint-disable-next-line camelcase
__internal_tasks: {
footerAction: <TasksFooterOpenTasks />,
},
studio: {
components: {
Expand Down

0 comments on commit 177bc79

Please sign in to comment.