From 59093263b16704f41f12a44c5e087a723f06151b Mon Sep 17 00:00:00 2001 From: LAUNAY Samuel <107540223+Lainow@users.noreply.github.com> Date: Thu, 29 Feb 2024 10:55:08 +0100 Subject: [PATCH] feat(Timeslot): implement Timeslot --- .eslintrc.js | 27 +++ .github/workflows/continuous-integration.yml | 3 +- .gitignore | 2 +- .npmrc | 1 + .stylelintrc.js | 27 +++ ajax/timeslot.php | 55 +++++ front/package.form.php | 2 +- front/timeslot.form.php | 40 ++++ front/timeslot.php | 41 ++++ front/timeslotrange.form.php | 59 +++++ hook.php | 14 ++ javascript/timeslot.js | 172 +++++++++++++++ package-lock.json | 20 ++ package.json | 12 ++ setup.php | 16 +- src/Computer/Group.php | 41 ++++ src/PackageTarget.php | 3 +- src/Timeslot.php | 92 ++++++++ src/TimeslotRange.php | 203 ++++++++++++++++++ .../package/subitemtarget.list.html.twig | 6 + templates/package/target.list.html.twig | 58 +++-- templates/package/task.list.html.twig | 1 - templates/package/timeslot.html.twig | 43 ++++ templates/timeslot/timeslotrange.html.twig | 108 ++++++++++ 24 files changed, 1016 insertions(+), 30 deletions(-) create mode 100644 .npmrc create mode 100644 ajax/timeslot.php create mode 100644 front/timeslot.form.php create mode 100644 front/timeslot.php create mode 100644 front/timeslotrange.form.php create mode 100644 javascript/timeslot.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/Timeslot.php create mode 100644 src/TimeslotRange.php create mode 100644 templates/package/timeslot.html.twig create mode 100644 templates/timeslot/timeslotrange.html.twig diff --git a/.eslintrc.js b/.eslintrc.js index 695779d..cf34169 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,30 @@ +/** + * ------------------------------------------------------------------------- + * Deploy plugin for GLPI + * ------------------------------------------------------------------------- + * + * LICENSE + * + * This file is part of Deploy. + * + * Deploy 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; either version 3 of the License, or + * (at your option) any later version. + * + * Deploy 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 Deploy. If not, see . + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ module.exports = { "root": true, diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f21cdb7..9254f2e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -14,13 +14,12 @@ on: concurrency: group: "${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: true - jobs: generate-ci-matrix: name: "Generate CI matrix" uses: "glpi-project/plugin-ci-workflows/.github/workflows/generate-ci-matrix.yml@v1" with: - glpi-version: "10.1.x" + glpi-version: "11.0.x" ci: name: "GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}" needs: "generate-ci-matrix" diff --git a/.gitignore b/.gitignore index f6254b8..02bf194 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ vendor/ .gh_token composer.lock *.min.* - +lib/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/.stylelintrc.js b/.stylelintrc.js index 1116459..4573782 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -1,3 +1,30 @@ +/** + * ------------------------------------------------------------------------- + * Deploy plugin for GLPI + * ------------------------------------------------------------------------- + * + * LICENSE + * + * This file is part of Deploy. + * + * Deploy 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; either version 3 of the License, or + * (at your option) any later version. + * + * Deploy 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 Deploy. If not, see . + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ module.exports = { "extends": "stylelint-config-standard", diff --git a/ajax/timeslot.php b/ajax/timeslot.php new file mode 100644 index 0000000..80a52d8 --- /dev/null +++ b/ajax/timeslot.php @@ -0,0 +1,55 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use Glpi\Application\View\TemplateRenderer; + +include("../../../inc/includes.php"); + +\Session::checkLoginUser(); +$trange = new TimeslotRange(); +$id = $_POST['plugin_deploy_timeslots_id']; +TimeslotRange::cleanOldData($_POST); +$_POST = TimeslotRange::cleanInput($_POST); +foreach ($_POST as $timeslot) { + foreach ($timeslot as $range) { + if ((bool)$range['is_enable'] == true) { + $trange->add($range); + } + } +} +$timeslots_data = TimeslotRange::getForTimeslot(Timeslot::getById($id)); +echo TemplateRenderer::getInstance()->render('@deploy/timeslot/timeslotrange.html.twig', [ + 'rand' => mt_rand(), + 'timeslot_id' => $id, + 'days_list' => TimeslotRange ::getDayList(), + 'timeslots_data' => $timeslots_data +]); diff --git a/front/package.form.php b/front/package.form.php index 3aab27d..358977d 100644 --- a/front/package.form.php +++ b/front/package.form.php @@ -112,7 +112,7 @@ $action->delete($_POST); Html::back(); } else if (isset($_POST["add_target"])) { - if ($_POST['plugin_deploy_computers_groups_id'] > 0) { + if ($_POST['plugin_deploy_computers_groups_id'] > 0 && $_POST['plugin_deploy_timeslots_id'] > 0) { $package_target = new PackageTarget(); $package_target->add($_POST); } diff --git a/front/timeslot.form.php b/front/timeslot.form.php new file mode 100644 index 0000000..d04f1f9 --- /dev/null +++ b/front/timeslot.form.php @@ -0,0 +1,40 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use Html; +use Session; + +include('../../../inc/includes.php'); + +Session::checkRight("entity", UPDATE); +$dropdown = new Timeslot(); +include(GLPI_ROOT . "/front/dropdown.common.form.php"); diff --git a/front/timeslot.php b/front/timeslot.php new file mode 100644 index 0000000..2d49c65 --- /dev/null +++ b/front/timeslot.php @@ -0,0 +1,41 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use Html; +use Search; +use Session; + +include('../../../inc/includes.php'); + +Session::checkRight("entity", UPDATE); +$dropdown = new Timeslot(); +include(GLPI_ROOT . "/front/dropdown.common.php"); diff --git a/front/timeslotrange.form.php b/front/timeslotrange.form.php new file mode 100644 index 0000000..a2d57fb --- /dev/null +++ b/front/timeslotrange.form.php @@ -0,0 +1,59 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use Html; +use Session; + +include('../../../inc/includes.php'); + +Session::checkRight("entity", UPDATE); + +if (!isset($_GET["id"])) { + $_GET["id"] = ""; +} + +$trange = new TimeslotRange(); + +if (isset($_POST['timeslot']) && !empty($_POST['timeslot'])) { + $_POST['timeslot'] = json_decode($_POST['timeslot'], true); + TimeslotRange::cleanOldData($_POST); + $_POST = TimeslotRange::cleanInput($_POST); + foreach ($_POST as $timeslot) { + foreach ($timeslot as $range) { + if ($range['is_enable'] == true) { + $trange->add($range); + } + } + } + Session::addMessageAfterRedirect(__('Range options saved', 'deploy'), true, INFO); +} +Html::back(); diff --git a/hook.php b/hook.php index a472ddc..97ca5f4 100644 --- a/hook.php +++ b/hook.php @@ -38,7 +38,10 @@ use GlpiPlugin\Deploy\PackageFile; use GlpiPlugin\Deploy\PackageTarget; use GlpiPlugin\Deploy\Profile; +use GlpiPlugin\Deploy\PackageTimeslot; use GlpiPlugin\Deploy\Repository; +use GlpiPlugin\Deploy\Timeslot; +use GlpiPlugin\Deploy\TimeslotRange; /** * ------------------------------------------------------------------------- @@ -68,6 +71,13 @@ * ------------------------------------------------------------------------- */ + // Define Dropdown tables to be manage in GLPI : +function plugin_deploy_getDropdown() +{ + $dropdowns = [Timeslot::class => Timeslot::getTypeName(2)]; + return $dropdowns; +} + function plugin_deploy_install() { $version = plugin_version_deploy(); @@ -84,6 +94,8 @@ function plugin_deploy_install() Group::install($migration); GroupDynamic::install($migration); GroupStatic::install($migration); + Timeslot::install($migration); + TimeslotRange::install($migration); return true; } @@ -106,6 +118,8 @@ function plugin_deploy_uninstall() Group::uninstall($migration); GroupDynamic::uninstall($migration); GroupStatic::uninstall($migration); + Timeslot::uninstall($migration); + TimeslotRange::uninstall($migration); return true; } diff --git a/javascript/timeslot.js b/javascript/timeslot.js new file mode 100644 index 0000000..32bc747 --- /dev/null +++ b/javascript/timeslot.js @@ -0,0 +1,172 @@ +/** + * ------------------------------------------------------------------------- + * Deploy plugin for GLPI + * ------------------------------------------------------------------------- + * + * LICENSE + * + * This file is part of Deploy. + * + * Deploy 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; either version 3 of the License, or + * (at your option) any later version. + * + * Deploy 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 Deploy. If not, see . + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +var AJAX_URL = CFG_GLPI.root_doc + '/' + GLPI_PLUGINS_PATH.deploy + '/ajax/timeslot.php'; + +var timeslot = {}; +var timeslotsData = JSON.parse(document.getElementById('timeslotsData').dataset.value); + +var everydayButton = document.getElementById('everyday'); +var daysLength = parseInt(document.getElementById('daysLength').dataset.value); +var timeslot_id = parseInt(document.getElementById('timeslotId').dataset.value); + +function setSliderValues(slider, values) { + slider.noUiSlider.set(values); +} + +function toggleSlider(slider, checkbox, addRangeButton, delRangeButton, i) { + if (checkbox.checked) { + addRangeButton.removeAttribute('disabled'); + delRangeButton.removeAttribute('disabled'); + setSliderValues(slider, timeslotsData[i] ? timeslotsData[i].map(slot => [slot.starttime, slot.endtime]).flat() : [8, 12, 14, 18]); + slider.style.display = 'block'; + } else { + addRangeButton.setAttribute('disabled', true); + delRangeButton.setAttribute('disabled', true); + slider.style.display = 'none'; + } + timeslot[i]['is_enable'] = +checkbox.checked; + document.getElementById('timeslot').value = JSON.stringify(timeslot); +} + +function sendAjaxRequest(action, timeslot, timeslot_id) { + $.ajax({ + method: 'POST', + url: AJAX_URL, + data: { + action: action, + timeslot: timeslot, + plugin_deploy_timeslots_id: timeslot_id + } + }).done(function(response) { + $('#tr_countainer').html(response); + }); +} + +for (let i = 1; i <= daysLength; i++) { + const slider = document.getElementById('slider' + i); + const checkbox = document.getElementById('notimeslot' + i); + const alldayButton = document.getElementById('allday' + i); + const addRangeButton = document.getElementById('addrange' + i); + const delRangeButton = document.getElementById('delrange' + i); + + timeslot[i] = { + is_enable: +checkbox.checked + }; + + noUiSlider.create(slider, { + start: timeslotsData[i] ? timeslotsData[i].map(slot => [slot.starttime, slot.endtime]).flat() : [0, 0, 0, 0], + connect: [false, ...Array(timeslotsData[i].length * 2).fill().flatMap((_, idx) => idx % 2 === 0 ? [true, false] : [])], + behaviour: 'drag', + step: 1, + range: { + 'min': 0, + 'max': 24 + }, + margin: 1, + }); + + slider.noUiSlider.on('update', function(values, handle) { + timeslot[i]['is_enable'] = +checkbox.checked; + const order = Math.floor(handle / 2); + const start = document.getElementById('value' + order + '_start' + i); + const end = document.getElementById('value' + order + '_end' + i); + if (handle % 2 === 1) { + end.value = values[handle]; + } else { + start.value = values[handle]; + } + timeslot[i][order] = { + starttime: start.value, + endtime: end.value + }; + document.getElementById('timeslot').value = JSON.stringify(timeslot); + }); + + // Disable slider if checkbox is not checked + toggleSlider(slider, checkbox, addRangeButton, delRangeButton, i); + + // Enable or disable slider on checkbox change + checkbox.addEventListener('change', function() { + toggleSlider(slider, this, addRangeButton, delRangeButton, i); + }); + + alldayButton.addEventListener('click', function(event) { + timeslot[i] = { + 0: { + starttime: '0.00', + endtime: '24.00' + }, + is_enable: 1 + }; + document.getElementById('timeslot').value = JSON.stringify(timeslot); + sendAjaxRequest('add', timeslot, timeslot_id); + }); + + // Disable add button if there are already 12 ranges + if (Object.keys(timeslot[i]).length - 1 >= 12) { + addRangeButton.setAttribute('disabled', true); + } + + addRangeButton.addEventListener('click', function(event) { + const lastKey = Object.keys(timeslot[i]).length - 1; + timeslot[i][lastKey + 1] = { + starttime: '23.00', + endtime: '24.00' + }; + document.getElementById('timeslot').value = JSON.stringify(timeslot); + sendAjaxRequest('add', timeslot, timeslot_id); + }); + + // Disable delete button if there is only 1 range + if (Object.keys(timeslot[i]).length - 1 === 1) { + delRangeButton.setAttribute('disabled', true); + } + + delRangeButton.addEventListener('click', function(event) { + const lastKey = Object.keys(timeslot[i]).length - 1; + delete timeslot[i][lastKey - 1]; + document.getElementById('timeslot').value = JSON.stringify(timeslot); + sendAjaxRequest('add', timeslot, timeslot_id); + }); + +} + +everydayButton.addEventListener('click', function(event) { + for (let i = 1; i <= daysLength; i++) { + timeslot[i] = { + 0: { + starttime: '0.00', + endtime: '24.00' + }, + is_enable: 1 + }; + document.getElementById('timeslot').value = JSON.stringify(timeslot); + document.getElementById("rangeform").submit(); + } +}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..701e652 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,20 @@ +{ + "name": "@glpi-plugins/deploy", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@glpi-plugins/deploy", + "hasInstallScript": true, + "license": "GPL-3.0", + "dependencies": { + "nouislider": "^15.7.1" + } + }, + "node_modules/nouislider": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.7.1.tgz", + "integrity": "sha512-5N7C1ru/i8y3dg9+Z6ilj6+m1EfabvOoaRa7ztpxBSKKRZso4vA52DGSbBJjw5XLtFr/LZ9SgGAXqyVtlVHO5w==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0605f51 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "@glpi-plugins/deploy", + "description": "GLPI Deploy plugin", + "private": true, + "license": "GPL-3.0", + "dependencies": { + "nouislider": "^15.7.1" + }, + "scripts": { + "postinstall": "mv node_modules lib" + } + } diff --git a/setup.php b/setup.php index ea0f365..72445e0 100644 --- a/setup.php +++ b/setup.php @@ -28,12 +28,14 @@ * ------------------------------------------------------------------------- */ +use Glpi\Plugin\Hooks; + define('PLUGIN_DEPLOY_VERSION', '0.0.5'); define('PLUGIN_DEPLOY_REPOSITORY_PATH', GLPI_PLUGIN_DOC_DIR . "/deploy/repository"); define('PLUGIN_DEPLOY_MANIFESTS_PATH', PLUGIN_DEPLOY_REPOSITORY_PATH . "/manifests"); define('PLUGIN_DEPLOY_PARTS_PATH', PLUGIN_DEPLOY_REPOSITORY_PATH . "/parts"); -define("PLUGIN_DEPLOY_MIN_GLPI", "10.1.0"); -define("PLUGIN_DEPLOY_MAX_GLPI", "10.1.99"); +define("PLUGIN_DEPLOY_MIN_GLPI", "11.0.0"); +define("PLUGIN_DEPLOY_MAX_GLPI", "11.0.99"); /** * Init hooks of the plugin. @@ -63,6 +65,9 @@ function plugin_init_deploy() ]; $PLUGIN_HOOKS['config_page']['deploy'] = 'front/package.php'; + $PLUGIN_HOOKS[Hooks::ADD_CSS]['deploy'][] = 'lib/nouislider/dist/nouislider.css'; + $PLUGIN_HOOKS[Hooks::ADD_JAVASCRIPT]['deploy'][] = 'lib/nouislider/dist/nouislider.min.js'; + Plugin::registerClass('GlpiPlugin\Deploy\Profile', ['addtabon' => ['Profile']]); } @@ -98,8 +103,13 @@ function plugin_version_deploy() */ function plugin_deploy_check_prerequisites() { + $prerequisitesSuccess = true; + if (!is_dir(__DIR__ . '/lib/') || !is_readable(__DIR__ . '/lib/.package-lock.json')) { + echo "Run `npm install` in the plugin directory
"; + $prerequisitesSuccess = false; + } - return true; + return $prerequisitesSuccess; } /** diff --git a/src/Computer/Group.php b/src/Computer/Group.php index 656bd6a..b04172c 100644 --- a/src/Computer/Group.php +++ b/src/Computer/Group.php @@ -34,6 +34,8 @@ use Computer; use DisplayPreference; use Glpi\Application\View\TemplateRenderer; +use GlpiPlugin\Deploy\PackageTarget; +use GlpiPlugin\Deploy\Timeslot; use Migration; use Search; use Session; @@ -148,6 +150,24 @@ public function rawSearchOptions() ] ]; + $tab[] = [ + 'id' => '9', + 'table' => Timeslot::getTable(), + 'field' => 'name', + 'datatype' => 'itemlink', + 'name' => __('Timeslot', 'deploy'), + 'forcegroupby' => true, + 'massiveaction' => false, + 'joinparams' => [ + 'beforejoin' => [ + 'table' => PackageTarget::getTable(), + 'joinparams' => [ + 'jointype' => 'child', + ] + ] + ] + ]; + return $tab; } @@ -202,6 +222,27 @@ public function countStaticItem() return $count; } + public function getTimeslotLink() + { + /** @var object $DB */ + global $DB; + + $params = [ + 'SELECT' => 'plugin_deploy_timeslots_id', + 'FROM' => PackageTarget::getTable(), + 'WHERE' => ['plugin_deploy_computers_groups_id' => $this->fields['id']], + ]; + $iterator = $DB->request($params); + $plugin_deploy_timeslots_id = 0; + foreach ($iterator as $data) { + $plugin_deploy_timeslots_id = $data['plugin_deploy_timeslots_id']; + } + + $timeslot = new Timeslot(); + $timeslot->getFromDB($plugin_deploy_timeslots_id); + return $timeslot->getLink(); + } + public static function install(Migration $migration) { diff --git a/src/PackageTarget.php b/src/PackageTarget.php index 3149653..801b197 100644 --- a/src/PackageTarget.php +++ b/src/PackageTarget.php @@ -134,11 +134,13 @@ public static function install(Migration $migration) $package_fk = getForeignKeyFieldForItemType(Package::class); $computer_group_fk = getForeignKeyFieldForItemType(Group::class); + $timeslot_fk = getForeignKeyFieldForItemType(Timeslot::class); $query = "CREATE TABLE IF NOT EXISTS `$table` ( `id` int $sign NOT NULL AUTO_INCREMENT, `$package_fk` int $sign NOT NULL DEFAULT '0', `$computer_group_fk` int $sign NOT NULL DEFAULT '0', + `$timeslot_fk` int $sign NOT NULL DEFAULT '0', `date_creation` timestamp NULL DEFAULT NULL, `date_mod` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), @@ -152,7 +154,6 @@ public static function install(Migration $migration) } } - public static function uninstall(Migration $migration) { $table = self::getTable(); diff --git a/src/Timeslot.php b/src/Timeslot.php new file mode 100644 index 0000000..da98f76 --- /dev/null +++ b/src/Timeslot.php @@ -0,0 +1,92 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use CommonDropdown; +use DBConnection; +use Migration; + +class Timeslot extends CommonDropdown +{ + public static function getTypeName($nb = 0) + { + return __('Timeslot', 'deploy'); + } + + public static function getIcon() + { + return 'ti ti-calendar'; + } + + public function defineTabs($options = []) + { + + $ong = []; + $this->addDefaultFormTab($ong) + ->addStandardTab(TimeslotRange::getType(), $ong, $options) + ->addStandardTab(__CLASS__, $ong, $options); + + return $ong; + } + + public static function install(Migration $migration) + { + /** @var object $DB */ + global $DB; + + $table = self::getTable(); + if (!$DB->tableExists($table)) { + $migration->displayMessage("Installing $table"); + + $default_charset = DBConnection::getDefaultCharset(); + $default_collation = DBConnection::getDefaultCollation(); + + $query = "CREATE TABLE {$table} ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `date_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `date_mod` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `name` (`name`), + KEY `date_creation` (`date_creation`), + KEY `date_mod` (`date_mod`) + ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; + $DB->request($query); + } + } + + public static function uninstall(Migration $migration) + { + $table = self::getTable(); + $migration->displayMessage("Uninstalling $table"); + $migration->dropTable($table); + } +} diff --git a/src/TimeslotRange.php b/src/TimeslotRange.php new file mode 100644 index 0000000..3c5a39a --- /dev/null +++ b/src/TimeslotRange.php @@ -0,0 +1,203 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2022-2024 by Deploy plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/deploy + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Deploy; + +use CommonDBTM; +use CommonGLPI; +use DBConnection; +use Glpi\Application\View\TemplateRenderer; +use Migration; + +class TimeslotRange extends CommonDBTM +{ + public static function getTypeName($nb = 0) + { + return __('Range', 'deploy'); + } + + public static function getIcon() + { + return 'ti ti-calendar-event'; + } + + public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) + { + if ($item->getType() == Timeslot::class) { + return self::createTabEntry(self::getTypeName(1), 0); + } + return ''; + } + + public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) + { + if ($item->getType() == Timeslot::class) { + self::showForTimeslot($item); + } + return true; + } + + public static function getForTimeslot(Timeslot $timeslot) + { + $timeslots = new self(); + $timeslots = $timeslots->find([ + 'plugin_deploy_timeslots_id' => $timeslot->fields['id'], + ]); + $timeslots_data = []; + foreach ($timeslots as $timeslot) { + $timeslots_data[$timeslot['weekday']][] = [ + 'checked' => 'checked', + 'starttime' => intval(substr($timeslot['time_start'], 0, 2)), + 'endtime' => intval(substr($timeslot['time_end'], 0, 2)), + ]; + $timeslots_data['as_data'] = true; + } + for ($i = 1; $i <= 7; $i++) { + if (!isset($timeslots_data[$i])) { + $timeslots_data[$i] = [ + [ + 'checked' => '', + 'starttime' => 8, + 'endtime' => 12, + ], + [ + 'checked' => '', + 'starttime' => 14, + 'endtime' => 18, + ] + ]; + } + } + return $timeslots_data; + } + + public static function showForTimeslot(Timeslot $timeslot) + { + $timeslots_data = self::getForTimeslot($timeslot); + TemplateRenderer::getInstance()->display('@deploy/timeslot/timeslotrange.html.twig', [ + 'rand' => mt_rand(), + 'timeslot_id' => $timeslot->fields['id'], + 'days_list' => self::getDayList(), + 'timeslots_data' => $timeslots_data + ]); + } + + public static function getDayList() + { + return [ + 1 => __('Monday'), + 2 => __('Tuesday'), + 3 => __('Wednesday'), + 4 => __('Thursday'), + 5 => __('Friday'), + 6 => __('Saturday'), + 7 => __('Sunday'), + ]; + } + + public static function cleanOldData(array $input) + { + $timeslot = new self(); + $olddata = $timeslot->find( + [ + 'plugin_deploy_timeslots_id' => $input['plugin_deploy_timeslots_id'], + ] + ); + foreach ($olddata as $data) { + $timeslot->delete( + [ + 'id' => $data['id'] + ] + ); + } + } + + public static function cleanInput(array $input) + { + $output = []; + foreach ($input['timeslot'] as $key => $value) { + foreach ($value as $k => $v) { + if ($k == 'is_enable') { + continue; + } + $start_time = sprintf('%02d:00:00', $v['starttime']); + $end_time = sprintf('%02d:00:00', $v['endtime']); + $output[$key][$k] = [ + 'plugin_deploy_timeslots_id' => $input['plugin_deploy_timeslots_id'], + 'weekday' => $key, + 'time_start' => $start_time, + 'time_end' => $end_time, + 'is_enable' => (bool)$value['is_enable'], + ]; + } + } + + return $output; + } + + public static function install(Migration $migration) + { + /** @var object $DB */ + global $DB; + + $table = self::getTable(); + if (!$DB->tableExists($table)) { + $migration->displayMessage("Installing $table"); + + $default_charset = DBConnection::getDefaultCharset(); + $default_collation = DBConnection::getDefaultCollation(); + + $query = "CREATE TABLE {$table} ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `plugin_deploy_timeslots_id` int unsigned NOT NULL DEFAULT '0', + `weekday` tinyint NOT NULL DEFAULT '1', + `time_start` time NULL DEFAULT NULL, + `time_end` time NULL DEFAULT NULL, + `entities_id` int unsigned NOT NULL DEFAULT '0', + `is_active` tinyint(1) NOT NULL DEFAULT '1', + `is_recursive` tinyint(1) NOT NULL DEFAULT '0', + `date_mod` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `entities_id` (`entities_id`), + KEY `is_active` (`is_active`), + KEY `is_recursive` (`is_recursive`), + KEY `date_mod` (`date_mod`) + ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; + $DB->request($query); + } + } + + public static function uninstall(Migration $migration) + { + $table = self::getTable(); + $migration->displayMessage("Uninstalling $table"); + $migration->dropTable($table); + } +} diff --git a/templates/package/subitemtarget.list.html.twig b/templates/package/subitemtarget.list.html.twig index 8d062cc..1fdf821 100644 --- a/templates/package/subitemtarget.list.html.twig +++ b/templates/package/subitemtarget.list.html.twig @@ -87,6 +87,9 @@ {{ __('Number of statics items', 'deploy') }} + + {{ __('Timeslot', 'deploy') }} + @@ -118,6 +121,9 @@ {{ subitem.countStaticItem() }} + + {{ subitem.getTimeslotLink()|raw }} + {% endfor %} diff --git a/templates/package/target.list.html.twig b/templates/package/target.list.html.twig index 6ed6406..d4fc4af 100644 --- a/templates/package/target.list.html.twig +++ b/templates/package/target.list.html.twig @@ -29,28 +29,44 @@ {% import 'components/form/fields_macros.html.twig' as fields %} {% extends "@deploy/package/subitemtarget.list.html.twig" %} - {% block subitem_form %} - {{ fields.dropdownField( - "GlpiPlugin\\Deploy\\Computer\\Group", - 'plugin_deploy_computers_groups_id', - '0', - call('GlpiPlugin\\Deploy\\Computer\\Group::getTypeName', [0]), - { - 'used': used_item, - } - ) }} +
+
+ {{ fields.dropdownField( + "GlpiPlugin\\Deploy\\Computer\\Group", + 'plugin_deploy_computers_groups_id', + '0', + call('GlpiPlugin\\Deploy\\Computer\\Group::getTypeName', [0]), + { + 'used': used_item, + 'required': true, + 'field_class': 'col-12 col-sm-3', + } + ) }} + + {{ fields.dropdownField( + "GlpiPlugin\\Deploy\\Timeslot", + 'plugin_deploy_timeslots_id', + '0', + __("Choose a timeslot", 'deploy'), + { + 'required': true, + 'field_class': 'col-12 col-sm-3', + } + ) }} - {% set btn_add %} - - {% endset %} + {% set btn_add %} + + {% endset %} - {{ fields.htmlField( - '', - btn_add, - '' - ) }} + {{ fields.htmlField( + '', + btn_add, + '' + ) }} +
+
{% endblock %} diff --git a/templates/package/task.list.html.twig b/templates/package/task.list.html.twig index 850609e..2207061 100644 --- a/templates/package/task.list.html.twig +++ b/templates/package/task.list.html.twig @@ -25,7 +25,6 @@ # @link https://github.com/pluginsGLPI/deploy # ------------------------------------------------------------------------- #} -
{% if tasks|length == 0 %} diff --git a/templates/package/timeslot.html.twig b/templates/package/timeslot.html.twig new file mode 100644 index 0000000..6f4277b --- /dev/null +++ b/templates/package/timeslot.html.twig @@ -0,0 +1,43 @@ +{# + # ------------------------------------------------------------------------- + # Deploy plugin for GLPI + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Deploy. + # + # Deploy 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; either version 3 of the License, or + # (at your option) any later version. + # + # Deploy 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 Deploy. If not, see . + # ------------------------------------------------------------------------- + # @copyright Copyright (C) 2022-2024 by Deploy plugin team. + # @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + # @link https://github.com/pluginsGLPI/deploy + # ------------------------------------------------------------------------- + #} + +
+ + diff --git a/templates/timeslot/timeslotrange.html.twig b/templates/timeslot/timeslotrange.html.twig new file mode 100644 index 0000000..584c5c9 --- /dev/null +++ b/templates/timeslot/timeslotrange.html.twig @@ -0,0 +1,108 @@ +{# + # ------------------------------------------------------------------------- + # Deploy plugin for GLPI + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Deploy. + # + # Deploy 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; either version 3 of the License, or + # (at your option) any later version. + # + # Deploy 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 Deploy. If not, see . + # ------------------------------------------------------------------------- + # @copyright Copyright (C) 2022-2024 by Deploy plugin team. + # @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + # @link https://github.com/pluginsGLPI/deploy + # ------------------------------------------------------------------------- + #} + +{% set header %} + + + + {{ __('Day')}} + + + {{ __('Timeslot', 'deploy')}} + + + {{ __('All Day', 'deploy')}} + + {% for i in 0..24 %} + + {{ '%02d'|format(i) }} + + {% endfor %} + + {{ __('Add', 'deploy')}} + + + {{ __('Delete', 'deploy')}} + + + +{% endset %} +
+
+
+
+ + {{ header }} + + {% for key, label in days_list %} + + + + + + + + + {% endfor %} + + {{ header }} +
{{ label }} + + + + +
+ {% for tkey, tvalue in timeslots_data[key] %} + + + {% endfor %} +
+ + + +
+
+
+
+
+
+ + + + +
+ + +
+
+
+
+
+
+ +