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

fix(core): add opt out option to studioAnnouncements #7820

Merged
merged 1 commit into from
Nov 15, 2024
Merged
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
3 changes: 3 additions & 0 deletions dev/studio-e2e-testing/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,7 @@ export default defineConfig({
enabled: true,
},
},
announcements: {
enabled: false,
},
})
23 changes: 23 additions & 0 deletions packages/sanity/src/core/config/configPropertyReducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,26 @@ export const createFallbackOriginReducer = (config: PluginOptions): string | und

return result
}

export const announcementsEnabledReducer = (opts: {
config: PluginOptions
initialValue: boolean
}): boolean => {
const {config, initialValue} = opts
const flattenedConfig = flattenConfig(config, [])

const result = flattenedConfig.reduce((acc, {config: innerConfig}) => {
const resolver = innerConfig.announcements?.enabled

if (!resolver && typeof resolver !== 'boolean') return acc
if (typeof resolver === 'boolean') return resolver

throw new Error(
`Expected \`announcements.enabled\` to be a boolean, but received ${getPrintableType(
resolver,
)}`,
)
}, initialValue)

return result
}
5 changes: 5 additions & 0 deletions packages/sanity/src/core/config/prepareConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {operatorDefinitions} from '../studio/components/navbar/search/definition
import {type InitialValueTemplateItem, type Template, type TemplateItem} from '../templates'
import {EMPTY_ARRAY, isNonNullable} from '../util'
import {
announcementsEnabledReducer,
createFallbackOriginReducer,
documentActionsReducer,
documentBadgesReducer,
Expand Down Expand Up @@ -663,6 +664,10 @@ function resolveSource({
fallbackStudioOrigin: createFallbackOriginReducer(config),
},
},

announcements: {
enabled: announcementsEnabledReducer({config, initialValue: true}),
},
}

return source
Expand Down
14 changes: 14 additions & 0 deletions packages/sanity/src/core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,13 @@ export interface PluginOptions {
* @beta
*/
onUncaughtError?: (error: Error, errorInfo: ErrorInfo) => void
/**
* @hidden
* @internal
*/
announcements?: {
enabled: boolean
}
}

/** @internal */
Expand Down Expand Up @@ -810,6 +817,13 @@ export interface Source {
* @beta
*/
onUncaughtError?: (error: Error, errorInfo: ErrorInfo) => void
/**
* @hidden
* @internal
*/
announcements?: {
enabled: boolean
}
}

/** @internal */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {catchError, combineLatest, map, type Observable, startWith} from 'rxjs'
import {StudioAnnouncementContext} from 'sanity/_singletons'

import {useClient} from '../../hooks/useClient'
import {useSource} from '../../studio/source'
import {useWorkspace} from '../../studio/workspace'
import {SANITY_VERSION} from '../../version'
import {
Expand All @@ -28,11 +29,7 @@ interface StudioAnnouncementsProviderProps {
}
const CLIENT_OPTIONS = {apiVersion: 'v2024-09-19'}

/**
* @internal
* @hidden
*/
export function StudioAnnouncementsProvider({children}: StudioAnnouncementsProviderProps) {
function StudioAnnouncementsProviderInner({children}: StudioAnnouncementsProviderProps) {
const telemetry = useTelemetry()
const [dialogMode, setDialogMode] = useState<DialogMode | null>(null)
const [isCardDismissed, setIsCardDismissed] = useState(false)
Expand Down Expand Up @@ -159,3 +156,16 @@ export function StudioAnnouncementsProvider({children}: StudioAnnouncementsProvi
</StudioAnnouncementContext.Provider>
)
}

/**
* @internal
* @hidden
*/
export function StudioAnnouncementsProvider(props: StudioAnnouncementsProviderProps) {
const source = useSource()

if (source.announcements?.enabled) {
return <StudioAnnouncementsProviderInner {...props} />
}
return props.children
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import {fireEvent, render, renderHook, waitFor} from '@testing-library/react'
import {type ReactNode} from 'react'
import {of} from 'rxjs'
import {defineConfig} from 'sanity'
import {type Config, defineConfig} from 'sanity'
import {beforeAll, beforeEach, describe, expect, test, vi} from 'vitest'

import {createTestProvider} from '../../../../../test/testUtils/TestProvider'
Expand Down Expand Up @@ -36,10 +36,11 @@ vi.mock('@sanity/client', () => ({
vi.mock('../../../hooks/useClient')
const useClientMock = useClient as ReturnType<typeof vi.fn>

const mockObservableRequest = vi.fn((announcements) => of(announcements))
const mockClient = (announcements: StudioAnnouncementDocument[]) => {
useClientMock.mockReturnValue({
observable: {
request: () => of(announcements),
request: () => mockObservableRequest(announcements),
},
})
}
Expand All @@ -55,9 +56,12 @@ const config = defineConfig({
projectId: 'test',
dataset: 'test',
})
async function createAnnouncementWrapper() {
async function createAnnouncementWrapper(configOverride: Partial<Config> = {}) {
const wrapper = await createTestProvider({
config,
config: {
...config,
...configOverride,
},
resources: [],
})

Expand Down Expand Up @@ -114,7 +118,8 @@ describe('StudioAnnouncementsProvider', () => {
const {result} = renderHook(() => useStudioAnnouncements(), {
wrapper,
})

expect(seenAnnouncementsMock).toBeCalled()
expect(mockObservableRequest).toBeCalled()
expect(result.current.unseenAnnouncements).toEqual([])
expect(result.current.studioAnnouncements).toEqual(mockAnnouncements)
})
Expand Down Expand Up @@ -641,3 +646,24 @@ describe('StudioAnnouncementsProvider', () => {
})
})
})

describe('StudioAnnouncementsProvider-Disabled', () => {
let wrapper = ({children}: {children: ReactNode}) => children
beforeAll(async () => {
// Reset all mocks
vi.clearAllMocks()
wrapper = await createAnnouncementWrapper({
announcements: {enabled: false},
})
})
test('if the feature is disabled, the client should not be called', () => {
const {result} = renderHook(() => useStudioAnnouncements(), {
wrapper,
})

expect(result.current.unseenAnnouncements).toEqual([])
expect(result.current.studioAnnouncements).toEqual([])
expect(seenAnnouncementsMock).not.toBeCalled()
expect(mockObservableRequest).not.toBeCalled()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import {type StudioAnnouncementsContextValue} from './types'

export function useStudioAnnouncements(): StudioAnnouncementsContextValue {
const context = useContext(StudioAnnouncementContext)

if (!context) {
throw new Error('useStudioAnnouncements: missing context value')
return {
studioAnnouncements: [],
unseenAnnouncements: [],
onDialogOpen: () => {},
}
}

return context
Expand Down
Loading