1+ import { ViewLayout } from '@/application/types' ;
12import { notify } from '@/components/_shared/notify' ;
3+ import PageIcon from '@/components/_shared/view-icon/PageIcon' ;
24import { useAppHandlers } from '@/components/app/app.hooks' ;
35import { useLoadPublishInfo } from '@/components/app/share/publish.hooks' ;
46import PublishLinkPreview from '@/components/app/share/PublishLinkPreview' ;
5- import { Button , CircularProgress , Typography } from '@mui/material' ;
7+ import { Button , CircularProgress , Divider , Typography } from '@mui/material' ;
68import React , { useCallback , useEffect } from 'react' ;
79import { useTranslation } from 'react-i18next' ;
810import { ReactComponent as PublishIcon } from '@/assets/publish.svg' ;
11+ import { ReactComponent as CheckboxCheckSvg } from '@/assets/check_filled.svg' ;
12+ import { ReactComponent as CheckboxUncheckSvg } from '@/assets/uncheck.svg' ;
913
1014function PublishPanel ( { viewId, opened, onClose } : { viewId : string ; onClose : ( ) => void ; opened : boolean } ) {
1115 const { t } = useTranslation ( ) ;
@@ -24,6 +28,7 @@ function PublishPanel ({ viewId, opened, onClose }: { viewId: string; onClose: (
2428 } = useLoadPublishInfo ( viewId ) ;
2529 const [ unpublishLoading , setUnpublishLoading ] = React . useState < boolean > ( false ) ;
2630 const [ publishLoading , setPublishLoading ] = React . useState < boolean > ( false ) ;
31+ const [ visibleViewId , setVisibleViewId ] = React . useState < string [ ] | undefined > ( undefined ) ;
2732
2833 useEffect ( ( ) => {
2934 if ( opened ) {
@@ -35,8 +40,10 @@ function PublishPanel ({ viewId, opened, onClose }: { viewId: string; onClose: (
3540 if ( ! publish || ! view ) return ;
3641
3742 setPublishLoading ( true ) ;
43+ const newPublishName = publishName || publishInfo ?. publishName || undefined ;
44+
3845 try {
39- await publish ( view , publishName || publishInfo ?. publishName ) ;
46+ await publish ( view , newPublishName , visibleViewId ) ;
4047 await loadPublishInfo ( ) ;
4148 notify . success ( t ( 'publish.publishSuccessfully' ) ) ;
4249 // eslint-disable-next-line
@@ -45,7 +52,7 @@ function PublishPanel ({ viewId, opened, onClose }: { viewId: string; onClose: (
4552 } finally {
4653 setPublishLoading ( false ) ;
4754 }
48- } , [ loadPublishInfo , publish , t , view , publishInfo ] ) ;
55+ } , [ loadPublishInfo , publish , t , view , publishInfo , visibleViewId ] ) ;
4956
5057 const handleUnpublish = useCallback ( async ( ) => {
5158 if ( ! view || ! unpublish ) return ;
@@ -103,22 +110,84 @@ function PublishPanel ({ viewId, opened, onClose }: { viewId: string; onClose: (
103110 </ div > ;
104111 } , [ handlePublish , handleUnpublish , isOwner , isPublisher , onClose , publishInfo , t , unpublishLoading , url , view ] ) ;
105112
113+ const layout = view ?. layout ;
114+ const isDatabase = layout !== undefined ? [ ViewLayout . Grid , ViewLayout . Board , ViewLayout . Calendar ] . includes ( layout ) : false ;
115+ const hasPublished = view ?. is_published ;
116+
117+ useEffect ( ( ) => {
118+ if ( ! hasPublished && isDatabase && view ) {
119+ const childIds = [ view . view_id , ...view . children . map ( ( child ) => child . view_id ) ] ;
120+
121+ setVisibleViewId ( childIds ) ;
122+ } else {
123+ setVisibleViewId ( undefined ) ;
124+ }
125+ } , [ hasPublished , isDatabase , view ] ) ;
126+
106127 const renderUnpublished = useCallback ( ( ) => {
107- return < Button
108- onClick = { ( ) => {
109- void handlePublish ( ) ;
110- } }
111- variant = { 'contained' }
112- className = { 'w-full' }
113- color = { 'primary' }
114- startIcon = { publishLoading ? < CircularProgress
115- color = { 'inherit' }
116- size = { 16 }
117- /> : undefined }
118- > {
119- t ( 'shareAction.publish' )
120- } </ Button > ;
121- } , [ handlePublish , publishLoading , t ] ) ;
128+ if ( ! view ) return null ;
129+ const list = [ view , ...view . children ] ;
130+
131+ return < div className = { 'flex flex-col gap-4 w-full' } >
132+ { isDatabase &&
133+ < div className = { 'flex mt-2 text-sm flex-col gap-3 rounded-[16px] border border-line-divider py-3 px-4' } >
134+ < div className = { 'text-text-caption' } > { t ( 'publishSelectedViews' , {
135+ count : visibleViewId ?. length || 0 ,
136+ } ) } </ div >
137+ < Divider />
138+ < div className = { 'flex flex-col gap-1 overflow-y-auto max-h-[300px] appflowy-scroller overflow-x-hidden' } >
139+ { list . map ( ( item ) => {
140+ const id = item . view_id ;
141+ const isCurrentView = view . view_id === item . view_id ;
142+
143+ const selected = visibleViewId ?. includes ( item . view_id ) ;
144+
145+ return < Button
146+ disabled = { isCurrentView }
147+ onClick = { ( ) => {
148+ setVisibleViewId ( prev => {
149+ const checked = prev ?. includes ( id ) ;
150+
151+ if ( checked ) {
152+ return prev ?. filter ( ( i ) => i !== id ) ;
153+ } else {
154+ return [ ...( prev || [ ] ) , id ] ;
155+ }
156+
157+ } ) ;
158+ } }
159+ key = { id }
160+ className = { 'flex justify-start items-center' }
161+ size = { 'small' }
162+ startIcon = { selected ? < CheckboxCheckSvg className = { 'w-5 h-5' } /> :
163+ < CheckboxUncheckSvg className = { 'w-5 h-5' } /> }
164+ color = { 'inherit' }
165+ >
166+ < div className = { 'flex items-center gap-2' } >
167+ < PageIcon view = { item } />
168+ { item . name || t ( 'untitled' ) }
169+ </ div >
170+
171+ </ Button > ;
172+ } ) }
173+ </ div >
174+
175+ </ div > }
176+ < Button
177+ onClick = { ( ) => {
178+ void handlePublish ( ) ;
179+ } }
180+ variant = { 'contained' }
181+ className = { 'w-full' }
182+ color = { 'primary' }
183+ startIcon = { publishLoading ? < CircularProgress
184+ color = { 'inherit' }
185+ size = { 16 }
186+ /> : undefined }
187+ > {
188+ t ( 'shareAction.publish' )
189+ } </ Button > </ div > ;
190+ } , [ handlePublish , isDatabase , publishLoading , t , view , visibleViewId ] ) ;
122191
123192 return (
124193 < div className = { 'flex flex-col gap-2 w-full overflow-hidden' } >
0 commit comments