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
20 changes: 15 additions & 5 deletions contentcuration/contentcuration/frontend/administration/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import difference from 'lodash/difference';
import findKey from 'lodash/findKey';
import intersection from 'lodash/intersection';
import transform from 'lodash/transform';
import omit from 'lodash/omit';
import pickBy from 'lodash/pickBy';

function _getBooleanVal(value) {
Expand Down Expand Up @@ -137,10 +136,10 @@ export const tableMixin = {
{
...this.$route.query,
page_size: pagination.rowsPerPage,
...omit(pagination, ['rowsPerPage', 'totalItems']),
...pagination,
},
value => {
return value !== null;
(value, key) => {
return value !== null && key !== 'rowsPerPage' && key !== 'totalItems';
}
);

Expand All @@ -156,6 +155,17 @@ export const tableMixin = {
});
},
},
fetchParams() {
const params = {
...this.$route.query,
};
if (params.sortBy) {
params.ordering = (params.descending ? '-' : '') + params.sortBy;
delete params.sortBy;
delete params.descending;
}
return params;
},
},
watch: {
'$route.query'() {
Expand All @@ -168,7 +178,7 @@ export const tableMixin = {
methods: {
_loadItems() {
this.loading = true;
this.fetch(this.$route.query).then(() => {
this.fetch(this.fetchParams).then(() => {
this.loading = false;
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
),

// Channels
...this.channels.map(channelId =>
...this.channel_id__in.map(channelId =>
createFilter(
channelId,
this.getChannelName(channelId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
:menu-props="menuProps"
/>
<MultiSelect
v-model="channels"
v-model="channel_id__in"
:label="$tr('channelSourceLabel')"
:items="channelOptions"
item-text="name"
Expand Down Expand Up @@ -197,8 +197,8 @@
loadChannels(listType) {
this.loadingChannels = true;
this.loadChannelList({ listType }).then(channels => {
if (this.channels.length) {
this.channels = [];
if (this.channel_id__in.length) {
this.channel_id__in = [];
}

this.channelOptions = channels.filter(c => c.id !== this.currentChannelId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { generateSearchMixin } from 'shared/mixins';
const searchFilters = {
kinds: filterTypes.MULTISELECT,
resources: filterTypes.BOOLEAN,
channels: filterTypes.MULTISELECT,
channel_id__in: filterTypes.MULTISELECT,
languages: filterTypes.MULTISELECT,
licenses: filterTypes.MULTISELECT,
coach: filterTypes.BOOLEAN,
Expand Down
104 changes: 99 additions & 5 deletions contentcuration/contentcuration/frontend/shared/data/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import flatMap from 'lodash/flatMap';
import get from 'lodash/get';
import isArray from 'lodash/isArray';
import isFunction from 'lodash/isFunction';
import isNumber from 'lodash/isNumber';
import isString from 'lodash/isString';
import matches from 'lodash/matches';
import overEvery from 'lodash/overEvery';
import pick from 'lodash/pick';
import sortBy from 'lodash/sortBy';
import uniq from 'lodash/uniq';
import uniqBy from 'lodash/uniqBy';
Expand Down Expand Up @@ -47,13 +49,69 @@ const QUERY_SUFFIXES = {
LTE: 'lte',
};

const ORDER_FIELD = 'ordering';

const VALID_SUFFIXES = new Set(Object.values(QUERY_SUFFIXES));

const SUFFIX_SEPERATOR = '__';
const validPositions = new Set(Object.values(RELATIVE_TREE_POSITIONS));

const EMPTY_ARRAY = Symbol('EMPTY_ARRAY');

class Paginator {
constructor(params) {
// Get parameters for page number based pagination
Object.assign(this, pick(params, 'page', 'page_size'));
// At a minimum, this pagination style requires a page_size
// parameter, so we check to see if that exists.
if (this.page_size) {
this.pageNumberType = true;
this.page = this.page || 1;
}
// Get parameters for limit offset pagination
Object.assign(this, pick(params, 'limit', 'offset'));
// At a minimum, this pagination style requires a limit
// parameter, so we check to see if that exists.
if (this.limit) {
this.limitOffsetType = true;
this.offset = this.offset || 0;
}
if (this.pageNumberType && this.limitOffsetType) {
console.warn(
'Specified both page number type pagination and limit offset may get unexpected results'
);
}
}
paginate(collection) {
let offset;
let limit;
if (this.pageNumberType) {
offset = (this.page - 1) * this.page_size;
limit = this.page_size;
}
if (this.limitOffsetType) {
offset = this.offset;
limit = this.limit;
}
if (isNumber(offset) && isNumber(limit)) {
const countPromise = collection.count();
const resultPromise = collection
.offset(offset)
.limit(limit)
.toArray();
return Promise.all([countPromise, resultPromise]).then(([count, results]) => {
const out = { count, results };
if (this.pageNumberType) {
out.total_pages = Math.ceil(count / this.page_size);
out.page = this.page;
}
return out;
});
}
return collection.toArray();
}
}

// Custom uuid4 function to match our dashless uuids on the server side
export function uuid4() {
return uuidv4().replace(/-/g, '');
Expand Down Expand Up @@ -315,6 +373,12 @@ class IndexedDBResource {
const arrayParams = {};
// Suffixed parameters - ones that are filtering by [gt/lt](e)
const suffixedParams = {};
// Field to sort by
let sortBy;
let reverse;

// Setup paginator.
const paginator = new Paginator(params);
for (let key of Object.keys(params)) {
// Partition our parameters
const [rootParam, suffix] = key.split(SUFFIX_SEPERATOR);
Expand All @@ -329,7 +393,16 @@ class IndexedDBResource {
} else if (!suffix) {
whereParams[rootParam] = params[key];
}
} else {
} else if (key === ORDER_FIELD) {
const ordering = params[key];
if (ordering.indexOf('-') === 0) {
sortBy = ordering.substring(1);
reverse = true;
} else {
sortBy = ordering;
}
} else if (!paginator[key]) {
// Don't filter by parameters that are used for pagination
filterParams[rootParam] = params[key];
}
}
Expand All @@ -344,7 +417,8 @@ class IndexedDBResource {
}
return Promise.resolve(EMPTY_ARRAY);
}
collection = table.where(Object.keys(arrayParams)[0]).anyOf(Object.values(arrayParams)[0]);
const keyPath = Object.keys(arrayParams)[0];
collection = table.where(keyPath).anyOf(Object.values(arrayParams)[0]);
if (process.env.NODE_ENV !== 'production') {
// Flag a warning if we tried to filter by an Array and other where params
if (Object.keys(whereParams).length > 1) {
Expand All @@ -358,6 +432,9 @@ class IndexedDBResource {
}
}
Object.assign(filterParams, whereParams);
if (sortBy === keyPath) {
sortBy = null;
}
} else if (Object.keys(arrayParams).length > 1) {
if (process.env.NODE_ENV !== 'production') {
// Flag a warning if we tried to filter by an Array and other where params
Expand All @@ -372,8 +449,19 @@ class IndexedDBResource {
}
} else if (Object.keys(whereParams).length > 0) {
collection = table.where(whereParams);
if (whereParams[sortBy] && Object.keys(whereParams).length === 1) {
// If there is only one where parameter, then the collection should already be sorted
// by the index that it was queried by.
// https://dexie.org/docs/Collection/Collection.sortBy()#remarks
sortBy = null;
}
} else {
collection = table.toCollection();
if (sortBy && this.indexFields.has(sortBy) && !reverse) {
collection = table.orderBy(sortBy);
sortBy = null;
} else {
collection = table.toCollection();
}
}
let filterFn;
if (Object.keys(filterParams).length !== 0) {
Expand Down Expand Up @@ -421,7 +509,13 @@ class IndexedDBResource {
if (filterFn) {
collection = collection.filter(filterFn);
}
return collection.toArray();
if (sortBy) {
if (reverse) {
collection = collection.reverse();
}
collection = collection.sortBy(sortBy);
}
return paginator.paginate(collection);
}

get(id) {
Expand Down Expand Up @@ -605,7 +699,7 @@ class Resource extends mix(APIResource, IndexedDBResource) {
if (objs === EMPTY_ARRAY) {
return [];
}
if (!objs.length) {
if (!objs.length && !objs.count) {
return this.requestCollection(params);
}
if (doRefresh) {
Expand Down
Loading