Skip to content

Commit 44f14d5

Browse files
committed
Refactor PublishSidePanel
1 parent f5dfe6c commit 44f14d5

2 files changed

Lines changed: 116 additions & 120 deletions

File tree

contentcuration/contentcuration/frontend/channelEdit/components/sidePanels/PublishSidePanel.vue

Lines changed: 111 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@closePanel="onClose"
99
>
1010
<template #header>
11-
<h1 class="side-panel-title">{{ getPanelTitle() }}</h1>
11+
<h1 class="side-panel-title">{{ publishChannel$() }}</h1>
1212
</template>
1313

1414
<template #default>
@@ -49,28 +49,29 @@
4949
<div class="form-section">
5050
<KTextbox
5151
v-model="version_notes"
52+
showInvalidText
5253
:label="versionDescriptionLabel$()"
53-
:invalid="version_notes.length === 0"
54-
:invalidText="'Version notes are required'"
55-
:showInvalidText="showVersionNotesInvalidText"
54+
:invalid="isVersionNotesBlurred && !isVersionNotesValid"
55+
:invalidText="versionNotesRequiredMessage$()"
5656
textArea
5757
:maxlength="250"
5858
:appearanceOverrides="{ maxWidth: 'none' }"
59-
@blur="onVersionNotesBlur"
59+
@blur="isVersionNotesBlurred = true"
6060
/>
6161
</div>
6262
<!-- Language selector -->
63+
<KCircularLoader v-if="isChannelLanguageLoading" />
6364
<div
64-
v-if="showLanguageDropdown"
65+
v-else-if="showLanguageDropdown"
6566
class="form-section"
6667
>
6768
<KSelect
68-
v-model="language"
69+
v-model="newChannelLanguage"
6970
:label="languageLabel$()"
70-
:invalid="showLanguageInvalidText"
71+
:invalid="isLanguageSelectBlurred && !isNewLanguageValid"
7172
:invalidText="languageRequiredMessage$()"
72-
:options="languages"
73-
@change="onLanguageChange"
73+
:options="languageOptions"
74+
@blur="isLanguageSelectBlurred = true"
7475
/>
7576
</div>
7677
</div>
@@ -152,7 +153,7 @@
152153

153154
<script>
154155
155-
import { ref, computed, getCurrentInstance, onMounted } from 'vue';
156+
import { ref, computed, getCurrentInstance } from 'vue';
156157
import SidePanelModal from 'shared/views/SidePanelModal';
157158
import { Channel, CommunityLibrarySubmission } from 'shared/data/resources';
158159
import { forceServerSync } from 'shared/data/serverSync';
@@ -173,12 +174,14 @@
173174
174175
const mode = ref(PublishModes.LIVE);
175176
const version_notes = ref('');
177+
const newChannelLanguage = ref({});
178+
const languageOptions = ref(null);
179+
180+
const isChannelLanguageLoading = ref(false);
176181
const submitting = ref(false);
177-
const language = ref({});
178-
const showLanguageInvalidText = ref(false);
179-
const showVersionNotesInvalidText = ref(false); // lazy validation
180-
const channelLanguages = ref([]);
181-
const channelLanguageExists = ref(true);
182+
const isVersionNotesBlurred = ref(false);
183+
const isLanguageSelectBlurred = ref(false);
184+
const isCurrentChannelLanguageValid = ref(false);
182185
183186
const instance = getCurrentInstance();
184187
const store = instance.proxy.$store;
@@ -205,6 +208,7 @@
205208
cancelAction$,
206209
languageLabel$,
207210
languageRequiredMessage$,
211+
versionNotesRequiredMessage$,
208212
} = communityChannelsStrings;
209213
210214
const currentChannel = computed(() => store.getters['currentChannel/currentChannel']);
@@ -224,24 +228,16 @@
224228
const isPrivateChannel = currentChannel.value.public === false;
225229
const isFirstPublish = currentChannel.value.version === 0;
226230
227-
return (
228-
((isCheffedChannel || isPrivateChannel) && isFirstPublish) || !channelLanguageExists.value
229-
);
230-
});
231-
232-
const languages = computed(() => {
233-
if (!currentChannel.value) return [];
234-
return filterLanguages(l => channelLanguages.value.includes(l.id));
235-
});
236-
237-
const defaultLanguage = computed(() => {
238-
if (!currentChannel.value?.language) return {};
239-
const channelLang = filterLanguages(l => l.id === currentChannel.value.language)[0];
240-
return languages.value.some(lang => lang.value === channelLang?.value) ? channelLang : {};
231+
if (isFirstPublish) {
232+
return isCheffedChannel || isPrivateChannel;
233+
}
234+
return !isCurrentChannelLanguageValid.value;
241235
});
242236
243-
const isLanguageValid = computed(() => {
244-
return Object.keys(language.value).length > 0;
237+
const isNewLanguageValid = computed(() => {
238+
// If language selector is not shown do not prevent submission
239+
if (!showLanguageDropdown.value) return true;
240+
return Object.keys(newChannelLanguage.value).length > 0;
245241
});
246242
247243
const isVersionNotesValid = computed(() => {
@@ -251,9 +247,7 @@
251247
// Validate the version and language for live mode
252248
const isFormValid = computed(() => {
253249
if (mode.value === PublishModes.LIVE) {
254-
const versionNotesValid = isVersionNotesValid.value;
255-
const languageValid = showLanguageDropdown.value ? isLanguageValid.value : true;
256-
return versionNotesValid && languageValid;
250+
return isVersionNotesValid.value && isNewLanguageValid.value;
257251
}
258252
return true;
259253
});
@@ -262,48 +256,92 @@
262256
return mode.value === PublishModes.DRAFT ? saveDraft$() : publishAction$();
263257
});
264258
265-
const filterLanguages = filterFn => {
266-
return LanguagesList.filter(filterFn).map(l => ({
259+
const getLanguagesOptions = languages => {
260+
return mapLanguagesOptions(LanguagesList.filter(lang => languages.includes(lang.id)));
261+
};
262+
const mapLanguagesOptions = languages => {
263+
return languages.map(l => ({
267264
value: l.id,
268265
label: l.native_name,
269266
}));
270267
};
271268
272-
// Validate the selected language when it changes
273-
const validateSelectedLanguage = () => {
274-
if (Object.keys(language.value).length > 0 && languages.value.length > 0) {
275-
const isValidLanguage = languages.value.some(lang => lang.value === language.value.value);
276-
if (!isValidLanguage) {
277-
language.value = {};
269+
/**
270+
* Makes sure that the channel.language is consistent with the channel resources languages
271+
* If not, show the language selector for the user to select a valid language for the channel
272+
*/
273+
const _auditChannelLanguage = async () => {
274+
if (!currentChannel.value) {
275+
return;
276+
}
277+
278+
const currentChannelLanguage = currentChannel.value.language;
279+
// If the current `channel.language` exists among its resources languages,
280+
// the channel language is valid
281+
isCurrentChannelLanguageValid.value = await channelLanguageExistsInResources();
282+
const channelLanguageOption = getLanguagesOptions([currentChannelLanguage])[0];
283+
284+
if (!isCurrentChannelLanguageValid.value || !channelLanguageOption) {
285+
// If not valid, or it doesn't exist in our LanguagesList, load resources languages
286+
const resourcesLanguages = await getLanguagesInChannelResources();
287+
if (resourcesLanguages.length > 0) {
288+
languageOptions.value = getLanguagesOptions(resourcesLanguages);
289+
return;
278290
}
279291
}
292+
293+
// if not found in LanguagesList and no resources languages found, set the whole
294+
// LanguagesList as options
295+
if (!channelLanguageOption) {
296+
languageOptions.value = mapLanguagesOptions(LanguagesList);
297+
return;
298+
}
299+
// In any other case, just set the channel language as the only option
300+
languageOptions.value = [channelLanguageOption];
301+
newChannelLanguage.value = channelLanguageOption;
280302
};
281303
282-
onMounted(async () => {
283-
if (currentChannel.value) {
284-
const exists = await channelLanguageExistsInResources();
285-
channelLanguageExists.value = exists;
304+
const auditChannelLanguage = async () => {
305+
isChannelLanguageLoading.value = true;
306+
await _auditChannelLanguage();
307+
isChannelLanguageLoading.value = false;
308+
};
286309
287-
if (!exists) {
288-
const languages = await getLanguagesInChannelResources();
289-
channelLanguages.value = languages.length ? languages : [currentChannel.value.language];
290-
language.value = defaultLanguage.value;
291-
validateSelectedLanguage();
292-
} else {
293-
channelLanguages.value = [currentChannel.value.language];
294-
language.value = defaultLanguage.value;
295-
validateSelectedLanguage();
296-
}
297-
}
298-
});
310+
auditChannelLanguage();
299311
300312
const onClose = () => {
301313
if (!submitting.value) emit('close');
302314
};
303315
316+
const checkResubmitToCommunityLibrary = async () => {
317+
if (mode.value !== PublishModes.LIVE) {
318+
return;
319+
}
320+
321+
try {
322+
const response = await CommunityLibrarySubmission.fetchCollection({
323+
channel: currentChannel.value.id,
324+
max_results: 1,
325+
});
326+
327+
const submissions = response?.results || [];
328+
329+
if (submissions.length > 0) {
330+
const latestSubmission = submissions[0];
331+
emit('showResubmitCommunityLibraryModal', {
332+
channel: { ...currentChannel.value },
333+
latestSubmissionVersion: latestSubmission.channel_version,
334+
});
335+
}
336+
} catch (error) {
337+
// Log the error but do not block the publish flow
338+
logging.error(error);
339+
}
340+
};
341+
304342
const submit = async () => {
305-
// Validate form before submission
306-
if (!validate()) {
343+
// Should not get here if the form is invalid, but just in case
344+
if (!isFormValid.value) {
307345
return;
308346
}
309347
@@ -319,39 +357,16 @@
319357
await Channel.publishDraft(currentChannel.value.id, { use_staging_tree: false });
320358
emit('close');
321359
} else {
322-
if (
323-
language.value &&
324-
language.value.value &&
325-
language.value.value !== currentChannel.value?.language
326-
) {
360+
if (newChannelLanguage.value.value !== currentChannel.value.language) {
327361
await store.dispatch('channel/updateChannel', {
328362
id: currentChannel.value.id,
329-
language: language.value.value,
363+
language: newChannelLanguage.value.value,
330364
});
331365
}
332366
333367
await Channel.publish(currentChannel.value.id, version_notes.value);
334368
335-
if (mode.value === PublishModes.LIVE) {
336-
try {
337-
const response = await CommunityLibrarySubmission.fetchCollection({
338-
channel: currentChannel.value.id,
339-
max_results: 1,
340-
});
341-
342-
const submissions = response?.results || [];
343-
344-
if (submissions.length > 0) {
345-
const latestSubmission = submissions[0];
346-
emit('showResubmitCommunityLibraryModal', {
347-
channel: { ...currentChannel.value },
348-
latestSubmissionVersion: latestSubmission.channel_version,
349-
});
350-
}
351-
} catch (error) {
352-
logging.error(error);
353-
}
354-
}
369+
await checkResubmitToCommunityLibrary();
355370
356371
emit('close');
357372
}
@@ -362,49 +377,28 @@
362377
}
363378
};
364379
365-
const getPanelTitle = () => {
366-
return publishChannel$();
367-
};
368-
369-
const onLanguageChange = () => {
370-
showLanguageInvalidText.value = !isLanguageValid.value;
371-
validateSelectedLanguage(); // Ensure language is always valid
372-
};
373-
374-
const onVersionNotesBlur = () => {
375-
showVersionNotesInvalidText.value = !isVersionNotesValid.value;
376-
};
377-
378-
const validate = () => {
379-
if (mode.value === PublishModes.DRAFT) {
380-
// For draft mode, no validation is required
381-
return true;
382-
} else {
383-
// For live mode, validate version notes and language
384-
showVersionNotesInvalidText.value = !isVersionNotesValid.value;
385-
showLanguageInvalidText.value = !isLanguageValid.value;
386-
return !showVersionNotesInvalidText.value && !showLanguageInvalidText.value;
387-
}
388-
};
389-
390380
return {
381+
isChannelLanguageLoading,
391382
PublishModes,
392383
mode,
393384
version_notes,
394385
submitting,
395-
language,
396-
showLanguageInvalidText,
397-
showVersionNotesInvalidText,
386+
languageOptions,
387+
newChannelLanguage,
388+
isVersionNotesBlurred,
389+
isLanguageSelectBlurred,
398390
399391
currentChannel,
400392
incompleteResourcesCount,
401393
showLanguageDropdown,
402-
languages,
403394
isFormValid,
395+
isNewLanguageValid,
396+
isVersionNotesValid,
404397
submitText,
405398
406399
modeLive$,
407400
modeDraft$,
401+
publishChannel$,
408402
versionNotesLabel$,
409403
modeLiveDescription$,
410404
modeDraftDescription$,
@@ -416,12 +410,10 @@
416410
cancelAction$,
417411
languageLabel$,
418412
languageRequiredMessage$,
413+
versionNotesRequiredMessage$,
419414
420415
onClose,
421416
submit,
422-
getPanelTitle,
423-
onLanguageChange,
424-
onVersionNotesBlur,
425417
};
426418
},
427419

contentcuration/contentcuration/frontend/shared/strings/communityChannelsStrings.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,13 @@ export const communityChannelsStrings = createTranslator('CommunityChannelsStrin
6969
message: 'Language',
7070
context: 'Label for the language selection dropdown',
7171
},
72+
versionNotesRequiredMessage: {
73+
message: 'Version notes are required',
74+
context: 'Error message when version notes are required but not provided',
75+
},
7276
languageRequiredMessage: {
7377
message: 'Language is required',
74-
context: 'Error message when language selection is required',
78+
context: 'Error message when language selection is required but not provided',
7579
},
7680
pendingStatus: {
7781
message: 'Submitted',

0 commit comments

Comments
 (0)