[IMP] website_slides: improve website_slides_survey integration

SPECS

1. Change the default content of the modal opened after the installation
of a module

When the installation of a suggested module from the upload dialog is
completed, the page is reloaded and the upload dialog is opened on load.
Since the user installed the module to add content of the category related to
this module, it is more convenient to open the modal directly on this category.

2. Replace the notification displayed when the user creates a new
certification by a permanent button allowing to add questions

When a user creates a certification, he must then add questions to this
certification. Instead of showing a notification after the creation
proposing to add questions that was shown only once, a permanent button
has been added to the view of the certification so that anyone with the
sufficient access rights can add questions, at any time, from the certification
view.

Task-2727654

closes odoo/odoo#86721

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Adrien Schoffeniels
2022-06-01 16:26:02 +02:00
parent 99499a7c40
commit 2e0490beb5
11 changed files with 71 additions and 90 deletions
+7 -4
View File
@@ -544,7 +544,7 @@ class WebsiteSlides(WebsiteProfile):
# display data
'pager': pager,
# display upload modal
'enable_slide_upload': 'enable_slide_upload' in kw,
'enable_slide_upload': kw.get('enable_slide_upload', False),
** errors,
** self._slide_channel_prepare_review_values(channel),
})
@@ -580,7 +580,8 @@ class WebsiteSlides(WebsiteProfile):
render_values['modules_to_install'] = [{
'id': module.id,
'name': module.shortdesc,
'motivational': _('Evaluate and certify your students.'),
'motivational': _('Want to test and certify your students?'),
'default_slide_category': 'certification',
}]
render_values = self._prepare_additional_channel_values(render_values, **kw)
@@ -1246,10 +1247,12 @@ class WebsiteSlides(WebsiteProfile):
channel._resequence_slides(slide, force_category=category)
redirect_url = "/slides/slide/%s" % (slide.id)
if channel.channel_type == "training" and slide.slide_category not in ["article", "quiz"]:
redirect_url = "/slides/%s" % (slug(channel))
if slide.slide_category == 'article':
redirect_url += "?enable_editor=1"
elif slide.slide_category == 'quiz':
redirect_url += "?quiz_quick_create"
elif channel.channel_type == "training":
redirect_url = "/slides/%s" % (slug(channel))
return {
'url': redirect_url,
'channel_type': channel.channel_type,
@@ -34,13 +34,20 @@ var SlideUploadDialog = Dialog.extend({
this._setup();
this.channelID = parseInt(options.channelId, 10);
this.defaultCategoryID = parseInt(options.categoryId,10);
this.defaultCategoryID = parseInt(options.categoryId, 10);
this.canUpload = options.canUpload === 'True';
this.canPublish = options.canPublish === 'True';
this.modulesToInstall = options.modulesToInstall ? JSON.parse(options.modulesToInstall.replace(/'/g, '"')) : null;
this.modulesToInstallStatus = null;
this.set('state', '_select');
if (options.openModal && options.openModal in this.slide_category_data) {
// Sets the appropriate category's upload template if one has to be opened on load.
this.set('state', options.openModal);
this.set('defaultTemplate', this.slide_category_data[options.openModal]['template']);
} else {
this.set('state', '_select');
this.set('defaultTemplate', 'website.slide.upload.modal.select');
}
this.on('change:state', this, this._onChangeType);
this.set('can_submit_form', false);
this.on('change:can_submit_form', this, this._onChangeCanSubmitForm);
@@ -51,6 +58,10 @@ var SlideUploadDialog = Dialog.extend({
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
if (self.get('state') !== '_select') {
self.$modal.find('.modal-dialog').addClass('modal-lg');
}
self._bindSelect2Dropdown();
self._resetModalButton();
});
},
@@ -668,7 +679,12 @@ var SlideUploadDialog = Dialog.extend({
method: 'button_immediate_install',
args: [[this.modulesToInstallStatus.id]],
}).then(function () {
window.location.href = window.location.origin + window.location.pathname + '?enable_slide_upload';
let redirectUrl = window.location.origin + window.location.pathname + '?enable_slide_upload';
if (self.modulesToInstallStatus.default_slide_category) {
redirectUrl += '=';
redirectUrl += self.modulesToInstallStatus.default_slide_category;
}
window.location.href = redirectUrl;
}, function () {
$el.text(_.str.sprintf(_t('Failed to install "%s".'), self.modulesToInstallStatus.name));
self.modulesToInstallStatus.installing = false;
@@ -733,13 +749,16 @@ publicWidget.registry.websiteSlidesUpload = publicWidget.Widget.extend({
},
/**
* Automatically opens the upload dialog if requested from query string.
* If openModal is defined ( === '' ), opens the category selection dialog.
* If openModal is a category name, opens the category's upload dialog.
*
* @override
*/
start: function () {
// Automatically open the upload dialog if requested from query string
if (this.$el.attr('data-open-modal')) {
this.$el.removeAttr('data-open-modal');
if ('openModal' in this.$el.data()) {
this._openDialog(this.$el);
this.$el.data('openModal', false);
}
return this._super.apply(this, arguments);
},
@@ -749,8 +768,7 @@ publicWidget.registry.websiteSlidesUpload = publicWidget.Widget.extend({
//--------------------------------------------------------------------------
_openDialog: function ($element) {
var data = $element.data();
return new SlideUploadDialog(this, data).open();
return new SlideUploadDialog(this, $element.data()).open();
},
//--------------------------------------------------------------------------
@@ -4,7 +4,7 @@
<t t-name="website.slide.upload.modal">
<div>
<div class="o_w_slide_upload_modal_container">
<t t-call="website.slide.upload.modal.select"/>
<t t-call="{{widget.get('defaultTemplate')}}"/>
</div>
</div>
</t>
@@ -29,7 +29,7 @@
<a class="o_wslides_js_upload_install_button w-100 text-center mb-4 btn rounded border text-600 p-3"
href="#" t-att-title="module_info['name']"
t-att-data-module-id="module_info['id']">
<i class="fa fa-trophy"></i> <t t-esc="module_info['motivational']"/>
<i class="fa fa-trophy"></i> <t t-out="module_info['motivational']"/><span class="text-primary"> Install the <t t-out="module_info['name']"/> app.</span>
</a>
</t>
</t>
@@ -37,7 +37,6 @@
'website_slides_survey/static/src/scss/website_slides_survey.scss',
'website_slides_survey/static/src/js/slides_upload.js',
'website_slides_survey/static/src/js/slides_course_fullscreen_player.js',
'website_slides_survey/static/src/js/slides_certification_upload_toast.js',
],
'survey.survey_assets': [
'website_slides_survey/static/src/scss/website_slides_survey_result.scss',
@@ -7,6 +7,7 @@ import werkzeug.exceptions
from odoo import _
from odoo import http
from odoo.addons.http_routing.models.ir_http import slug
from odoo.exceptions import AccessError
from odoo.http import request
from odoo.osv import expression
@@ -74,13 +75,9 @@ class WebsiteSlidesSurvey(WebsiteSlides):
# Then create the slide
result = super(WebsiteSlidesSurvey, self).create_slide(*args, **post)
if create_new_survey:
# Set the redirect_url used in toaster
action_id = request.env.ref('survey.action_survey_form').id
result.update({
'redirect_url': '/web#id=%s&action=%s&model=survey.survey&view_type=form' % (post['survey_id'], action_id),
'redirect_to_certification': True
})
if post['slide_category'] == "certification":
# Set the url to redirect the user to the survey
result['url'] = '/slides/slide/%s?fullscreen=1' % (slug(request.env['slide.slide'].browse(result['slide_id']))),
return result
@@ -1,39 +0,0 @@
odoo.define('website_slides_survey.certification_upload_toast', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
var {Markup, sprintf} = require('web.utils');
var sessionStorage = window.sessionStorage;
var core = require('web.core');
var _t = core._t;
publicWidget.registry.CertificationUploadToast = publicWidget.Widget.extend({
selector: '.o_wslides_survey_certification_upload_toast',
/**
* @override
*/
start: function () {
var self = this;
this._super.apply(this, arguments).then(function () {
var url = sessionStorage.getItem("survey_certification_url");
if (url) {
var message = sprintf(Markup(
_t('Follow this link to add questions to your certification. <a href="%s">Edit certification</a>')), url);
self.displayNotification({
type: 'info',
title: _t('Certification created'),
message: message,
sticky: true,
});
sessionStorage.removeItem("survey_certification_url");
}
});
},
});
return publicWidget.registry.CertificationUploadToast;
});
@@ -3,7 +3,6 @@ odoo.define('website_slides_survey.upload_modal', function (require) {
var core = require('web.core');
var _t = core._t;
var sessionStorage = window.sessionStorage;
var SlidesUpload = require('@website_slides/js/slides_upload')[Symbol.for("default")];
/**
@@ -23,8 +22,12 @@ SlidesUpload.SlideUploadDialog.include({
*/
_onChangeCertification: function (ev) {
const $inputElement = this.$("input#name");
if (ev.added && ev.added.text && !$inputElement.val().trim()) {
$inputElement.val(ev.added.text);
if (ev.added) {
this.$('.o_error_no_certification').addClass('d-none');
this.$('#certification_id').closest('.form-group').find('.select2-container').removeClass('is-invalid');
if (ev.added.text && !$inputElement.val().trim()) {
$inputElement.val(ev.added.text);
}
}
},
@@ -83,11 +86,14 @@ SlidesUpload.SlideUploadDialog.include({
var $select2Container = $certificationInput
.closest('.form-group')
.find('.select2-container');
var $errorContainer = $('.o_error_no_certification');
$select2Container.removeClass('is-invalid is-valid');
if ($certificationInput.is(':invalid')) {
$select2Container.addClass('is-invalid');
$errorContainer.removeClass('d-none');
} else if ($certificationInput.is(':valid')) {
$select2Container.addClass('is-valid');
$errorContainer.addClass('d-none');
}
}
@@ -115,22 +121,6 @@ SlidesUpload.SlideUploadDialog.include({
result['survey'] = survey;
return result;
},
/**
* Overridde to handle certification created on-the-fly: toaster will hold
* survey edit url, need to put it in session to use it in CertificationUploadToast
*
* @override
* @private
*/
_onFormSubmitDone: function (data) {
if (!data.error && data.redirect_to_certification) {
sessionStorage.setItem("survey_certification_url", data.redirect_url);
window.location.reload();
} else {
this._super.apply(this, arguments);
}
},
});
SlidesUpload.websiteSlidesUpload.include({
@@ -8,6 +8,7 @@
<div class="form-group">
<label for="certification_id" class="col-form-label">Certification</label>
<input class="form-control" id="certification_id" required="required"/>
<span class="o_error_no_certification text-danger d-none">Please select a certification.</span>
</div>
<t t-call="website.slide.upload.modal.common"/>
<canvas id="data_canvas" class="d-none"></canvas>
@@ -17,7 +18,7 @@
<div class="img-thumbnail h-100">
<div class="o_slide_tutorial p-3">
<div class="h5">How to upload a certification on your course?</div>
<div class="mx-3 my-4">You can create your certification from here or use an existing one. Once your certification is created, you can still edit it in backend.</div>
<div class="my-4">You can create your certification from here or use an existing one. Once your certification is created, you can still edit it in backend.</div>
</div>
</div>
</div>
@@ -2,20 +2,25 @@
<templates>
<t t-name="website.slides.fullscreen.certification">
<div class="justify-content-center align-self-center">
<div class="justify-content-center align-self-center text-center">
<div t-if="widget.get('slide').category === 'certification' &amp;&amp; !widget.get('slide').completed" class="">
<a class="btn btn-primary" t-att-href="'/slides_survey/slide/get_certification_url?slide_id=' + widget.get('slide').id" target="_blank">
<i class="fa fa-trophy"/>
<span t-if="widget.get('slide').isMember"> Start Certification</span>
<i class="fa fa-graduation-cap"/>
<span t-if="widget.get('slide').isMember"> Begin Certification</span>
<span t-else="">Test Certification</span>
</a>
</div>
<div class="text-center" t-if="widget.get('slide').category === 'certification' &amp;&amp; widget.get('slide').completed">
<div t-if="widget.get('slide').category === 'certification' &amp;&amp; widget.get('slide').completed">
<h4 class="mb-3 text-white">Congratulations, you passed the Certification!</h4>
<a role="button" class="btn btn-primary" t-att-href="'/survey/' + widget.get('slide').certificationId + '/get_certification'">
<i class="fa fa-fw fa-trophy" role="img" aria-label="Download certification" title="Download certification"/> Download certification
</a>
</div>
<div t-if="widget.get('slide').category === 'certification' &amp;&amp; widget.get('slide').canUpload" class="mt-3 h6">
<a t-att-href="'/web#id=' + widget.get('slide').certificationId + '&amp;model=survey.survey&amp;view_type=form'">
<i class="fa fa-arrow-right mr-1"/>Add Questions to this Survey
</a>
</div>
</div>
</t>
@@ -3,22 +3,28 @@
<data>
<template id="slide_content_detailed" inherit_id="website_slides.slide_content_detailed">
<xpath expr="//div[hasclass('o_wslides_lesson_content_type')]" position="inside">
<div t-if="slide.slide_category == 'certification' and not channel_progress[slide.id].get('completed')" class="col mt32 mb8 d-flex justify-content-center">
<div t-if="slide.slide_category == 'certification' and not channel_progress[slide.id].get('completed')" class="col mt32 mb8 text-center">
<a role="button"
class="btn btn-primary btn-lg"
id="start_certification"
t-att-href="'/slides_survey/slide/get_certification_url?slide_id=%s' %(slide.id)">
<i class="fa fa-trophy" role="img"/>
<t t-if="slide.channel_id.is_member and slide.channel_id.active">Start Certification</t>
t-att-href="'/slides_survey/slide/get_certification_url?slide_id=%s' %(slide.id)"
target="_blank">
<i class="fa fa-fw fa-graduation-cap" role="img"/>
<t t-if="slide.channel_id.is_member and slide.channel_id.active">Begin Certification</t>
<t t-else="">Test Certification</t>
</a>
</div>
<div t-if="slide.slide_category == 'certification' and channel_progress[slide.id].get('completed')" class="col mt32 mb8 text-center">
<h4 class="mb-3">Congratulations, you passed the Certification!</h4>
<a role="button" class="btn btn-primary btn-lg mb-3" t-att-href="'/survey/%s/get_certification' % slide.survey_id.id">
<a role="button" class="btn btn-primary btn-lg" t-att-href="'/survey/%s/get_certification' % slide.survey_id.id">
<i class="fa fa-fw fa-trophy" role="img" aria-label="Download certification" title="Download certification"/> Download certification
</a>
</div>
<div t-if="slide.slide_category == 'certification' and slide.channel_id.can_upload" class="col mb8 d-flex justify-content-center">
<a class="my-4" t-att-href="'/web#id=' + str(slide.survey_id.id) + '&amp;model=survey.survey&amp;view_type=form'">
<i class="fa fa-arrow-right mr-1"/>Add Questions to this Survey
</a>
</div>
</xpath>
<xpath expr="//a[hasclass('o_wslides_done_button')][1]" position="after">
<a t-elif="not slide_completed and slide.slide_category == 'certification'"
@@ -5,6 +5,7 @@
<xpath expr="//li[@t-att-data-id='slide.id']" position="attributes">
<attribute name="t-att-data-certification-id">slide.survey_id.id</attribute>
<attribute name="t-att-data-is-member">slide.channel_id.is_member</attribute>
<attribute name="t-att-data-can-upload">channel.can_upload</attribute>
</xpath>
</template>