@@ -293,7 +291,7 @@
aggregatorToolTip:
'Website or org hosting the content collection but not necessarily the creator or copyright holder',
copyrightHolderLabel: 'Copyright holder',
- cannotEditPublic: 'Cannot edit for public channel resources',
+ cannotEditPublic: 'Not editable for resources from public channels',
editOnlyLocal: 'Edits will be reflected only for local resources',
mixed: 'Mixed',
saveAction: 'Save',
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditBooleanMapModal.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditBooleanMapModal.spec.js
index 428d41cad1..2c49fe6b94 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditBooleanMapModal.spec.js
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditBooleanMapModal.spec.js
@@ -78,6 +78,11 @@ const makeWrapper = ({ nodeIds, field = 'categories', ...restOptions }) => {
hideLabel: true,
nodeIds,
},
+ on: {
+ input(value) {
+ props.inputHandler(value);
+ },
+ },
});
},
},
@@ -107,6 +112,7 @@ describe('EditBooleanMapModal', () => {
actions: contentNodeActions,
getters: {
getContentNodes: () => ids => ids.map(id => nodes[id]),
+ getContentNode: () => id => nodes[id],
},
},
},
@@ -199,7 +205,7 @@ describe('EditBooleanMapModal', () => {
});
describe('Submit', () => {
- test('should call updateContentNode with the right options on success submit - categories', () => {
+ test('should call updateContentNode with the selected options on an empty boolean map when success submit', async () => {
const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
const schoolCheckbox = findOptionCheckbox(wrapper, Categories.SCHOOL);
@@ -207,58 +213,43 @@ describe('EditBooleanMapModal', () => {
const sociologyCheckbox = findOptionCheckbox(wrapper, Categories.SOCIOLOGY);
sociologyCheckbox.element.click();
- const animationFrameId = requestAnimationFrame(() => {
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('submit');
- expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
- id: 'node1',
- categories: {
- [Categories.SCHOOL]: true,
- [Categories.SOCIOLOGY]: true,
- },
- });
- expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
- id: 'node2',
- categories: {
- [Categories.SCHOOL]: true,
- [Categories.SOCIOLOGY]: true,
- },
- });
- cancelAnimationFrame(animationFrameId);
+ await wrapper.vm.handleSave();
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {
+ [Categories.SCHOOL]: true,
+ [Categories.SOCIOLOGY]: true,
+ },
+ });
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node2',
+ categories: {
+ [Categories.SCHOOL]: true,
+ [Categories.SOCIOLOGY]: true,
+ },
});
});
- test('should emit close event on success submit', () => {
+ test('should emit close event on success submit', async () => {
const wrapper = makeWrapper({ nodeIds: ['node1'] });
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('submit');
-
- const animationFrameId = requestAnimationFrame(() => {
- expect(wrapper.emitted('close')).toBeTruthy();
- cancelAnimationFrame(animationFrameId);
- });
+ await wrapper.vm.handleSave();
+ expect(wrapper.emitted('close')).toBeTruthy();
});
- test('should show a confirmation snackbar on success submit', () => {
+ test('should show a confirmation snackbar on success submit', async () => {
const wrapper = makeWrapper({ nodeIds: ['node1'] });
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('submit');
-
- const animationFrameId = requestAnimationFrame(() => {
- expect(generalActions.showSnackbarSimple).toHaveBeenCalled();
- cancelAnimationFrame(animationFrameId);
- });
+ await wrapper.vm.handleSave();
+ expect(generalActions.showSnackbarSimple).toHaveBeenCalled();
});
});
test('should emit close event on cancel', () => {
const wrapper = makeWrapper({ nodeIds: ['node1'] });
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('cancel');
-
- const animationFrameId = requestAnimationFrame(() => {
- expect(wrapper.emitted('close')).toBeTruthy();
- cancelAnimationFrame(animationFrameId);
- });
+ wrapper.vm.close();
+ expect(wrapper.emitted('close')).toBeTruthy();
});
describe('topic nodes present', () => {
@@ -284,39 +275,262 @@ describe('EditBooleanMapModal', () => {
expect(wrapper.find('[data-test="update-descendants-checkbox"]').exists()).toBeFalsy();
});
- test('should call updateContentNode on success submit if the user does not check the update descendants checkbox', () => {
+ test('should call updateContentNode on success submit if the user does not check the update descendants checkbox', async () => {
nodes['node1'].kind = ContentKindsNames.TOPIC;
const wrapper = makeWrapper({ nodeIds: ['node1'], isDescendantsUpdatable: true });
+ await wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {},
+ });
+ });
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('submit');
+ test('should call updateContentNodeDescendants on success submit if the user checks the descendants checkbox', async () => {
+ nodes['node1'].kind = ContentKindsNames.TOPIC;
- const animationFrameId = requestAnimationFrame(() => {
- expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ const wrapper = makeWrapper({ nodeIds: ['node1'], isDescendantsUpdatable: true });
+ wrapper.find('[data-test="update-descendants-checkbox"]').element.click();
+ await wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNodeDescendants).toHaveBeenCalledWith(
+ expect.anything(),
+ {
id: 'node1',
categories: {},
+ }
+ );
+ });
+ });
+
+ describe('mixed options that are not selected across all nodes', () => {
+ describe('render mixed options message', () => {
+ test('should not render mixed options message if there are not mixed options across selected nodes', () => {
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ expect(wrapper.find('[data-test="mixed-categories-message"]').exists()).toBeFalsy();
+ });
+
+ test('should not render mixed options message if there are not mixed options across selected nodes - 2', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ expect(wrapper.find('[data-test="mixed-categories-message"]').exists()).toBeFalsy();
+ });
+
+ test('should render mixed options message if there are mixed options across selected nodes', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ nodes['node2'].categories = {};
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ expect(wrapper.find('[data-test="mixed-categories-message"]').exists()).toBeTruthy();
+ });
+
+ test('should render mixed options message if there are mixed options across selected nodes - 2', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ expect(wrapper.find('[data-test="mixed-categories-message"]').exists()).toBeTruthy();
+ });
+ });
+ describe('on submit', () => {
+ test('should add new selected options on submit even if there are not common selected options', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.FOUNDATIONS]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ const schoolCheckbox = findOptionCheckbox(wrapper, Categories.SCHOOL);
+ schoolCheckbox.element.click();
+
+ wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {
+ // already daily_life category selected plus new school category selected
+ [Categories.SCHOOL]: true,
+ [Categories.DAILY_LIFE]: true,
+ },
+ });
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node2',
+ categories: {
+ // already foundations category selected plus new school category selected
+ [Categories.SCHOOL]: true,
+ [Categories.FOUNDATIONS]: true,
+ },
+ });
+ });
+
+ test('should add new selected options on submit even if there are common selected options', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.FOUNDATIONS]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ const schoolCheckbox = findOptionCheckbox(wrapper, Categories.SCHOOL);
+ schoolCheckbox.element.click();
+
+ wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {
+ // already daily_life and foundation category selected plus new school category selected
+ [Categories.SCHOOL]: true,
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ },
+ });
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node2',
+ categories: {
+ // already foundations category selected plus new school category selected
+ [Categories.SCHOOL]: true,
+ [Categories.FOUNDATIONS]: true,
+ },
+ });
+ });
+
+ test('should not remove common selected options even if they are unchecked', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ const dailyLifeCheckbox = findOptionCheckbox(wrapper, Categories.DAILY_LIFE);
+ dailyLifeCheckbox.element.click(); // uncheck daily lifye
+
+ const schoolCheckbox = findOptionCheckbox(wrapper, Categories.SCHOOL);
+ schoolCheckbox.element.click(); // check school
+
+ wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {
+ // already daily_life and foundation category selected plus new school category selected
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ [Categories.SCHOOL]: true,
+ },
+ });
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node2',
+ categories: {
+ // already daily life category selected plus new school category selected
+ [Categories.DAILY_LIFE]: true,
+ [Categories.SCHOOL]: true,
+ },
+ });
+ });
+
+ test('should not remove common selected options even if they are unchecked and no new options are checked', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ [Categories.SCHOOL]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ const dailyLifeCheckbox = findOptionCheckbox(wrapper, Categories.DAILY_LIFE);
+ dailyLifeCheckbox.element.click(); // uncheck daily lifye
+
+ wrapper.vm.handleSave();
+
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node1',
+ categories: {
+ // already selected options
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ [Categories.SCHOOL]: true,
+ },
+ });
+ expect(contentNodeActions.updateContentNode).toHaveBeenCalledWith(expect.anything(), {
+ id: 'node2',
+ categories: {
+ // already selected options
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ },
});
- cancelAnimationFrame(animationFrameId);
});
});
+ describe('can save method', () => {
+ test('should not can save if there are mixed categories and no options selected', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.FOUNDATIONS]: true,
+ };
- test('should call updateContentNodeDescendants on success submit if the user checks the descendants checkbox', () => {
- nodes['node1'].kind = ContentKindsNames.TOPIC;
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
- const wrapper = makeWrapper({ nodeIds: ['node1'], isDescendantsUpdatable: true });
+ expect(wrapper.vm.canSave).toBeFalsy();
+ });
+
+ test('should can save if there are mixed categories but new options are selected', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.FOUNDATIONS]: true,
+ };
+
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
+
+ const schoolCheckbox = findOptionCheckbox(wrapper, Categories.SCHOOL);
+ schoolCheckbox.element.click();
+
+ expect(wrapper.vm.canSave).toBeTruthy();
+ });
+
+ test('should can save if there are mixed categories but at least one common option across all nodes', () => {
+ nodes['node1'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ [Categories.FOUNDATIONS]: true,
+ };
+ nodes['node2'].categories = {
+ [Categories.DAILY_LIFE]: true,
+ };
+
+ const wrapper = makeWrapper({ nodeIds: ['node1', 'node2'] });
- wrapper.find('[data-test="update-descendants-checkbox"] input').setChecked(true);
- wrapper.find('[data-test="edit-booleanMap-modal"]').vm.$emit('submit');
-
- const animationFrameId = requestAnimationFrame(() => {
- expect(contentNodeActions.updateContentNodeDescendants).toHaveBeenCalledWith(
- expect.anything(),
- {
- id: 'node1',
- categories: {},
- }
- );
- cancelAnimationFrame(animationFrameId);
+ expect(wrapper.vm.canSave).toBeTruthy();
});
});
});
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditSourceModal.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditSourceModal.spec.js
index 20858eecac..8be43746f9 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditSourceModal.spec.js
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/QuickEditModal/__tests__/EditSourceModal.spec.js
@@ -141,7 +141,7 @@ describe('EditSourceModal', () => {
const wrapper = makeWrapper(['node1', 'node2']);
- expect(wrapper.find('.help').text()).toContain('Cannot edit');
+ expect(wrapper.find('.help').text()).toContain(EditSourceModal.$trs.cannotEditPublic);
});
test('should disable inputs when node has freeze_authoring_data set to true', () => {
@@ -162,7 +162,7 @@ describe('EditSourceModal', () => {
const wrapper = makeWrapper(['node1']);
- expect(wrapper.find('.help').text()).toContain('Cannot edit');
+ expect(wrapper.find('.help').text()).toContain(EditSourceModal.$trs.cannotEditPublic);
});
test('should not disable inputs when not all nodes are imported', () => {
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue
index 7812086201..053a5fd70c 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue
@@ -270,6 +270,9 @@
+
+ {{ helpTextString.$tr('cannotEditPublic') }}
+
@@ -344,6 +348,9 @@
@input="copyright_holder = $event"
@focus="trackClick('Copyright holder')"
/>
+
+ {{ helpTextString.$tr('cannotEditPublic') }}
+
@@ -384,6 +391,7 @@
import FileUpload from '../../views/files/FileUpload';
import SubtitlesList from '../../views/files/supplementaryLists/SubtitlesList';
import { isImportedContent, isDisableSourceEdits, importedChannelLink } from '../../utils';
+ import EditSourceModal from '../QuickEditModal/EditSourceModal.vue';
import AccessibilityOptions from './AccessibilityOptions.vue';
import LevelsOptions from 'shared/views/contentNodeFields/LevelsOptions';
import CategoryOptions from 'shared/views/contentNodeFields/CategoryOptions';
@@ -409,6 +417,7 @@
nonUniqueValue,
} from 'shared/constants';
import { constantsTranslationMixin, metadataTranslationMixin } from 'shared/mixins';
+ import { crossComponentTranslator } from 'shared/i18n';
function getValueFromResults(results) {
if (results.length === 0) {
@@ -547,6 +556,7 @@
valid: true,
diffTracker: {},
changed: false,
+ helpTextString: crossComponentTranslator(EditSourceModal),
};
},
computed: {
@@ -776,10 +786,12 @@
saveFromDiffTracker(id) {
if (this.diffTracker[id]) {
this.changed = true;
- return this.updateContentNode({ id, ...this.diffTracker[id] }).then(() => {
- delete this.diffTracker[id];
- return this.changed;
- });
+ return this.updateContentNode({ id, checkComplete: true, ...this.diffTracker[id] }).then(
+ () => {
+ delete this.diffTracker[id];
+ return this.changed;
+ }
+ );
}
return Promise.resolve(this.changed);
},
@@ -991,4 +1003,14 @@
}
}
+ // Positions help text underneath
+ p.help {
+ position: relative;
+ top: -20px;
+ left: 10px;
+ margin-bottom: 14px;
+ font-size: 12px;
+ color: var(--v-text-lighten4);
+ }
+
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/EditModal.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/EditModal.vue
index 2dba69cc0f..3ab92e6cbb 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/EditModal.vue
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/EditModal.vue
@@ -64,13 +64,18 @@
{{ $tr('addTopic') }}
-
+
{{ $tr('uploadButton') }}
@@ -96,7 +101,7 @@
@@ -123,8 +128,10 @@
isInheritModalOpen = active"
/>
@@ -252,6 +259,9 @@
listElevated: false,
storagePoll: null,
openTime: null,
+ isInheritModalOpen: false,
+ newNodeIds: [],
+ creatingNodes: false,
};
},
computed: {
@@ -315,6 +325,17 @@
invalidNodes() {
return this.nodeIds.filter(id => !this.getContentNodeIsValid(id));
},
+ currentSelectedNodes: {
+ get() {
+ if (this.isInheritModalOpen && this.newNodeIds.length) {
+ return this.newNodeIds;
+ }
+ return this.selected;
+ },
+ set(value) {
+ this.selected = value;
+ },
+ },
},
beforeRouteEnter(to, from, next) {
if (
@@ -378,7 +399,11 @@
if (completeCheck !== node.complete) {
validationPromises.push(
- vm.updateContentNode({ id: nodeId, complete: completeCheck })
+ vm.updateContentNode({
+ id: nodeId,
+ complete: completeCheck,
+ checkComplete: true,
+ })
);
}
});
@@ -432,7 +457,10 @@
this.hideHTMLScroll(false);
this.$router.push({
name: RouteNames.TREE_VIEW,
- params: { nodeId: this.$route.params.nodeId },
+ params: {
+ nodeId: this.$route.params.nodeId,
+ addedCount: this.nodeIds.length,
+ },
});
},
hideHTMLScroll(hidden) {
@@ -506,28 +534,37 @@
return newNodeId;
});
},
+ resetInheritMetadataModal() {
+ this.$refs.inheritModal?.checkInheritance();
+ },
createTopic() {
this.createNode('topic', {
title: '',
}).then(newNodeId => {
this.selected = [newNodeId];
+ this.$nextTick(() => {
+ this.resetInheritMetadataModal();
+ });
});
},
- createNodesFromUploads(fileUploads) {
- fileUploads.forEach((file, index) => {
- let title;
- if (file.metadata.title) {
- title = file.metadata.title;
- } else {
- title = file.original_filename
- .split('.')
- .slice(0, -1)
- .join('.');
- }
- this.createNode(
- FormatPresets.has(file.preset) && FormatPresets.get(file.preset).kind_id,
- { title, ...file.metadata }
- ).then(newNodeId => {
+ async createNodesFromUploads(fileUploads) {
+ this.creatingNodes = true;
+ const parentPropDefinedForInheritModal = Boolean(this.$refs.inheritModal?.parent);
+ this.newNodeIds = await Promise.all(
+ fileUploads.map(async (file, index) => {
+ let title;
+ if (file.metadata.title) {
+ title = file.metadata.title;
+ } else {
+ title = file.original_filename
+ .split('.')
+ .slice(0, -1)
+ .join('.');
+ }
+ const newNodeId = await this.createNode(
+ FormatPresets.has(file.preset) && FormatPresets.get(file.preset).kind_id,
+ { title, ...file.metadata }
+ );
if (index === 0) {
this.selected = [newNodeId];
}
@@ -535,8 +572,15 @@
...file,
contentnode: newNodeId,
});
- });
- });
+ return newNodeId;
+ })
+ );
+ this.creatingNodes = false;
+ if (parentPropDefinedForInheritModal) {
+ // Only call this if the parent prop was previously defined, otherwise,
+ // rely on the parent prop watcher to trigger the inherit event.
+ this.resetInheritMetadataModal();
+ }
},
updateTitleForPage() {
this.updateTabTitle(this.$store.getters.appendChannelName(this.modalTitle));
@@ -547,8 +591,31 @@
});
},
inheritMetadata(metadata) {
- for (const nodeId of this.nodeIds) {
- this.updateContentNode({ id: nodeId, ...metadata, mergeMapFields: true });
+ if (!this.createMode) {
+ // This shouldn't happen, but prevent this just in case.
+ return;
+ }
+ const setMetadata = () => {
+ const nodeIds = this.uploadMode ? this.newNodeIds : this.selected;
+ for (const nodeId of nodeIds) {
+ this.updateContentNode({
+ id: nodeId,
+ ...metadata,
+ mergeMapFields: true,
+ checkComplete: true,
+ });
+ }
+ this.newNodeIds = [];
+ };
+ if (!this.creatingNodes) {
+ setMetadata();
+ } else {
+ const unwatch = this.$watch('creatingNodes', creatingNodes => {
+ if (!creatingNodes) {
+ unwatch();
+ setMetadata();
+ }
+ });
}
},
},
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/InheritAncestorMetadataModal.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/InheritAncestorMetadataModal.vue
index 6c0a42fda7..333d3f0eab 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/InheritAncestorMetadataModal.vue
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/InheritAncestorMetadataModal.vue
@@ -7,13 +7,13 @@
:submitText="$tr('continueAction')"
:cancelText="$tr('cancelAction')"
@submit="handleContinue"
- @cancel="closed = true"
+ @cancel="handleCancel"
>
-
- {{ $tr('inheritMetadataDescription') }}
-
+
+ {{ $tr('inheritMetadataDescription') }}
+
!isUndefined(this.parent.extra_fields.inherit_metadata[field])
+ field => !isUndefined(this.parent.extra_fields.inherited_metadata[field])
)
);
},
active() {
- return (
- this.parent !== null &&
- !this.allFieldsDesignatedByParent &&
- !this.closed &&
- this.parentHasInheritableMetadata
- );
+ return this.parent !== null && !this.closed;
},
inheritableMetadataItems() {
const returnValue = {};
@@ -141,6 +136,11 @@
fieldsToInherit() {
return Object.keys(this.inheritableMetadataItems).filter(field => this.checks[field]);
},
+ parentHasNonLanguageMetadata() {
+ return (
+ !isEmpty(this.categories) || !isEmpty(this.grade_levels) || !isEmpty(this.learner_needs)
+ );
+ },
parentHasInheritableMetadata() {
return !isEmpty(this.inheritableMetadataItems);
},
@@ -178,12 +178,28 @@
this.resetData();
}
},
+ active(newValue) {
+ this.$emit('updateActive', newValue);
+ },
},
created() {
this.resetData();
},
methods: {
...mapActions('contentNode', ['updateContentNode']),
+ /**
+ * @public
+ */
+ checkInheritance() {
+ if (this.allFieldsDesignatedByParent || !this.parentHasInheritableMetadata) {
+ // If all fields have been designated by the parent, or there is nothing to inherit,
+ // automatically continue
+ this.handleContinue();
+ } else {
+ // Wait for the data to be updated before showing the dialog
+ this.closed = false;
+ }
+ },
resetData() {
if (this.parent) {
this.dontShowAgain = false;
@@ -193,12 +209,16 @@
}
this.checks = checks;
ContentNode.getAncestors(this.parent.id).then(ancestors => {
+ if (!this.parent) {
+ // If the parent has been removed before the data is fetched, return
+ return;
+ }
for (const field of inheritableFields) {
if (
- this.parent.extra_fields.inherit_metadata &&
- this.parent.extra_fields.inherit_metadata[field]
+ this.parent.extra_fields?.inherited_metadata &&
+ !isUndefined(this.parent.extra_fields.inherited_metadata[field])
) {
- this.checks[field] = this.parent.extra_fields.inherit_metadata[field];
+ this.checks[field] = this.parent.extra_fields.inherited_metadata[field];
}
}
this.categories = ancestors.reduce((acc, ancestor) => {
@@ -230,14 +250,7 @@
};
}, {});
this.$nextTick(() => {
- if (this.allFieldsDesignatedByParent || !this.parentHasInheritableMetadata) {
- // If all fields have been designated by the parent, or there is nothing to inherit,
- // automatically continue
- this.handleContinue();
- } else {
- // Wait for the data to be updated before showing the dialog
- this.closed = false;
- }
+ this.checkInheritance();
});
});
}
@@ -250,19 +263,19 @@
// but just in case, return
return;
}
- const inherit_metadata = {
- ...(this.parent?.extra_fields.inherit_metadata || {}),
+ const inherited_metadata = {
+ ...(this.parent?.extra_fields.inherited_metadata || {}),
};
for (const field of inheritableFields) {
if (this.inheritableMetadataItems[field]) {
// Only store preferences for fields that have been shown to the user as inheritable
- inherit_metadata[field] = this.checks[field];
+ inherited_metadata[field] = this.checks[field];
}
}
this.updateContentNode({
id: this.parent.id,
extra_fields: {
- inherit_metadata,
+ inherited_metadata,
},
});
},
@@ -283,6 +296,10 @@
}
this.closed = true;
},
+ handleCancel() {
+ this.closed = true;
+ this.$emit('inherit', {});
+ },
},
$trs: {
applyResourceDetailsTitle: "Apply details from the folder '{folder}'",
diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/move/MoveModal.vue b/contentcuration/contentcuration/frontend/channelEdit/components/move/MoveModal.vue
index d5c6164863..a68c50d51b 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/components/move/MoveModal.vue
+++ b/contentcuration/contentcuration/frontend/channelEdit/components/move/MoveModal.vue
@@ -135,7 +135,7 @@