Add loader if channel is being published and community library side p…#5523
Conversation
| # Prevent creating submissions while a publish is in progress | ||
| if getattr(getattr(channel, "main_tree", None), "publishing", False): | ||
| raise ValidationError( | ||
| "Cannot create a community library submission while the channel is being published." | ||
| ) |
| let publishPollId = null; | ||
| function startPublishPolling() { | ||
| if (publishPollId || !isPublishing.value) return; | ||
| publishPollId = setInterval(() => { | ||
| Channel.fetchModel(props.channel.id).then(ch => { | ||
| if (ch) { | ||
| isPublishing.value = Boolean(ch.publishing); | ||
| if (!isPublishing.value) { | ||
| currentChannelVersion.value = ch.version; | ||
| clearInterval(publishPollId); | ||
| publishPollId = null; | ||
| } | ||
| } | ||
| }); | ||
| }, 2000); |
There was a problem hiding this comment.
Oh, I think here we can use the liveQuery method instead? Just as you did for the draft version publishing! https://github.com/taoerman/studio/blob/781d95378f7f20dd1dc1cf2f4f10bdf15b0457a2/contentcuration/contentcuration/frontend/shared/data/resources.js#L1275
| const isPublishing = ref(Boolean(props.channel.publishing)); | ||
| const currentChannelVersion = ref(props.channel.version); | ||
| const replacementConfirmed = ref(false); | ||
|
|
||
| // Monitor publishing completion using liveQuery to watch channel's publishing property | ||
| let publishSubscription = null; | ||
| let publishTimeout = null; | ||
|
|
||
| function startPublishMonitoring() { | ||
| if (publishSubscription || !isPublishing.value) return; | ||
|
|
||
| if (!Channel.table || !Channel.table.get) return; | ||
|
|
||
| const observable = liveQuery(() => { | ||
| return Channel.table.get(props.channel.id); | ||
| }); | ||
|
|
||
| publishSubscription = observable.subscribe({ | ||
| next: async channel => { | ||
| if (channel && !channel.publishing) { | ||
| stopPublishMonitoring(); | ||
| isPublishing.value = false; | ||
| currentChannelVersion.value = channel.version; | ||
| await store.dispatch('channel/loadChannel', props.channel.id); | ||
| } | ||
| }, | ||
| }); | ||
|
|
||
| publishTimeout = setTimeout(() => { | ||
| stopPublishMonitoring(); | ||
| }, 300000); | ||
| } | ||
|
|
||
| function stopPublishMonitoring() { | ||
| if (publishSubscription) { | ||
| publishSubscription.unsubscribe(); | ||
| publishSubscription = null; | ||
| } | ||
| if (publishTimeout) { | ||
| clearTimeout(publishTimeout); | ||
| publishTimeout = null; | ||
| } | ||
| } | ||
|
|
||
| if (isPublishing.value) { | ||
| startPublishMonitoring(); | ||
| } | ||
|
|
||
| watch( | ||
| () => currentChannel.value?.publishing, | ||
| (newPublishing, oldPublishing) => { | ||
| isPublishing.value = Boolean(newPublishing); | ||
| if (newPublishing && !oldPublishing) { | ||
| startPublishMonitoring(); | ||
| } else if (!newPublishing && oldPublishing) { | ||
| stopPublishMonitoring(); | ||
| } | ||
| }, | ||
| ); | ||
|
|
||
| onUnmounted(() => { | ||
| stopPublishMonitoring(); | ||
| }); |
There was a problem hiding this comment.
A hundred apologies, I did not catch this earlier... 🥲, but.... since the props.channel prop is already reactive, then a simply computed property would automatically watch any changes on the publishing property:
const isPublishing = computed(() => props.channel?.publishing === true);And we wouldn't need to set up the monitoring machinery.
| () => currentChannel.value?.publishing, | ||
| async (isPublishing, wasPublishing) => { | ||
| if (wasPublishing === true && isPublishing === false && props.channel.id) { | ||
| await Channel.fetchModel(props.channel.id); | ||
| const ch = await Channel.fetchModel(props.channel.id); | ||
| if (ch) { | ||
| currentChannelVersion.value = ch.version; | ||
| } | ||
| await store.dispatch('channel/loadChannel', props.channel.id); | ||
| } | ||
| }, |
There was a problem hiding this comment.
Now that we can rely on the reactiveness of the props.channel, we can get rid of this watcher too!
| if (isPublishing.value) { | ||
| showSnackbar({ text: submittingSnackbar$() }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
In theory, this should never get here, right? And even if it does, I don't think it'd be appropriate to show a "submitting" snackbar. Was there any particular reason for this?
There was a problem hiding this comment.
I read the code again and tested the workflow manually and it would not get there. Removed, Thanks.
| const countries = ref([]); | ||
| const description = ref(''); | ||
| const isPublishing = ref(Boolean(props.channel.publishing)); | ||
| const currentChannelVersion = ref(props.channel.version); |
There was a problem hiding this comment.
Seems like the definition of this currentChannelVersion can also be replaced with a computed property: const currentChannelVersion = computed(() => props.channel.version);.
I tried it, and... it seems there is an error with the reactiveness of the version, as the version never gets updated!
However, this is not a problem with the reactiveness of the props.channel property, but with how we manage the changes in Studio. The reason why the version of props.channel doesn't change is that in the backend, when we create the change that informs the publish task has finished, we don't specify the new version in that change, and therefore, when changes are synced to the frontend, we don't update the channel version property. Therefore, the fix for this would be to include the new version of the channel in the channel update event after publishing a new version here! After this, we shouldn't need to reload the channel from the backend to get the proper updates of the version 😄.
There was a problem hiding this comment.
Thanks Alex! LOL, I used const isPublishing = ref(Boolean(props.channel.publishing)); const currentChannelVersion = ref(props.channel.version); They worked on my laptop, but they needed some time to load. However, your idea is looks more reasonable! I will fix the code according to your idea.
| if (!publishedData.value) return undefined; | ||
|
|
||
| return publishedData.value[currentChannel.value?.version]; | ||
| return publishedData.value[currentChannelVersion.value]; |
There was a problem hiding this comment.
Just a note that we may have a problem with this publishedData not being reloaded when the channel is published. Would you like to take a look and come up with a way to keep this updated smoothly? We can open another issue for this if that makes more sense 😄.
| @@ -376,7 +454,10 @@ | |||
| () => currentChannel.value?.publishing, | |||
There was a problem hiding this comment.
I did not flag this earlier because I wanted to have the complete picture regarding this currentChannel prop with this PR. And now that it seems that props.channel is indeed reactive, then I think we can just always use props.channel, and avoid the definition of this currentChannel here?
The pros of using props.channel instead of currentChannel are that we make this side panel less coupled to the channel edit context. And if, for some reason, we want to show it in another place, it will be easier to implement.
AlexVelezLl
left a comment
There was a problem hiding this comment.
Thanks @taoerman! Just one little requirement before merging!
| // Watch for version changes and refetch publishedData | ||
| watch(currentChannelVersion, (newVersion, oldVersion) => { | ||
| if (newVersion && newVersion !== oldVersion) { | ||
| fetchPublishedData(); | ||
| } | ||
| }); |
There was a problem hiding this comment.
I think we can remove this and rely on the isPublishing watcher. If we keep both, we may end up making the same fetch twice, consuming time and resources unnecessarily.
There was a problem hiding this comment.
Thanks Alex, I checked the code and found it truly redundant and duplicate. I've removed this watch.
Summary
References
Fixed #5452
Reviewer guidance
run frontend and backend unit tests,
test the frontend manually.