@@ -30,6 +30,8 @@ const infiniteOptionsMocks = vi.hoisted(() => ({
3030
3131const chartOptions = vi . hoisted ( ( ) => ( { current : undefined as unknown } ) )
3232
33+ const editionMock = vi . hoisted ( ( ) => ( { value : 'COMMUNITY' } ) )
34+
3335const queryData = vi . hoisted ( ( ) => ( {
3436 activity : {
3537 data : [
@@ -190,9 +192,13 @@ vi.mock('@/context/permission-state', () => ({
190192 workspacePermissionKeysAtom : permissionState . workspaceKeysAtom ,
191193} ) )
192194
193- vi . mock ( '@/features/system-features/state' , ( ) => ( {
194- knowledgeFsUploadEnabledAtom : systemFeaturesState . uploadAvailableAtom ,
195- } ) )
195+ vi . mock ( '@/features/system-features/state' , async ( ) => {
196+ const { atom } = await import ( 'jotai' )
197+ return {
198+ deploymentEditionAtom : atom ( ( ) => editionMock . value ) ,
199+ knowledgeFsUploadEnabledAtom : systemFeaturesState . uploadAvailableAtom ,
200+ }
201+ } )
196202
197203vi . mock ( '../../space/context' , ( ) => ( {
198204 useKnowledgeSpacePermission : ( permission : string ) =>
@@ -367,6 +373,7 @@ function renderOverviewWithNuqs(
367373describe ( 'KnowledgeOverviewPage' , ( ) => {
368374 beforeEach ( ( ) => {
369375 vi . clearAllMocks ( )
376+ editionMock . value = 'COMMUNITY'
370377 tasksQueryState . isError = false
371378 tasksQueryState . isPending = false
372379 tasksQueryState . isRefetching = false
@@ -821,6 +828,86 @@ describe('KnowledgeOverviewPage', () => {
821828 )
822829 } )
823830
831+ it ( 'limits cloud activity filters to the most recent 90 calendar days' , async ( ) => {
832+ vi . useFakeTimers ( { toFake : [ 'Date' ] } )
833+ vi . setSystemTime ( new Date ( 2026 , 8 , 8 , 12 ) )
834+ editionMock . value = 'CLOUD'
835+ const user = userEvent . setup ( )
836+ const earliest = dayjs ( ) . subtract ( 89 , 'day' ) . startOf ( 'day' )
837+
838+ renderOverviewWithNuqs ( < KnowledgeOverviewPage knowledgeSpaceId = "space-1" /> )
839+ expect ( queryOptionsMocks . activity . mock . lastCall ?. [ 0 ] ) . toMatchObject ( {
840+ input : { query : { from_at : earliest . toISOString ( ) } } ,
841+ } )
842+ await user . click ( screen . getByRole ( 'button' , { name : 'knowledgeOverview.overview.allActivity' } ) )
843+ await user . click ( screen . getByRole ( 'combobox' , { name : 'knowledgeOverview.overview.timeRange' } ) )
844+ expect (
845+ screen . queryByRole ( 'option' , { name : 'knowledgeOverview.overview.allTime' } ) ,
846+ ) . not . toBeInTheDocument ( )
847+ await user . click (
848+ await screen . findByRole ( 'option' , { name : 'knowledgeOverview.overview.last90Days' } ) ,
849+ )
850+
851+ const options = infiniteOptionsMocks . activity . mock . lastCall ?. [ 0 ] as {
852+ input : ( cursor : string | null ) => { query : Record < string , unknown > }
853+ }
854+ expect ( options . input ( null ) . query . from_at ) . toBe ( earliest . toISOString ( ) )
855+ expect ( options . input ( 'older' ) . query ) . toMatchObject ( {
856+ cursor : 'older' ,
857+ from_at : earliest . toISOString ( ) ,
858+ to_at : dayjs ( ) . endOf ( 'day' ) . toISOString ( ) ,
859+ } )
860+
861+ const ordinal = ( day : number ) => {
862+ const suffix =
863+ [ 'th' , 'st' , 'nd' , 'rd' ] [ day % 100 > 10 && day % 100 < 14 ? 0 : day % 10 ] ?? 'th'
864+ return `${ day } ${ suffix } `
865+ }
866+ const calendarLabel = ( date : dayjs . Dayjs ) =>
867+ new RegExp ( `${ date . format ( 'MMMM' ) } ${ ordinal ( date . date ( ) ) } , ${ date . year ( ) } ` )
868+ await user . click (
869+ screen . getByRole ( 'button' , { name : / k n o w l e d g e O v e r v i e w \. o v e r v i e w \. t i m e R a n g e s t a r t / } ) ,
870+ )
871+ expect (
872+ screen . getByRole ( 'button' , { name : calendarLabel ( earliest . subtract ( 1 , 'day' ) ) } ) ,
873+ ) . toBeDisabled ( )
874+ expect ( screen . getByRole ( 'button' , { name : calendarLabel ( earliest ) } ) ) . toBeEnabled ( )
875+ await user . click ( screen . getByRole ( 'button' , { name : calendarLabel ( earliest . add ( 1 , 'day' ) ) } ) )
876+ expect (
877+ screen . getByRole ( 'combobox' , { name : 'knowledgeOverview.overview.timeRange' } ) ,
878+ ) . toHaveTextContent ( 'filter.period.custom' )
879+ expect ( infiniteOptionsMocks . activity . mock . lastCall ?. [ 0 ] . input ( null ) . query . from_at ) . toBe (
880+ earliest . add ( 1 , 'day' ) . toISOString ( ) ,
881+ )
882+ } )
883+
884+ it . each ( [ 'COMMUNITY' , 'ENTERPRISE' ] ) (
885+ 'preserves all-time activity queries for %s' ,
886+ async ( edition ) => {
887+ editionMock . value = edition
888+ const user = userEvent . setup ( )
889+ renderOverviewWithNuqs ( < KnowledgeOverviewPage knowledgeSpaceId = "space-1" /> )
890+ expect ( queryOptionsMocks . activity . mock . lastCall ?. [ 0 ] . input . query ) . not . toHaveProperty (
891+ 'from_at' ,
892+ )
893+ await user . click (
894+ screen . getByRole ( 'button' , { name : 'knowledgeOverview.overview.allActivity' } ) ,
895+ )
896+ await user . click (
897+ screen . getByRole ( 'combobox' , { name : 'knowledgeOverview.overview.timeRange' } ) ,
898+ )
899+ await user . click (
900+ await screen . findByRole ( 'option' , { name : 'knowledgeOverview.overview.allTime' } ) ,
901+ )
902+
903+ const options = infiniteOptionsMocks . activity . mock . lastCall ?. [ 0 ] as {
904+ input : ( cursor : string | null ) => { query : Record < string , unknown > }
905+ }
906+ expect ( options . input ( null ) . query ) . not . toHaveProperty ( 'from_at' )
907+ expect ( options . input ( null ) . query ) . not . toHaveProperty ( 'to_at' )
908+ } ,
909+ )
910+
824911 it ( 'shows safe activity details and relative times for today in the drawer' , async ( ) => {
825912 // At midnight, "two hours ago" is yesterday and deliberately uses an absolute date.
826913 vi . useFakeTimers ( { toFake : [ 'Date' ] } )
0 commit comments