/** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; under version 2 * of the License (non-upgradable). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2015-2021 (original work) Open Assessment Technologies SA ; */ define([ 'jquery', 'lodash', 'i18n', 'helpers', 'moment', 'core/request', 'layout/loading-bar', 'util/encode', 'ui/feedback', 'ui/dialog', 'taoClientDiagnostic/tools/getStatus', 'taoClientDiagnostic/tools/performances/tester', 'taoClientDiagnostic/tools/fingerprint/tester', 'tpl!taoClientDiagnostic/tools/diagnostic/tpl/fingerprint', 'tpl!taoClientDiagnostic/tools/diagnostic/tpl/details', 'taoClientDiagnostic/tools/csvExporter', 'ui/datatable', 'lib/moment-timezone.min' ], function( $, _, __, helpers, moment, request, loadingBar, encode, feedback, dialog, getStatus, performancesTesterFactory, fingerprintTesterFactory, fingerprintTpl, detailsTpl, csvExporter ) { 'use strict'; /** * The CSS scope * @type {string} * @private */ const cssScope = '.diagnostic-index'; /** * Default Time Zone for date * @type {string} * @private */ const defaultDateTimeZone = 'UTC'; /** * Default date format * @type {string} * @private */ const defaultDateFormat = 'Y/MM/DD HH:mm:ss'; /** * Format a number with decimals * @param {number} value - The number to format * @param {number|string} [digits] - The number of decimals * @returns {number} * @private */ function formatNumber(value, digits) { const nb = 'undefined' === typeof digits ? 2 : Math.max(0, parseInt(digits, 10)); const factor = Math.pow(10, nb) || 1; return Math.round(value * factor) / factor; } /** * Format a bandwidth value * @param {number} value * @returns {number|string} * @private */ function formatBandwidth(value) { if (value > 100) { return '> 100'; } return formatNumber(value); } /** * Transform date to local timezone * @param {string} date * @returns {string} * @private */ function transformDateToLocal(date) { let time; if (_.isFinite(date)) { if (!_.isNumber(date)) { date = _.parseInt(date, 10); } const d = new Date(date * 1000); time = moment.utc(d); } else { time = moment.tz(date, defaultDateTimeZone); } return time.tz(moment.tz.guess()).format(defaultDateFormat); } // the page is always loading data when starting loadingBar.start(); /** * Controls the readiness check page */ return { /** * Entry point of the page */ start() { const $container = $(cssScope); const extension = $container.data('extension') || 'taoClientDiagnostic'; const $list = $container.find('.list'); let dataset = $container.data('set'); const extensionConfig = $container.data('config') || {}; const config = extensionConfig.diagnostic || extensionConfig; const installedExtension = $container.data('installedextension') || false; const diagnosticUrl = helpers._url('diagnostic', 'Diagnostic', extension); const removeUrl = helpers._url('remove', 'Diagnostic', extension); const serviceUrl = helpers._url('diagnosticData', 'Diagnostic', extension); const performancesTester = performancesTesterFactory(config.testers.performance || {}); const fingerprintTester = fingerprintTesterFactory(config.testers.fingerprint || {}); const tools = []; const actions = []; const model = []; // request the server with a selection of readiness check results function requestData(url, selection, message) { if (selection && selection.length) { loadingBar.start(); request({ url, data: { id: selection }, method: 'POST', noToken: true }) .then(response => { loadingBar.stop(); if (response && response.success) { if (message) { feedback().success(message); } $list.datatable('refresh'); } else { feedback().error( `${__('Something went wrong ...')}
${encode.html(response.error)}`, { encodeHtml: false } ); } }) .catch(() => loadingBar.stop()); } } // request the server to remove the selected diagnostic-index function remove(selection) { requestData(removeUrl, selection, __('The readiness check result have been removed')); } // tool: page refresh tools.push({ id: 'refresh', icon: 'reset', title: __('Refresh the page'), label: __('Refresh'), action() { $list.datatable('refresh'); } }); // tool: readiness check tools.push({ id: 'launch', icon: 'play', title: __('Launch another readiness check'), label: __('Launch readiness check'), action() { window.location.href = diagnosticUrl; } }); if (config.export) { // tool: export csv tools.push({ id: 'csvExport', icon: 'export', title: __('Export CSV'), label: __('Export CSV'), action() { csvExporter.exportCsv(model); } }); } if (installedExtension) { // tool: compatibility via lti tools.push({ id: 'lti', icon: 'play', title: __('Try a test delivery'), label: __('Try a test delivery'), action() { window.location.href = deliveryUrl; } }); } // tool: remove selected results tools.push({ id: 'remove', icon: 'remove', title: __('Remove the selected readiness check results'), label: __('Remove'), massAction: true, action(selection) { dialog({ message: __('The selected readiness check results will be removed. Continue ?'), autoRender: true, autoDestroy: true, onOkBtn() { remove(selection); } }); } }); // tool: close tab, this won't be present in an LTI iframe // button should always be right most if (window.self === window.top) { tools.push({ id: 'exitButton', icon: 'close', title: __('Exit'), label: __('Exit'), action() { window.self.close(); } }); } // action: remove the result actions.push({ id: 'remove', icon: 'remove', title: __('Remove the readiness check result?'), action(id) { dialog({ autoRender: true, autoDestroy: true, message: __('The readiness check result will be removed. Continue ?'), onOkBtn() { remove([id]); } }); } }); // column: Workstation identifier model.push({ id: 'workstation', label: __('Workstation') }); // column: School name if (config.requireSchoolName) { model.push({ id: 'school_name', label: __('School name') }); } // column: School id if (config.requireSchoolId) { model.push({ id: 'school_id', label: __('School id') }); } // column: School number if (config.validateSchoolName) { model.push({ id: 'school_number', label: __('School number') }); } // results of fingerprinting if (config.testers.fingerprint && config.testers.fingerprint.enabled) { // column: Fingerprint of the workstation model.push({ id: 'fingerprint-cell', label: __('Fingerprint'), transform(v, row) { return fingerprintTpl(row.fingerprint); } }); $list.on('click.fingerprint', '.fingerprint-cell span.details', function(e) { const id = $(e.target) .closest('tr') .data('itemIdentifier'); const row = _.find(dataset.data, { id: id }); if (row) { dialog({ content: detailsTpl(fingerprintTester.getSummary(row.fingerprint)), buttons: 'ok', autoRender: true, autoDestroy: true }); } }); } // results of screen test if (config.testers.screen && config.testers.screen.enabled) { // column: Screen Width and Height model.push({ id: 'screen_size', label: __('Screen resolution'), transform(value, row) { if (row.screen && row.screen.width && row.screen.height) { return row.screen.width + 'x' + row.screen.height; } } }); } // results of browser test if (config.testers.browser && config.testers.browser.enabled) { // column: Operating system information model.push({ id: 'os', label: __('OS') }); // column: Browser information model.push({ id: 'browser', label: __('Browser') }); } // results of performances test if (config.testers.performance && config.testers.performance.enabled) { // column: Performances of the workstation model.push({ id: 'performance', label: __('Performances'), transform(value) { const status = performancesTester.getFeedback(value); return status.feedback && status.feedback.message; } }); } // results of bandwidth test if (config.testers.bandwidth && config.testers.bandwidth.enabled) { // column: Available bandwidth model.push({ id: 'bandwidth', label: __('Bandwidth'), transform: formatBandwidth }); } // results of intensive bandwidth test if (config.testers.intensive_bandwidth && config.testers.intensive_bandwidth.enabled) { // column: Available bandwidth model.push({ id: 'intensive_bandwidth', label: __('Intensive bandwidth'), transform: formatBandwidth }); } // results of upload speed test if (config.testers.upload && config.testers.upload.enabled) { // column: Available upload speed model.push({ id: 'upload', label: __('Upload speed'), transform: formatBandwidth }); } // column: Date of diagnostic model.push({ id: 'date', label: __('Date'), transform: transformDateToLocal }); $list .on('query.datatable', () => loadingBar.start()) .on('load.datatable', (e, data) => { dataset = data; loadingBar.stop(); }) .datatable( { url: serviceUrl, status: { empty: __('No readiness checks have been done!'), available: __('Readiness checks already done'), loading: __('Loading') }, selectable: true, tools, actions, model }, dataset ); } }; });