Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
087796c
Update change application code to remove reliance on current request.
rtibbles Jan 22, 2021
dd3162d
Initial implementation of more robust change tracking and syncing.
rtibbles May 3, 2021
c06b668
Add per channel and per user max server_rev tracking.
rtibbles Mar 1, 2022
3f81d54
Code cleanup from review.
rtibbles Mar 22, 2022
4f0dfed
Make Orphanage non-user visible.
rtibbles Mar 24, 2022
5077f2f
Update event generation API to add channel and user scoping. Update u…
rtibbles Mar 24, 2022
eacf9fb
Add a channel scoped event for invitiation acceptance.
rtibbles Mar 24, 2022
2a6f238
Add a special exception for channel_id scoping for channels that do n…
rtibbles Mar 24, 2022
0d6cb80
Fix synctests for viewsets.
rtibbles Mar 24, 2022
fd08e2b
Remove tests for deleted tasks.
rtibbles Mar 24, 2022
96b31fd
Change non-admin channel viewset to soft delete.
rtibbles Apr 8, 2022
d42e733
Simplify returned change handling to ensure RESTful and Sync calls re…
rtibbles Apr 8, 2022
a8c3b0b
Separate backend bookmark annotation and editing from the channels vi…
rtibbles Apr 12, 2022
681d745
Update frontend data handling to use new Bookmark backend for loading…
rtibbles Apr 12, 2022
8f8470d
Remove bookmark tests for channel. Reinstate erroneously removed edit…
rtibbles Apr 18, 2022
8af6b22
Fix JS tests.
rtibbles Apr 18, 2022
8333660
Make tweaks to active channel monitoring.
rtibbles Apr 28, 2022
cb36ec6
Copy kwargs to avoid mutating state.
rtibbles Apr 28, 2022
6adaf62
Update unsynced change indicators.
rtibbles Apr 28, 2022
26e3f89
Move all copying to be processed inline in the channel changes.
rtibbles Apr 28, 2022
9fb2703
Update frontend to properly mark channel scope of move and copy changes.
rtibbles Apr 28, 2022
fb06092
Move publishing operations out of no-op atomic transaction.
rtibbles May 26, 2022
a52916d
Generalize dummy progress tracker logic.
rtibbles May 27, 2022
57a0b48
Add change types for published and synced.
rtibbles May 27, 2022
7c0143d
Handle new change types and cleanup unused code.
rtibbles May 27, 2022
c171a6e
Handle channel publishing as an event. Update publish to take a langu…
rtibbles May 27, 2022
87f19ad
Update task tracking to be non-blocking and use sync endpoint.
rtibbles May 30, 2022
0f4ff4c
Fix synced change error handling.
rtibbles May 30, 2022
80a6f26
Update frontend to handle publish and sync as changes.
rtibbles May 30, 2022
3f63de6
Clean up content node vuex state.
rtibbles May 30, 2022
debc168
Fix frontend linting.
rtibbles May 30, 2022
1e9ff53
clean up unused tasks. Make change application tasks non-hogging.
rtibbles May 30, 2022
9ff1d45
Delete defunct task api test suite.
rtibbles Jun 8, 2022
94c071e
Fix content node tests to include channel_id in change events.
rtibbles Jun 8, 2022
f0aaaed
Make internal publish endpoint use change events.
rtibbles Jun 8, 2022
808d6bc
Remove blocking task types check from publish as no longer needed.
rtibbles Jun 8, 2022
b157f10
Update frontend following review.
rtibbles Jun 8, 2022
575590b
Add explicit ordering by server_rev for change to return.
rtibbles Jun 8, 2022
d367cd8
Lint.
rtibbles Jun 8, 2022
32cd523
Create a consolidated serialize class method for changes.
rtibbles Jun 21, 2022
23153a6
Warn rather than error when no nodes have changed.
rtibbles Jun 21, 2022
d7e6f6f
Update activate channel to store the change to communicate to editors.
rtibbles Jun 21, 2022
5d93060
Cleanup unused serializer fields.
rtibbles Jun 21, 2022
b71ae3b
Use Change class serialize method.
rtibbles Jun 21, 2022
d183644
Add unpublished changes annotation to channels.
rtibbles Jun 21, 2022
40ff645
Remove created_by from changes initiated purely to communicate to the…
rtibbles Jun 21, 2022
ab56059
Fix parentheses for proper evaluation of error state.
rtibbles Jun 21, 2022
ebc31f6
Let sync mechanism handle all change propagation to the frontend.
rtibbles Jun 21, 2022
bdf580c
Apply all changes in order to reduce conflicts.
rtibbles Jun 21, 2022
4f2c710
Set published and changed on local nodes when publishing.
rtibbles Jun 21, 2022
eab2374
Update channel unpublished changes based on returned changes.
rtibbles Jun 21, 2022
c884cf3
Use unpublished changes to determine if changed.
rtibbles Jun 21, 2022
1cb9927
Add special handling for content node dot path fields.
rtibbles Jun 21, 2022
cc30acf
Use applyMods function to apply remote changes.
rtibbles Jun 21, 2022
d0e26f1
Simplify ADD_CONTENTNODES mutation.
rtibbles Jun 21, 2022
8b25f03
Remove redundant test.
rtibbles Jun 22, 2022
2d30f14
Fix getChannels getter.
rtibbles Jun 22, 2022
ff42a51
Add exception for ricecooker channels to be published manually.
rtibbles Jun 22, 2022
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
8 changes: 4 additions & 4 deletions contentcuration/contentcuration/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import contentcuration.models as models
from contentcuration.utils.garbage_collect import get_deleted_chefs_root
from contentcuration.viewsets.sync.utils import generate_update_event
from contentcuration.viewsets.sync.constants import CHANNEL
from contentcuration.viewsets.sync.utils import generate_update_event


def write_file_to_storage(fobj, check_valid=False, name=None):
Expand Down Expand Up @@ -89,12 +89,12 @@ def activate_channel(channel, user):
user.staged_files.all().delete()
user.set_space_used()

change = generate_update_event(
models.Change.create_change(generate_update_event(
channel.id,
CHANNEL,
{
"root_id": channel.main_tree.id,
"staging_root_id": None
},
)
return change
channel_id=channel.id,
), applied=True)
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
},
},
created() {
this.activateTaskUpdateTimer();
this.initState();
},
methods: {
...mapActions('task', ['activateTaskUpdateTimer']),
...mapActions('task', ['initState']),
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
</VToolbarItems>
<VSpacer />
<OfflineText indicator />
<ProgressModal />
<div v-if="errorsInChannel && canEdit" class="mx-1">
<VTooltip bottom>
<template #activator="{ on }">
Expand Down Expand Up @@ -164,7 +165,6 @@
<slot></slot>

<PublishModal v-if="showPublishModal" v-model="showPublishModal" />
<ProgressModal :syncing="syncing" :noSyncNeeded="noSyncNeeded" />
<template v-if="isPublished">
<ChannelTokenModal v-model="showTokenModal" :channel="currentChannel" />
</template>
Expand All @@ -173,7 +173,6 @@
v-model="showSyncModal"
:channel="currentChannel"
@syncing="syncInProgress"
@nosync="noResourcesToSync"
/>
<MessageDialog v-model="showDeleteModal" :header="$tr('deleteTitle')">
{{ $tr('deletePrompt') }}
Expand Down Expand Up @@ -289,7 +288,6 @@
showClipboard: false,
showDeleteModal: false,
syncing: false,
noSyncNeeded: false,
};
},
computed: {
Expand All @@ -303,10 +301,8 @@
},
isChanged() {
return (
this.rootNode &&
(this.rootNode.changed ||
this.rootNode.has_updated_descendants ||
this.rootNode.has_new_descendants)
this.currentChannel &&
(this.currentChannel.unpublished_changes || (this.isRicecooker && this.rootNode.changed))
);
},
isPublished() {
Expand All @@ -317,6 +313,7 @@
},
disablePublish() {
return (
this.currentChannel.publishing ||
!this.isChanged ||
!this.currentChannel.language ||
(this.rootNode && !this.rootNode.total_count)
Expand Down Expand Up @@ -407,9 +404,6 @@
syncInProgress() {
this.syncing = true;
},
noResourcesToSync() {
this.noSyncNeeded = true;
},
deleteChannelModal() {
this.showDeleteModal = true;
this.trackClickEvent('Delete channel');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,105 +1,56 @@
<template>

<div v-if="isSyncing || nothingToSync || isPublishing">
<KModal
v-if="!displayCancelModal"
data-test="progress-modal"
:title="progressModalTitle"
<div class="px-1">
<div v-if="isSyncing && !syncError" class="grey--text" data-test="progress">
<span>{{ $tr('syncHeader') }}</span>&nbsp;<span>{{ progressPercent }}</span>
</div>
<div
v-else-if="syncError"
class="red--text"
>
{{ progressModalDescription }}

<ProgressBar
v-if="!nothingToSync"
data-test="progress-bar"
:progressPercent="progressPercent"
:currentTaskError="currentTaskError"
/>
<div
v-if="currentTaskError"
class="caption mt-2 red--text"
>
<Icon small color="red">
error
</Icon>
{{ $tr('defaultErrorText') }}
</div>

<template slot="actions">
<KButton
v-if="isFinished || currentTaskError"
primary
data-test="refresh-button"
@click="cancelTaskAndClose(currentTask)"
>
{{ $tr('refreshButton') }}
</KButton>
<KButton
v-else
primary
data-test="stop-button"
@click="displayCancelModal = true"
>
{{ $tr('stopButton') }}
</KButton>
</template>
</KModal>

<KModal
v-else
data-test="cancel-modal"
:title="$tr('cancelHeader')"
:submitText="$tr('confirmStopButton')"
:cancelText="$tr('cancel')"
@submit="cancelTaskAndClose(currentTask)"
@cancel="displayCancelModal = false"
<Icon small color="red">
error
</Icon>
{{ $tr('syncError') }}
</div>
<div
v-if="currentPublishTaskError"
class="red--text"
>
{{ $tr('cancelText') }}
</KModal>
<Icon small color="red">
error
</Icon>
{{ $tr('defaultErrorText') }}
</div>
<div v-else-if="isPublishing" class="grey--text" data-test="progress">
<span>{{ $tr('publishHeader') }}</span>&nbsp;<span>{{ progressPercent }}</span>
</div>
<div v-else class="grey--text">
{{ lastPublished ?
$tr('lastPublished', { last_published: $formatRelative(lastPublished, now) }) :
$tr('unpublishedText')
}}
</div>
</div>

</template>

<script>

import { mapActions, mapGetters } from 'vuex';
import { mapGetters } from 'vuex';
import get from 'lodash/get';
import ProgressBar from './ProgressBar';
import { TASK_ID } from 'shared/data/constants';

export default {
name: 'ProgressModal',
components: {
ProgressBar,
},
props: {
syncing: {
type: Boolean,
default: false,
},
noSyncNeeded: {
type: Boolean,
default: false,
},
},
data() {
return {
displayCancelModal: false,
};
},
data: () => ({
now: Date.now(),
}),
computed: {
...mapGetters('task', ['currentTasksForChannel']),
...mapGetters('task', ['getAsyncTask', 'getPublishTaskForChannel']),
...mapGetters('currentChannel', ['currentChannel', 'canManage']),
currentTasks() {
return this.currentTasksForChannel(this.currentChannel.id) || null;
},
isSyncing() {
return this.syncing && this.currentChannel && !this.currentChannel.publishing;
},
// this handles validation errors from the Sync Resources Modal
// where .sync itself errors because of the validation error
// for not syncing channels with no imported resources
// this property is added her as a way to manager feedback to the user
nothingToSync() {
return this.isSyncing && this.noSyncNeeded;
return this.currentTask && this.currentTask.task_type === 'sync-channel';
},
isPublishing() {
// add condition so that publishing modal is only visible for users
Expand All @@ -110,82 +61,56 @@
return false;
},
currentTask() {
if (this.isSyncing) {
return this.currentTasks.find(task => task.task_type === 'sync-channel');
} else if (this.isPublishing) {
return this.currentTasks.find(task => task.task_type === 'export-channel');
} else {
return null;
}
return this.getAsyncTask(this.currentChannel[TASK_ID]) || null;
},
progressPercent() {
if (this.nothingToSync) {
return 100;
}
return get(this.currentTask, ['metadata', 'progress'], 0);
},
isFinished() {
return this.progressPercent >= 100;
const progressPercent = get(this.currentTask, ['metadata', 'progress'], 0);
return this.$formatNumber(Math.round(progressPercent || 0) / 100, {
style: 'percent',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
},
currentTaskError() {
currentPublishTaskError() {
const publishTask = this.getPublishTaskForChannel(this.currentChannel.id);
return Boolean(
get(this.currentTask, ['metadata', 'error'], null) ||
get(this.currentTask, 'status') === 'FAILURE'
(publishTask && get(publishTask, ['metadata', 'error'], null)) ||
get(publishTask, 'status') === 'FAILURE'
);
},
progressModalTitle() {
if (this.isPublishing) {
return this.$tr('publishHeader');
}
if (this.isSyncing || this.nothingToSync) {
return this.$tr('syncHeader');
}
return '';
syncError() {
return (
this.isSyncing &&
(get(this.currentTask, ['metadata', 'error'], null) ||
get(this.currentTask, 'status') === 'FAILURE')
);
},
progressModalDescription() {
if (this.isPublishing) {
return this.$tr('publishDescription');
}
if (this.isFinished && (this.isSyncing || this.nothingToSync)) {
return this.$tr('finishedMessage');
} else if ((this.currentTask && this.isPublishing) || this.currentChannel.publishing) {
return this.$tr('publishDescription');
} else if (this.syncing || (this.currentTask && this.isSyncing)) {
return this.$tr('syncDescription');
lastPublished() {
if (!this.currentChannel.last_published) {
return null;
}
if (this.isSyncing || this.nothingToSync) {
return this.$tr('syncDescription');
const date = new Date(this.currentChannel.last_published);
if (date > this.now) {
return this.now;
}
return '';
return date;
},
},
methods: {
...mapActions('currentChannel', ['stopTask']),
cancelTaskAndClose(task) {
this.stopTask(task).then(() => {
window.location.reload();
});
},
mounted() {
this.timer = setInterval(() => {
this.now = Date.now();
}, 10000);
},
beforeDestroy() {
clearInterval(this.timer);
},
$trs: {
/* eslint-disable kolibri/vue-no-unused-translations */
defaultHeader: 'Updating channel',
defaultDescription: 'Update is in progress, please wait...',
/* eslint-enable */
defaultErrorText:
'An unexpected error has occurred. Please try again, and if you continue to see this message, please contact support via the Help menu.',
finishedMessage: 'Operation complete! Click "Refresh" to update the page.',
defaultErrorText: 'Last publish failed.',
publishHeader: 'Publishing channel',
publishDescription:
'Once publishing is complete, you will receive an email notification and will be able to make further edits to your channel.',
lastPublished: 'Published {last_published}',
unpublishedText: 'Unpublished',
syncHeader: 'Syncing channel',
syncDescription: 'Channel syncing is in progress, please wait...',
stopButton: 'Stop',
refreshButton: 'Refresh',
cancel: 'No, go back',
confirmStopButton: 'Yes, stop task',
cancelHeader: 'Are you sure?',
cancelText: 'Are you sure you would like to cancel this task?',
syncError: 'Last sync failed',
},
};

Expand Down
Loading