Skip to content

Commit 52aa234

Browse files
committed
manage fullcalendar load and fix actualtime limits
1 parent 1b140e8 commit 52aa234

8 files changed

Lines changed: 125 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Actualtime
22

3+
## [3.2.2] - 2025/08/12
4+
### Fixed
5+
- Limit and better control for timer modification
6+
37
## [3.2.1] - 2025/06/10
48
### Fixed
59
- ProjectTask parent key to start the timer

front/sourcetimer.form.php

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,34 @@
4040
) {
4141
if (isset($_POST["update"])) {
4242
$config = new PluginActualtimeConfig();
43+
$itemtype = $_POST["itemtype"] ?? '';
44+
$item_id = $_POST["items_id"] ?? 0;
45+
$task_limit = PluginActualtimeSourcetimer::getTaskLimits($itemtype, $item_id);
4346
foreach ($_POST['actual_end'] as $key => $value) {
44-
if (!empty($value)) {
45-
$actualtime = new PluginActualtimeTask();
46-
if ($actualtime->getFromDB($key)) {
47-
if ($value != $actualtime->fields['actual_end'] && $value > $actualtime->fields['actual_begin']) {
48-
$seconds = (strtotime($value) - strtotime($actualtime->fields['actual_begin']));
49-
$input = [
50-
'id' => $key,
51-
'actual_end' => $value,
52-
'actual_actiontime' => $seconds,
53-
'is_modified' => 1,
47+
if (empty($value)) {
48+
continue;
49+
}
50+
$actualtime = new PluginActualtimeTask();
51+
if ($actualtime->getFromDB($key)) {
52+
if ($value != $actualtime->fields['actual_end'] && $value > $actualtime->fields['actual_begin']) {
53+
$seconds = (strtotime($value) - strtotime($actualtime->fields['actual_begin']));
54+
$input = [
55+
'id' => $key,
56+
'actual_end' => $value,
57+
'actual_actiontime' => $seconds,
58+
'is_modified' => 1,
59+
];
60+
if ($actualtime->fields['is_modified'] == 0) {
61+
$source = new PluginActualtimeSourcetimer();
62+
$input_source = [
63+
'plugin_actualtime_tasks_id' => $actualtime->fields['id'],
64+
'users_id' => Session::getLoginUserID(),
65+
'source_end' => $actualtime->fields['actual_end'],
66+
'source_actiontime' => $actualtime->fields['actual_actiontime'],
5467
];
55-
if ($actualtime->fields['is_modified'] == 0) {
56-
$source = new PluginActualtimeSourcetimer();
57-
$input_source = [
58-
'plugin_actualtime_tasks_id' => $actualtime->fields['id'],
59-
'users_id' => Session::getLoginUserID(),
60-
'source_end' => $actualtime->fields['actual_end'],
61-
'source_actiontime' => $actualtime->fields['actual_actiontime'],
62-
];
63-
$source->add($input_source);
64-
}
65-
$actualtime->update($input);
68+
$source->add($input_source);
6669
}
70+
$actualtime->update($input);
6771
}
6872
}
6973
}

inc/config.class.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public static function install(Migration $migration): void
211211
`autoupdate_duration` TINYINT NOT NULL DEFAULT '0',
212212
`planned_task` TINYINT NOT NULL DEFAULT '0',
213213
`multiple_day` TINYINT NOT NULL DEFAULT '0',
214-
`daily_limit` INT NOT NULL DEFAULT '8',
214+
`task_limit` INT NOT NULL DEFAULT '8',
215215
PRIMARY KEY (`id`)
216216
) ENGINE=InnoDB DEFAULT CHARSET={$default_charset}
217217
COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;";
@@ -229,8 +229,8 @@ public static function install(Migration $migration): void
229229
$migration->addField($table, 'planned_task', 'bool');
230230
$migration->addField($table, 'multiple_day', 'bool');
231231
// * 3.2.2
232-
// daily limit in hours for actualtime
233-
$migration->addField($table, 'daily_limit', 'int', ['value' => 8]);
232+
// task limit in hours for actualtime
233+
$migration->addField($table, 'task_limit', 'int', ['value' => 8]);
234234

235235
$migration->migrationOneTable($table);
236236
}

inc/dashboard.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public static function dashboardCards(?array $cards = []): array
7474
'filters' => ['dates'],
7575
'provider' => PluginActualtimeProvider::class . '::lessActualtimeUsageByDay',
7676
];
77+
7778
$cards['plugin_actualtime_moreapercentagectualtimetasksbyday'] = [
7879
'widgettype' => ['bars', 'lines'],
7980
'label' => Ticket::getTypeName() . ' - ' . __('Top 20 % Actualtime usage per day', 'actualtime'),

inc/sourcetimer.class.php

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,69 @@ public static function postShowItem($params): void
198198
* @return void
199199
*/
200200
public function modalForm(string $itemtype, int $items_id): void
201+
{
202+
$config = PluginActualtimeConfig::getInstance();
203+
$actualtimes = [];
204+
$userdata = [];
205+
$duration = 0;
206+
207+
foreach (self::getActualtimes($itemtype, $items_id) as $rows_id => $data) {
208+
if (empty($userdata)) {
209+
$href = User::getFormURLWithID($data['users_id']);
210+
$username = User::getFriendlyNameById($data['users_id']);
211+
$userdata['user'] = "<a href=\"{$href}\" target=\"_blank\">{$username}</a>";
212+
}
213+
$actualtimes[$rows_id] = $data;
214+
}
215+
216+
$max_hour = $config->fields['daily_limit'];
217+
if ($max_hour == 0) {
218+
$max_hour = 24;
219+
}
220+
221+
$previous_row = 0;
222+
foreach ($actualtimes as $rows_id => $data) {
223+
$data['rand'] = mt_rand();
224+
$data['min_date'] = $data['actual_begin'];
225+
$max_seconds = $max_hour * 60 * 60 - $duration;
226+
$limit = strtotime($data['min_date'] . " + {$max_seconds} seconds");
227+
$a_limit = date('Y-m-d H:i:s', $limit);
228+
if (isset($actualtimes[$previous_row])) {
229+
$max_date = $data['actual_begin'];
230+
if ($max_date > $a_limit) {
231+
$max_date = $a_limit;
232+
}
233+
$actualtimes[$previous_row]['max_date'] = $max_date;
234+
$previous_max_seconds = strtotime($max_date) - strtotime($actualtimes[$previous_row]['actual_end']);
235+
$actualtimes[$previous_row]['limit'] = Html::timestampToString($previous_max_seconds);
236+
}
237+
$data['max_date'] = $a_limit;
238+
$data['limit'] = Html::timestampToString($max_seconds);
239+
$data['stamp_actiontime'] = Html::timestampToString($data['actual_actiontime']);
240+
$actualtimes[$rows_id] = $data;
241+
$duration += (int) $data['actual_actiontime'];
242+
$previous_row = $rows_id;
243+
}
244+
$userdata['duration'] = Html::timestampToString($duration);
245+
$userdata['limit'] = Html::timestampToString($max_hour * 60 * 60);
246+
247+
$template = "@actualtime/forms/modify_timers.html.twig";
248+
TemplateRenderer::getInstance()->display($template, [
249+
'itemtype' => $itemtype,
250+
'items_id' => $items_id,
251+
'actualtimes' => $actualtimes,
252+
'userdata' => $userdata,
253+
'target' => $this->getFormURL(),
254+
]);
255+
}
256+
257+
/**
258+
* @param string $itemtype
259+
* @param int $items_id
260+
*
261+
* @return \DBmysqlIterator
262+
*/
263+
private static function getActualtimes(string $itemtype, int $items_id): \DBmysqlIterator
201264
{
202265
/** @var \DBmysql $DB */
203266
global $DB;
@@ -211,25 +274,27 @@ public function modalForm(string $itemtype, int $items_id): void
211274
],
212275
];
213276

214-
$actualtimes = [];
215-
$userdata = [];
216-
foreach ($DB->request($query) as $rows_id => $data) {
217-
if (empty($userdata)) {
218-
$href = User::getFormURLWithID($data['users_id']);
219-
$username = User::getFriendlyNameById($data['users_id']);
220-
$userdata['user'] = "<a href=\"{$href}\" target=\"_blank\">{$username}</a>";
221-
}
222-
$actualtimes[$rows_id] = $data;
223-
}
277+
return $DB->request($query);
278+
}
224279

280+
/**
281+
* @param string $itemtype
282+
* @param int $items_id
283+
*
284+
* @return array
285+
*/
286+
public static function getTaskLimits(string $itemtype, int $items_id): array
287+
{
225288
$config = PluginActualtimeConfig::getInstance();
289+
$limits = [];
226290
$duration = 0;
227291
$max_hour = $config->fields['daily_limit'];
228292
if ($max_hour == 0) {
229293
$max_hour = 24;
230294
}
295+
296+
$actualtimes = self::getActualtimes($itemtype, $items_id);
231297
foreach ($actualtimes as $rows_id => $data) {
232-
$data['rand'] = mt_rand();
233298
$data['min_date'] = $data['actual_begin'];
234299
$next_row = $rows_id + 1;
235300
$max_seconds = $max_hour * 60 * 60 - $duration;
@@ -249,17 +314,8 @@ public function modalForm(string $itemtype, int $items_id): void
249314
$actualtimes[$rows_id] = $data;
250315
$duration += (int) $data['actual_actiontime'];
251316
}
252-
$userdata['duration'] = Html::timestampToString($duration);
253-
$userdata['limit'] = Html::timestampToString($max_hour * 60 * 60);
254317

255-
$template = "@actualtime/forms/modify_timers.html.twig";
256-
TemplateRenderer::getInstance()->display($template, [
257-
'itemtype' => $itemtype,
258-
'items_id' => $items_id,
259-
'actualtimes' => $actualtimes,
260-
'userdata' => $userdata,
261-
'target' => $this->getFormURL(),
262-
]);
318+
return $limits;
263319
}
264320

265321
/**

setup.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
use Glpi\Plugin\Hooks;
3333

34-
define('PLUGIN_ACTUALTIME_VERSION', '3.2.2-beta');
34+
define('PLUGIN_ACTUALTIME_VERSION', '3.2.2-beta.2');
3535

3636
// Minimal GLPI version, inclusive
3737
define("PLUGIN_ACTUALTIME_MIN_GLPI", "10.0.10");

templates/forms/config.html.twig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@
6363
) }}
6464

6565
{{ fields.numberField(
66-
'daily_limit',
67-
item.fields['daily_limit'],
68-
__('Daily limit in hours for actualtime', 'actualtime'),
66+
'task_limit',
67+
item.fields['task_limit'],
68+
__('Task limit in hours for ActualTime', 'actualtime'),
6969
options|merge({
7070
'input_addclass': 'w-auto',
7171
'min': 0,

templates/forms/modify_timers.html.twig

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<tr>
2323
<th scope="col" class="col-1">{{ __('User') }}</th>
2424
<th scope="col" class="col-1">{{ __('Duration') }}</th>
25-
<th scope="col" class="col-1">{{ __('Daily limit', 'actualtime') }}</th>
25+
<th scope="col" class="col-1">{{ __('Task limit', 'actualtime') }}</th>
2626
</tr>
2727
</thead>
2828
<tbody>
@@ -44,7 +44,7 @@
4444

4545
{% set start_tooltip = __('Start') ~ ': ' ~ actualtime['min_date'] %}
4646
{% set end_tooltip = __('End') ~ ': ' ~ actualtime['max_date'] %}
47-
{% set limit_tooltip = __('Max available time', 'actualtime') ~ ': ' ~ actualtime['limit'] %}
47+
{% set limit_tooltip = __('Additional time available', 'actualtime') ~ ': ' ~ actualtime['limit'] %}
4848
{% set actual_end_tooltip %}
4949
{% do call(
5050
'Html::showToolTip',
@@ -54,15 +54,19 @@
5454
{{ fields.datetimeField(
5555
'actual_end[' ~ actualtime['id'] ~ ']',
5656
actualtime['actual_end'],
57-
__('End date') ~ ' ' ~ actual_end_tooltip,
57+
__('End date') ~ ' (' ~ actualtime['stamp_actiontime'] ~ ') ' ~ actual_end_tooltip,
5858
options|merge({'rand': actualtime['rand']})
5959
) }}
60+
{# To give it time to load the fullcalendar library #}
6061
<script>
61-
$(document).ready(function () {
62+
const intervalname{{ actualtime['rand'] }} = setInterval(() => {
6263
var date_end_input = $("[id='actual-end-{{ actualtime['id'] }}_{{ actualtime['rand'] }}']")[0];
63-
date_end_input._flatpickr.set('minDate', "{{ actualtime['min_date'] }}");
64-
date_end_input._flatpickr.set('maxDate', "{{ actualtime['max_date'] }}");
65-
});
64+
if (date_end_input._flatpickr) {
65+
date_end_input._flatpickr.set('minDate', "{{ actualtime['min_date'] }}");
66+
date_end_input._flatpickr.set('maxDate', "{{ actualtime['max_date'] }}");
67+
clearInterval(intervalname{{ actualtime['rand'] }});
68+
}
69+
}, 200);
6670
</script>
6771
{% endfor %}
6872

0 commit comments

Comments
 (0)