Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Granular Import Export UIs #2610

Merged
merged 56 commits into from
Nov 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
1da0add
Add "available channels page"
jonboiser Oct 10, 2017
4fff7ee
Add objectAssign config to buble-loader
jonboiser Oct 13, 2017
2dd6aa8
Add selectedResourcesSize component
jonboiser Oct 13, 2017
b96744f
Convert some object.assigns to object spread
jonboiser Oct 16, 2017
e91bf62
Stub select content page
jonboiser Oct 16, 2017
75fa020
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Oct 17, 2017
29fe79c
Move channelFactory to utils
jonboiser Oct 17, 2017
aad8350
Show description and resource counts
jonboiser Oct 17, 2017
db49a17
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Oct 24, 2017
5fcad4d
Show differences between channel on/off device
jonboiser Oct 24, 2017
fff65ad
Add selected resources size component
jonboiser Oct 24, 2017
3adc890
Show new version ui-alert
jonboiser Oct 25, 2017
6775eac
Integrate with on-device info display components
jonboiser Oct 25, 2017
4e56fb2
Add ‘add node’ actions
jonboiser Oct 25, 2017
752cdaf
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Oct 27, 2017
e533d03
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Oct 30, 2017
b5defb8
Configure vue-loader to use object.assign
jonboiser Oct 30, 2017
122d26e
Call CNG API with drive_id instead of datafolder
jonboiser Nov 3, 2017
7dc7ea9
Put channel root in breadcrumbs metadata
jonboiser Nov 3, 2017
da2dc20
Add transformBreadcrumb utility
jonboiser Nov 3, 2017
33ad5fb
Add showAvailableChannelsPage action
jonboiser Nov 3, 2017
c85d6c5
Add select-drive-modal
jonboiser Nov 5, 2017
a9ec297
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 6, 2017
d9244d1
Linting and broken integrations
jonboiser Nov 6, 2017
9425616
Add ‘showAllCrumbs’ prop to k-breadcrumbs
jonboiser Nov 7, 2017
d52f9ee
Style select-content-page
jonboiser Nov 7, 2017
b79c504
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 13, 2017
221d39b
Integrate with remote channels API
jonboiser Nov 13, 2017
0325b91
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 13, 2017
f140574
Integrate RemoteChannelAPI
jonboiser Nov 14, 2017
2a23c35
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 15, 2017
f57774c
Cleanup treeViewUtils
jonboiser Nov 15, 2017
20f9b14
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 15, 2017
39726d9
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 15, 2017
60dd89a
Fix tests
jonboiser Nov 15, 2017
be13b4d
Pull tasks outside of resource layer
jonboiser Nov 21, 2017
883bac3
Fix channel size counts
jonboiser Nov 21, 2017
bd7c21e
Add error ui-alerts to select-content-page
jonboiser Nov 21, 2017
574634b
Cleanup
jonboiser Nov 21, 2017
1e122ad
Add better “no drives” message to select drive modal
jonboiser Nov 21, 2017
f40df7e
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 21, 2017
0c9467d
INtegrate filesize endpoint
jonboiser Nov 21, 2017
1f00eaf
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 22, 2017
8c9803b
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 22, 2017
4362488
Change resources_on_device -> on_device_resources
jonboiser Nov 22, 2017
8c4fa00
Merge remote-tracking branch 'origin/develop' into available-channels
jonboiser Nov 22, 2017
44587cf
Prettier autofixes
jonboiser Nov 22, 2017
9e7a8de
Cleanup
jonboiser Nov 22, 2017
2209afd
On manage-content hide channels without downloaded resources
jonboiser Nov 22, 2017
a5c0ac8
Fix double node-adding bug
jonboiser Nov 22, 2017
c38765b
breadcrumbs style guide is 'in progress' - re #2664
indirectlylit Nov 22, 2017
f42ef22
Fix channel filtering on localexport channels available
jonboiser Nov 22, 2017
1969baa
Hide unavailable nodes during localexport
jonboiser Nov 22, 2017
d47f82a
Reset included/omitted lists when going back in wizard
jonboiser Nov 22, 2017
932d155
Merge branch 'develop' into available-channels
jonboiser Nov 23, 2017
fb80aff
Merge branch 'develop' into available-channels
indirectlylit Nov 23, 2017
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
9 changes: 3 additions & 6 deletions frontend_build/src/webpack.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@ var config = {
options: {
preserveWhitespace: false,
loaders: {
js: {
loader: 'buble-loader',
query: {
objectAssign: 'Object.assign',
},
},
stylus: ExtractTextPlugin.extract({
allChunks: true,
use: vueStylusLoaders,
Expand All @@ -76,6 +70,9 @@ var config = {
use: vueSassLoaders,
}),
},
buble: {
objectAssign: 'Object.assign',
},
// handles <mat-svg/>, <ion-svg/>, <iconic-svg/>, and <file-svg/> svg inlining
preLoaders: { html: 'svg-icon-inline-loader' },
},
Expand Down
9 changes: 7 additions & 2 deletions karma_config/testUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MockResource {
} else {
fetchable.fetch = () => Promise.resolve(payload);
}
sinon.spy(fetchable, 'fetch');
return fetchable;
}

Expand All @@ -35,7 +36,9 @@ class MockResource {
}

__getModelFetchReturns(payload, willReject = false) {
this.getModel.returns(this.__getFetchable(payload, willReject));
const fetchable = this.__getFetchable(payload, willReject);
this.getModel.returns(fetchable);
return fetchable;
}

__getModelSaveReturns(payload, willReject = false) {
Expand All @@ -45,7 +48,9 @@ class MockResource {
}

__getCollectionFetchReturns(payload, willReject = false) {
this.getCollection.returns(this.__getFetchable(payload, willReject));
const fetchable = this.__getFetchable(payload, willReject);
this.getCollection.returns(fetchable);
return fetchable;
}
}

Expand Down
3 changes: 3 additions & 0 deletions karma_config/vueLocal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import router from 'vue-router';
import vueintl from 'vue-intl';
import 'intl';
import 'intl/locale-data/jsonp/en.js';
import kRouter from 'kolibri.coreVue.router';

kRouter.init([]);

vue.prototype.Kolibri = {};
vue.config.silent = true;
Expand Down
1 change: 1 addition & 0 deletions kolibri/content/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ def _studio_response_to_kolibri_response(cls, studioresp):
"thumbnail": studioresp.get("icon_encoding"),
"public": studioresp.get("public", True),
"total_resources": studioresp.get("total_resource_count", 0),
"total_file_size": studioresp.get("published_size"),
"version": studioresp.get("version", 0),
"included_languages": included_languages,
"last_updated": studioresp.get("last_published"),
Expand Down
14 changes: 12 additions & 2 deletions kolibri/content/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,18 @@ def get_lang_name(self, instance):

class Meta:
model = ChannelMetadata
fields = ('root', 'id', 'name', 'description', 'author', 'last_updated', 'version', 'thumbnail',
'lang_code', 'lang_name')
fields = (
'author',
'description',
'id',
'last_updated',
'lang_code',
'lang_name',
'name',
'root',
'thumbnail',
'version',
)


class LowerCaseField(serializers.CharField):
Expand Down
3 changes: 3 additions & 0 deletions kolibri/core/assets/src/api-resources/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Resource } from '../api-resource';
/**
* @example <caption>Delete a channel</caption>
* ChannelResource.getModel(channel_id).delete()
*
* @example Only get the channels that are "available" (i.e. with resources on device)
* ChannelResource.getCollection().fetch({ available: true })
*/
export default class ChannelResource extends Resource {
static resourceName() {
Expand Down
28 changes: 28 additions & 0 deletions kolibri/core/assets/src/api-resources/contentNodeGranular.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Resource } from '../api-resource';

/**
* @example Get ContentNode from a local USB drive for the purposes of importing from that drive.
* ContentNodeGranular.getModel(pk).fetch({ importing_from_drive_id: 'drive_1' });
*
* @example Get ContentNode from a remote channel (whose content DB has been downloaded).
* OR exporting to a USB drive.
* ContentNodeGranular.getModel(pk).fetch();
*
* Note: if the top-level of the channel is desired, then `pk` must be the channels's `root` id.
*/
export default class ContentNodeGranularResource extends Resource {
static resourceName() {
return 'contentnode_granular';
}

static idKey() {
return 'pk';
}

// Given a node ID, returns the {total_file_size, on_device_file_size}
getFileSizes(pk) {
return this.client({
path: `${this.urls['contentnodefilesize_list']()}${pk}`,
});
}
}
6 changes: 6 additions & 0 deletions kolibri/core/assets/src/api-resources/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ClassroomResource from './classroom';
import ContentNodeResource from './contentNode';
import ContentNodeGranular from './contentNodeGranular';
import FacilityUserResource from './facilityUser';
import FacilityUsernameResource from './facilityUsername';
import LearnerGroupResource from './learnerGroup';
Expand All @@ -24,6 +25,7 @@ import UserProgressResource from './userProgress';
import ContentNodeProgressResource from './contentNodeProgress';
import DeviceProvisionResource from './deviceProvision';
import DevicePermissionsResource, { NewDevicePermissionsResource } from './devicePermissions';
import RemoteChannel from './remoteChannel';

const classroomResource = new ClassroomResource();
const contentNodeResource = new ContentNodeResource();
Expand Down Expand Up @@ -52,10 +54,14 @@ const contentNodeProgressResource = new ContentNodeProgressResource();
const deviceProvisionResource = new DeviceProvisionResource();
const devicePermissionsResource = new DevicePermissionsResource();
const newDevicePermissionsResource = new NewDevicePermissionsResource();
const ContentNodeGranularResource = new ContentNodeGranular();
const RemoteChannelResource = new RemoteChannel();

export {
classroomResource as ClassroomResource,
contentNodeResource as ContentNodeResource,
ContentNodeGranularResource,
RemoteChannelResource,
facilityUserResource as FacilityUserResource,
facilityUsernameResource as FacilityUsernameResource,
learnerGroupResource as LearnerGroupResource,
Expand Down
7 changes: 7 additions & 0 deletions kolibri/core/assets/src/api-resources/remoteChannel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Resource } from '../api-resource';

export default class RemoteChannelResource extends Resource {
static resourceName() {
return 'remotechannel';
}
}
123 changes: 95 additions & 28 deletions kolibri/core/assets/src/api-resources/task.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,109 @@
import { Resource } from '../api-resource';
import pickBy from 'lodash/pickBy';

export default class TaskResource extends Resource {
static resourceName() {
return 'task';
}

localExportContent(driveId) {
const clientObj = {
path: this.localExportUrl(),
entity: { drive_id: driveId },
};
return this.client(clientObj);
/**
* Initiates a Task that imports a Channel Metadata DB from a remote source
*
* @param {string} channel_id -
*
*/
startRemoteChannelImport({ channel_id }) {
return this.client({
path: this.urls[`${this.name}_startremotechannelimport`](),
method: 'POST',
entity: {
channel_id,
},
});
}

localImportContent(driveId) {
const clientObj = {
path: this.localImportUrl(),
entity: { drive_id: driveId },
};
return this.client(clientObj);
/**
* Initiates a Task that imports a Channel Metadata DB from a local drive
*
* @param {string} params.channel_id -
* @param {string} params.drive_id -
*
*/
startDiskChannelImport({ channel_id, drive_id }) {
return this.client({
path: this.urls[`${this.name}_startdiskchannelimport`](),
method: 'POST',
entity: {
channel_id,
drive_id,
},
});
}

remoteImportContent(channelId) {
const clientObj = {
path: this.remoteImportUrl(),
entity: { channel_id: channelId },
};
return this.client(clientObj);
/**
* Initiates a Task that imports Channel Content from a remote source
*
* @param {string} params.channel_id -
* @param {string} [params.baseurl] - URL of remote source (defaults to Kolibri Studio)
* @param {Array<string>} [params.node_ids] -
* @param {Array<string>} [params.exclude_node_ids] -
* @returns {Promise}
*
*/
startRemoteContentImport(params) {
return this.client({
path: this.urls[`${this.name}_startremotecontentimport`](),
method: 'POST',
entity: pickBy(params),
});
}

/**
* Initiates a Task that imports Channel Content from a local drive
*
* @param {string} params.channel_id -
* @param {string} params.drive_id -
* @param {Array<string>} [params.node_ids] -
* @param {Array<string>} [params.exclude_node_ids] -
* @returns {Promise}
*
*/
startDiskContentImport(params) {
return this.client({
path: this.urls[`${this.name}_startdiskcontentimport`](),
method: 'POST',
entity: pickBy(params),
});
}

/**
* Initiates a Task that exports Channel Content to a local drive
*
* @param {string} params.channel_id -
* @param {string} params.drive_id -
* @param {Array<string>} [params.node_ids] -
* @param {Array<string>} [params.exclude_node_ids] -
* @returns {Promise}
*
*/
startDiskContentExport(params) {
// Not naming it after URL to keep internal consistency
return this.client({
path: this.urls[`${this.name}_startdiskexport`](),
method: 'POST',
entity: pickBy(params),
});
}

/**
* Gets all the Tasks outside of the Resource Layer mechanism
*
*/
getTasks() {
return this.client({
path: this.urls[`${this.name}_list`](),
method: 'GET',
});
}

deleteChannel(channelId) {
Expand Down Expand Up @@ -58,16 +135,6 @@ export default class TaskResource extends Resource {
};
return this.client(clientObj);
}

get localExportUrl() {
return this.urls[`${this.name}_startlocalexport`];
}
get localImportUrl() {
return this.urls[`${this.name}_startlocalimport`];
}
get remoteImportUrl() {
return this.urls[`${this.name}_startremoteimport`];
}
get deleteChannelUrl() {
return this.urls[`${this.name}_startdeletechannel`];
}
Expand Down
4 changes: 4 additions & 0 deletions kolibri/core/assets/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class Router {
replace(location, onComplete, onAbort) {
return this._vueRouter.replace(location, onComplete, onAbort);
}

push(location, onComplete, onAbort) {
return this._vueRouter.push(location, onComplete, onAbort);
}
}

const router = new Router();
Expand Down
9 changes: 5 additions & 4 deletions kolibri/core/assets/src/views/core-modal/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
:style="{ width: width, height: height }"
>

<div class="top-buttons" @keydown.enter.stop>
<div class="top-buttons" @keydown.enter.stop v-if="!hideTopButtons">
<button :aria-label="$tr('goBack')" @click="emitBackEvent" class="header-btn btn-back" v-if="enableBackBtn">
<mat-svg category="navigation" name="arrow_back" />
</button>
Expand Down Expand Up @@ -100,6 +100,10 @@
type: String,
required: false,
},
hideTopButtons: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand Down Expand Up @@ -221,9 +225,6 @@
.btn-close
right: -10px

.title
text-align: center

.fade-enter-active, .fade-leave-active
transition: all 0.3s ease

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import { validateLinkObject } from 'kolibri.utils.validators';

export default {
name: 'immersiveFullScreen',
props: {
backPageLink: {
type: Object,
Expand Down
16 changes: 15 additions & 1 deletion kolibri/core/assets/src/views/k-breadcrumbs/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>

<div v-show="crumbs.length > 1">
<div v-show="showAllCrumbs || crumbs.length > 1">
<nav class="breadcrumbs">
<div v-show="collapsedCrumbs.length" class="breadcrumbs-dropdown-wrapper">
<ui-icon-button :hasDropdown="true" icon="expand_more" size="small">
Expand Down Expand Up @@ -110,6 +110,14 @@
return crumbItems.slice(0, -1).every(crumb => validateLinkObject(crumb.link));
},
},
/**
* When set to 'true', a breadcrumb will be shown for each item in 'items' array.
* Otherwise, the first item will be omitted.
*/
showAllCrumbs: {
type: Boolean,
default: false,
},
},

data: () => ({
Expand All @@ -135,6 +143,12 @@
return Math.min(this.parentWidth - DROPDOWN_SIDE_PADDING, MAX_CRUMB_WIDTH);
},
},
watch: {
items(val) {
this.crumbs = Array.from(val);
this.attachSensors();
},
},

This comment was marked as spam.

This comment was marked as spam.

created() {
this.crumbs = Array.from(this.items);
},
Expand Down
Loading