Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { shallowMount, mount } from '@vue/test-utils';
import { AssessmentItemToolbarActions } from '../../constants';
import { assessmentItemKey } from '../../utils';
import AssessmentEditor from './AssessmentEditor';
import { AssessmentItemTypes, ValidationErrors } from 'shared/constants';
import { AssessmentItemTypes, ValidationErrors, DELAYED_VALIDATION } from 'shared/constants';

jest.mock('shared/views/MarkdownEditor/MarkdownEditor/MarkdownEditor.vue');
jest.mock('shared/views/MarkdownEditor/MarkdownViewer/MarkdownViewer.vue');
Expand Down Expand Up @@ -306,7 +306,7 @@ describe('AssessmentEditor', () => {
answers: [],
hints: [],
order: 1,
isNew: true,
[DELAYED_VALIDATION]: true,
});
});

Expand Down Expand Up @@ -348,7 +348,7 @@ describe('AssessmentEditor', () => {
answers: [],
hints: [],
order: 2,
isNew: true,
[DELAYED_VALIDATION]: true,
});
expect(listeners.addItem).toBeCalledTimes(1);
});
Expand Down Expand Up @@ -433,7 +433,7 @@ describe('AssessmentEditor', () => {
answers: [],
hints: [],
order: 4,
isNew: true,
[DELAYED_VALIDATION]: true,
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
import AssessmentItemEditor from '../AssessmentItemEditor/AssessmentItemEditor';
import AssessmentItemPreview from '../AssessmentItemPreview/AssessmentItemPreview';
import Checkbox from 'shared/views/form/Checkbox';
import { AssessmentItemTypes } from 'shared/constants';
import { AssessmentItemTypes, DELAYED_VALIDATION } from 'shared/constants';

function areItemsEqual(item1, item2) {
if (!item1 || !item2) {
Expand Down Expand Up @@ -245,7 +245,7 @@
}
this.$emit('updateItem', {
...assessmentItemKey(this.activeItem),
isNew: false,
[DELAYED_VALIDATION]: false,
});
this.activeItem = null;
},
Expand Down Expand Up @@ -313,8 +313,8 @@
type: AssessmentItemTypes.SINGLE_SELECTION,
answers: [],
hints: [],
isNew: true,
order: newItemOrder,
[DELAYED_VALIDATION]: true,
};

let reorderedItems = [...this.sortedItems];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@
return this.getAssessmentItems(this.nodeId);
},
areAssessmentItemsValid() {
return this.getAssessmentItemsAreValid({ contentNodeId: this.nodeId, ignoreNew: true });
return this.getAssessmentItemsAreValid({ contentNodeId: this.nodeId, ignoreDelayed: true });
},
assessmentItemsErrors() {
return this.getAssessmentItemsErrors({ contentNodeId: this.nodeId, ignoreNew: true });
return this.getAssessmentItemsErrors({ contentNodeId: this.nodeId, ignoreDelayed: true });
},
invalidItemsErrorMessage() {
const invalidItemsCount = this.getInvalidAssessmentItemsCount({
contentNodeId: this.nodeId,
ignoreNew: true,
ignoreDelayed: true,
});

if (!invalidItemsCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<VLayout row>
<VFlex shrink class="text-truncate">
<h3
v-if="hasTitle(node) || !canEdit || copying || node.isNew"
v-if="hasTitle(node) || !canEdit || copying || isNew"
class="notranslate text-truncate"
:class="[
isCompact ? 'font-weight-regular' : '',
Expand All @@ -69,7 +69,7 @@
</VFlex>
<VFlex>
<ContentNodeValidator
v-if="canEdit && !copying && !node.isNew"
v-if="canEdit && !copying && !isNew"
:node="node"
/>
</VFlex>
Expand Down Expand Up @@ -194,7 +194,7 @@
import ContentNodeValidator from '../ContentNodeValidator';
import ContentNodeChangedIcon from '../ContentNodeChangedIcon';
import TaskProgress from '../../views/progress/TaskProgress';
import { ContentLevel, Categories } from '../../../shared/constants';
import { ContentLevel, Categories, NEW_OBJECT } from 'shared/constants';
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
import { RolesNames } from 'shared/leUtils/Roles';
import ImageOnlyThumbnail from 'shared/views/files/ImageOnlyThumbnail';
Expand Down Expand Up @@ -262,6 +262,9 @@
isTopic() {
return this.node.kind === ContentKindsNames.TOPIC;
},
isNew() {
return this.node[NEW_OBJECT];
},
thumbnailAttrs() {
const { title, kind, thumbnail_src: src, thumbnail_encoding: encoding } = this.node;
return { title, kind, src, encoding };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
import BottomBar from 'shared/views/BottomBar';
import FileDropzone from 'shared/views/files/FileDropzone';
import { isNodeComplete } from 'shared/utils/validation';
import { DELAYED_VALIDATION } from 'shared/constants';

const CHECK_STORAGE_INTERVAL = 10000;

Expand Down Expand Up @@ -422,7 +423,7 @@
// X button action
this.enableValidation(this.nodeIds);
let assessmentItems = this.getAssessmentItems(this.nodeIds);
assessmentItems.forEach(item => (item.question ? (item.isNew = false) : ''));
assessmentItems.forEach(item => (item.question ? (item[DELAYED_VALIDATION] = false) : ''));
this.updateAssessmentItems(assessmentItems);
// reaches into Details Tab to run save of diffTracker
// before the validation pop up is executed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
areAssessmentItemsValid() {
return (
!this.oneSelected ||
this.getAssessmentItemsAreValid({ contentNodeId: this.nodeIds[0], ignoreNew: true })
this.getAssessmentItemsAreValid({ contentNodeId: this.nodeIds[0], ignoreDelayed: true })
);
},
areFilesValid() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
getInvalidAssessmentItemsCount,
getAssessmentItemsAreValid,
} from '../getters';
import { AssessmentItemTypes, ValidationErrors } from 'shared/constants';
import { AssessmentItemTypes, DELAYED_VALIDATION, ValidationErrors } from 'shared/constants';

describe('assessmentItem getters', () => {
let state;
Expand Down Expand Up @@ -45,7 +45,7 @@ describe('assessmentItem getters', () => {
'assessment-id-3': {
assessment_id: 'assessment-id-3',
contentnode: 'content-node-id-2',
isNew: true,
[DELAYED_VALIDATION]: true,
type: AssessmentItemTypes.SINGLE_SELECTION,
question: 'What color are minions?',
answers: [
Expand All @@ -67,15 +67,15 @@ describe('assessmentItem getters', () => {
'assessment-id-4': {
assessment_id: 'assessment-id-4',
contentnode: 'content-node-id-3',
isNew: true,
[DELAYED_VALIDATION]: true,
type: AssessmentItemTypes.SINGLE_SELECTION,
question: '',
answers: [],
},
'assessment-id-5': {
assessment_id: 'assessment-id-5',
contentnode: 'content-node-id-3',
isNew: true,
[DELAYED_VALIDATION]: true,
type: AssessmentItemTypes.SINGLE_SELECTION,
question: '',
answers: [],
Expand Down Expand Up @@ -103,7 +103,7 @@ describe('assessmentItem getters', () => {
{
assessment_id: 'assessment-id-3',
contentnode: 'content-node-id-2',
isNew: true,
[DELAYED_VALIDATION]: true,
type: AssessmentItemTypes.SINGLE_SELECTION,
question: 'What color are minions?',
answers: [
Expand Down Expand Up @@ -145,9 +145,9 @@ describe('assessmentItem getters', () => {
});
});

it("doesn't include invalid nodes errors that are new if `ignoreNew` set to true", () => {
it("doesn't include invalid nodes errors that are new if `ignoreDelayed` set to true", () => {
expect(
getAssessmentItemsErrors(state)({ contentNodeId: 'content-node-id-2', ignoreNew: true })
getAssessmentItemsErrors(state)({ contentNodeId: 'content-node-id-2', ignoreDelayed: true })
).toEqual({
'assessment-id-2': [
ValidationErrors.QUESTION_REQUIRED,
Expand All @@ -163,11 +163,11 @@ describe('assessmentItem getters', () => {
expect(getInvalidAssessmentItemsCount(state)({ contentNodeId: 'content-node-id-2' })).toBe(2);
});

it("doesn't count invalid nodes that are new if `ignoreNew` set to true", () => {
it("doesn't count invalid nodes that are new if `ignoreDelayed` set to true", () => {
expect(
getInvalidAssessmentItemsCount(state)({
contentNodeId: 'content-node-id-2',
ignoreNew: true,
ignoreDelayed: true,
})
).toBe(1);
});
Expand All @@ -182,9 +182,12 @@ describe('assessmentItem getters', () => {
expect(getAssessmentItemsAreValid(state)({ contentNodeId: 'content-node-id-2' })).toBe(false);
});

it('returns true if all assessment items are not valid and marked as new if `ignoreNew` set to true', () => {
it('returns true if all assessment items are not valid and marked as new if `ignoreDelayed` set to true', () => {
expect(
getAssessmentItemsAreValid(state)({ contentNodeId: 'content-node-id-4', ignoreNew: true })
getAssessmentItemsAreValid(state)({
contentNodeId: 'content-node-id-4',
ignoreDelayed: true,
})
).toBe(true);
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getAssessmentItemErrors } from 'shared/utils/validation';
import { DELAYED_VALIDATION } from 'shared/constants';

/**
* Get assessment items of a node.
Expand All @@ -25,17 +26,17 @@ export function getAssessmentItemsCount(state) {

/**
* Get a map of assessment items errors where keys are assessment ids.
* Consider new assessment items as valid if `ignoreNew` is true.
* Consider new assessment items as valid if `ignoreDelayed` is true.
*/
export function getAssessmentItemsErrors(state) {
return function({ contentNodeId, ignoreNew = false }) {
return function({ contentNodeId, ignoreDelayed = false }) {
const assessmentItemsErrors = {};
if (!state.assessmentItemsMap || !state.assessmentItemsMap[contentNodeId]) {
return assessmentItemsErrors;
}
Object.keys(state.assessmentItemsMap[contentNodeId]).forEach(assessmentItemId => {
const assessmentItem = state.assessmentItemsMap[contentNodeId][assessmentItemId];
if (ignoreNew && assessmentItem.isNew) {
if (ignoreDelayed && assessmentItem[DELAYED_VALIDATION]) {
assessmentItemsErrors[assessmentItemId] = [];
} else {
assessmentItemsErrors[assessmentItemId] = getAssessmentItemErrors(assessmentItem);
Expand All @@ -47,12 +48,12 @@ export function getAssessmentItemsErrors(state) {

/**
* Get total number of invalid assessment items of a node.
* Consider new assessment items as valid if `ignoreNew` is true.
* Consider new assessment items as valid if `ignoreDelayed` is true.
*/
export function getInvalidAssessmentItemsCount(state) {
return function({ contentNodeId, ignoreNew = false }) {
return function({ contentNodeId, ignoreDelayed = false }) {
let count = 0;
const assessmentItemsErrors = getAssessmentItemsErrors(state)({ contentNodeId, ignoreNew });
const assessmentItemsErrors = getAssessmentItemsErrors(state)({ contentNodeId, ignoreDelayed });

for (const assessmentItemId in assessmentItemsErrors) {
if (assessmentItemsErrors[assessmentItemId].length) {
Expand All @@ -66,10 +67,10 @@ export function getInvalidAssessmentItemsCount(state) {

/**
* Are all assessment items of a node valid?
* Consider new assessment items as valid if `ignoreNew` is true.
* Consider new assessment items as valid if `ignoreDelayed` is true.
*/
export function getAssessmentItemsAreValid(state) {
return function({ contentNodeId, ignoreNew = false }) {
return getInvalidAssessmentItemsCount(state)({ contentNodeId, ignoreNew }) === 0;
return function({ contentNodeId, ignoreDelayed = false }) {
return getInvalidAssessmentItemsCount(state)({ contentNodeId, ignoreDelayed }) === 0;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function getContentNodeIsValid(state, getters, rootState, rootGetters) {
// and it is not used within a form to run field validations,
// it's okay to set this to false. This also accounts for
// any async delays with the node creation
ignoreNew: false,
ignoreDelayed: false,
})))
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import find from 'lodash/find';
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
import { RolesNames } from 'shared/leUtils/Roles';
import { NEW_OBJECT } from 'shared/constants';

export function parseNode(node, children) {
const thumbnail_encoding = JSON.parse(node.thumbnail_encoding || '{}');
Expand Down Expand Up @@ -35,7 +34,6 @@ export function parseNode(node, children) {
...aggregateValues,
thumbnail_encoding,
tags,
isNew: node[NEW_OBJECT],
};
}

Expand Down
4 changes: 4 additions & 0 deletions contentcuration/contentcuration/frontend/shared/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export const NOVALUE = Symbol('No value default');
// that they have not yet been committed to our IndexedDB layer.
export const NEW_OBJECT = Symbol('New object');

// This symbol is used as a key on new objects used to denote when
// validation should be delayed
export const DELAYED_VALIDATION = Symbol('Delayed validation');

export const kindToIconMap = {
audio: 'headset',
channel: 'apps',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ export const RELATIVE_TREE_POSITIONS = {
RIGHT: 'right',
};

// Special fields used for copying and other async tasks
// Special fields used for frontend specific handling
export const COPYING_FLAG = '__COPYING';
export const TASK_ID = '__TASK_ID';
export const LAST_FETCHED = '__last_fetch';

// This constant is used for saving/retrieving a current
// user object from the session table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ import {
ACTIVE_CHANNELS,
CHANNEL_SYNC_KEEP_ALIVE_INTERVAL,
MAX_REV_KEY,
LAST_FETCHED,
} from './constants';
import applyChanges, { applyMods, collectChanges } from './applyRemoteChanges';
import mergeAllChanges from './mergeChanges';
import db, { channelScope, CLIENTID, Collection } from './db';
import { API_RESOURCES, INDEXEDDB_RESOURCES } from './registry';
import { fileErrors, NEW_OBJECT } from 'shared/constants';
import { DELAYED_VALIDATION, fileErrors, NEW_OBJECT } from 'shared/constants';
import client, { paramsSerializer } from 'shared/client';
import { currentLanguage } from 'shared/i18n';
import urls from 'shared/urls';

// Number of seconds after which data is considered stale.
const REFRESH_INTERVAL = 5;

const LAST_FETCHED = '__last_fetch';

const QUERY_SUFFIXES = {
IN: 'in',
GT: 'gt',
Expand Down Expand Up @@ -495,7 +494,7 @@ class IndexedDBResource {
}

/**
* Method to remove the NEW_OBJECT
* Method to remove the NEW_OBJECT and DELAYED_VALIDATION symbols
* property so we don't commit it to IndexedDB
* @param {Object} obj
* @return {Object}
Expand All @@ -505,6 +504,7 @@ class IndexedDBResource {
...obj,
};
delete out[NEW_OBJECT];
delete out[DELAYED_VALIDATION];
return out;
}

Expand Down
Loading