Skip to content

Conversation

@taoerman
Copy link
Member

@taoerman taoerman commented Nov 7, 2025

Summary

Implemented ResubmitChannelModal to prompt users to resubmit a channel to the Community Library when publishing a channel that already has submissions. The modal appears immediately on publish click (not after completion, another issue has added a loader to make sure the side panel would load updated data from backend) and shows the channel name and the version already in the submission queue.

References

Fixed #5451

Reviewer guidance

test manually.

Copy link
Member

@AlexVelezLl AlexVelezLl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @taoerman! Looking good, just a little concerned about the KModal styles overrides, and noted a couple of nitpicks. Thanks!

Comment on lines 14 to 33
<template #actions>
<div class="resubmit-modal-actions">
<KButton
class="resubmit-modal-dismiss-btn"
:style="dismissButtonStyles"
data-test="dismiss-button"
@click="handleDismiss"
>
{{ dismissButtonText }}
</KButton>
<KButton
class="resubmit-modal-resubmit-btn"
primary
data-test="resubmit-button"
@click="handleResubmit"
>
{{ resubmitButtonText }}
</KButton>
</div>
</template>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason why we need these buttons to be in the #actions slot instead of using the KModal props? (It is not completely incorrect, it is more so because this slot is just for when we want specific styles handling on KModal actions)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Alex, just using KModal props could make code simpler! Fixed!

Comment on lines 102 to 162
[data-test='resubmit-modal'],
[data-test='resubmit-modal'] > *,
[data-test='resubmit-modal'] [role='dialog'],
[data-test='resubmit-modal'] .KModal,
[data-test='resubmit-modal'] .modal {
width: 500px !important;
max-width: 500px !important;
max-height: 284px !important;
}
[data-test='resubmit-modal'] h1,
[data-test='resubmit-modal'] h2,
[data-test='resubmit-modal'] h3,
[data-test='resubmit-modal'] h4,
[data-test='resubmit-modal'] .modal-title,
[data-test='resubmit-modal'] [class*='title'] {
width: 452px;
height: 52px;
font-family: 'Noto Sans', sans-serif;
font-size: 20px;
font-weight: 600;
line-height: 130%;
letter-spacing: 0%;
vertical-align: middle;
}
.resubmit-modal-content {
padding: 8px 0;
margin-top: 35px;
}
.resubmit-modal-description,
.resubmit-modal-question {
width: 100%;
min-height: 40px;
padding: 0;
margin: 0;
font-family: 'Noto Sans', sans-serif;
font-size: 14px;
font-weight: 400;
line-height: 140%;
letter-spacing: 0%;
vertical-align: middle;
}
.resubmit-modal-actions {
display: flex;
gap: 10px;
justify-content: flex-end;
width: 452px;
min-height: 40px;
padding-top: 16px;
}
.resubmit-modal-dismiss-btn:hover {
background-color: var(--hover-bg-color) !important;
}
.resubmit-modal-resubmit-btn {
height: 40px;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, are all of these styles added to match exactly the Figma specs? I don't think we need almost any of them; we can rely on KModal's inner styles to have a consistent view across modals in the application.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I added these styles to match Figma. But I found only using KModal's inner styles could also match Figma. Thanks Alex!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the resubmit CL modal be checked and triggered by this component? If so, we can show a loader here, until that check finishes, and then we can emit a showResubmitCommunityLibraryModal or something like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added! But when I tried to test it manually. The process of publishing was so fast. I could not even see the loader. LOL!

Comment on lines 589 to 592
this.resubmitModalChannel = {
...this.currentChannel,
version: latestSubmission.channel_version,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't need to update the channel version in this way after this is merged!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it!

Comment on lines 581 to 585
if (Array.isArray(response)) {
submissions = response;
} else if (response && response.results && Array.isArray(response.results)) {
submissions = response.results;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to check the response type. In this point of the application, it should always be the same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, Thanks!

Comment on lines 58 to 94
computed: {
title() {
return communityChannelsStrings.resubmitModalTitle$();
},
description() {
return communityChannelsStrings.resubmitModalBodyFirst$({
channelName: this.channel.name,
version: this.channel.version,
});
},
question() {
return communityChannelsStrings.resubmitModalBodySecond$();
},
dismissButtonText() {
return communityChannelsStrings.dismissButton$();
},
resubmitButtonText() {
return communityChannelsStrings.resubmitButton$();
},
dismissButtonStyles() {
return {
color: this.$themeTokens.primary,
backgroundColor: this.$themePalette.grey.v_100,
'--hover-bg-color': this.$themePalette.grey.v_200,
};
},
},
methods: {
handleDismiss() {
this.$emit('dismiss');
this.$emit('input', false);
},
handleResubmit() {
this.$emit('resubmit');
this.$emit('input', false);
},
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and just one last thing! 😅 Could we migrate this to use the Vue Composition API instead? Thanks!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've migrated!

Copy link
Member

@AlexVelezLl AlexVelezLl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a couple of things that can be changed to have a better consistency with other modals 👐 .

Comment on lines +27 to +44
value: {
type: Boolean,
default: false,
},
channel: {
type: Object,
required: true,
validator(value) {
return value && typeof value.name === 'string' && typeof value.version === 'number';
},
},
latestSubmissionVersion: {
type: Number,
default: null,
},
});
const emit = defineEmits(['dismiss', 'resubmit', 'input']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, similar to what we did for the DeleteModal here, could we also use the @close event for the parent component to close the Modal instead of using dismiss and v-model? So we can keep this consistent pattern for rendering modals!

Comment on lines +38 to +52
latestSubmissionVersion: {
type: Number,
default: null,
},
});
const emit = defineEmits(['dismiss', 'resubmit', 'input']);
const title = computed(() => communityChannelsStrings.resubmitModalTitle$());
const publishedVersion = computed(() => {
return props.latestSubmissionVersion != null
? props.latestSubmissionVersion
: props.channel.version;
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latestSubmissionVersion should be required as well. If this prop is null, we should automatically close the side panel, since we need this information to be accurate when showing the modal; otherwise, it may confuse users.

const mode = ref(PublishModes.LIVE);
const version_notes = ref('');
const submitting = ref(false);
const checkingResubmit = ref(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just use the current submitting loading ref instead of creating a new one, because at the end, this process of checking the latest submission could be part of the "submission" process.

Comment on lines +143 to +149
<span
v-if="checkingResubmit"
class="loader-wrapper"
>
<KCircularLoader :size="16" />
</span>
<span v-else>{{ submitText }}</span>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't usually change the text button to a circular loader while something is loading, so we can just skip it!

Comment on lines +359 to +361
} catch (error) {
store.dispatch('shared/handleAxiosError', error);
} finally {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, let's do nothing if something fails, let's make this call just optional, and if it fails, it shouldn't block the normal user workflow.

if (submissions.length > 0) {
const latestSubmission = submissions[0];
emit('showResubmitCommunityLibraryModal', {
channel: currentChannel.value ? { ...currentChannel.value } : null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentChannel.value should always be defined at this point, so lets just skip the null check

const latestSubmission = submissions[0];
emit('showResubmitCommunityLibraryModal', {
channel: currentChannel.value ? { ...currentChannel.value } : null,
latestSubmissionVersion: latestSubmission?.channel_version ?? null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This latestSubmission ref should also always be defined at this point, the same with the channel_version, since this is a required field in the backend model, so that we can skip the null checks here too!

}
function handleResubmit() {
emit('resubmit');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also emit the 'close' event when resubmitting, so that the parent component can handle both events separately, without needing to close the modal when the resubmit event is emitted.

Comment on lines +564 to +577
handleResubmit() {
this.showResubmitModal = false;
this.showSubmitToCommunityLibrarySidePanel = true;
},
handleDismissResubmit() {
this.showResubmitModal = false;
this.resubmitModalChannel = null;
this.resubmitModalSubmissionVersion = null;
},
handleShowResubmitModal({ channel, latestSubmissionVersion }) {
this.resubmitModalChannel = channel;
this.resubmitModalSubmissionVersion = latestSubmissionVersion || null;
this.showResubmitModal = true;
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although less common, there is a more handy way to pass these multiple variables needed for showing the ResubmitChannelModal, and it is just storing the entire emitted object, and checking if this object is null to show the ResubmitChannelModal.

i.e., we could instead do something like this:

    <PublishSidePanel
      v-if="showPublishSidePanel"
      @close="showPublishSidePanel = false"
      @showResubmitCommunityLibraryModal="e => resubmitModalData = e" // we store the whole object without unwrapping it
    />

And then in the ResubmitChannelModal rendering:

    <ResubmitChannelModal
      v-if="resubmitModalData" // We check if the `resubmitModalData` is defined
      :channel="resubmitModalData.channel" // since at this point we know this ref is defined, we can access its properties
      :latestSubmissionVersion="resubmitModalData.latestSubmissionVersion"
      @resubmit="handleResubmit"
      @close="resubmitModalData = null" // Set it to null instead of false since this variable is expected to be an object
    />

With this, we prevent any potential regression because of data corruption (e.g., we set showResubmitModal but not resubmitModalChannel or resubmitModalSubmissionVersion), and save us some lines in the component.

Comment on lines +227 to +234
resubmitButton: {
message: 'RESUBMIT',
context: 'Button in the resubmit modal to open the submit to Community Library side panel',
},
dismissButton: {
message: 'DISMISS',
context: 'Button in the resubmit modal to dismiss the modal',
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use the Action suffix instead of Button, so for consistency, we can rename these strings to be resubmitAction and dismissAction.

And we can set the message to be just "Resubmit" and "Dismiss", and KButton will take care of using the upper case if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show resubmit channel to community library CTA after channel publish

3 participants