mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 01:32:38 +00:00
This commit is contained in:
parent
a5294262e6
commit
3efecb8bed
@ -39,7 +39,7 @@
|
||||
|
||||
### Shopping list
|
||||
|
||||
- Added a new shopping list setting (top right corner settings menu) to automatically add products, that are below their defined min. stock amount, to the shopping list
|
||||
- Added a new shopping list setting (top right corner settings menu) to automatically add products, that are below their defined min. stock amount, to the shopping list (defaults to disabled)
|
||||
- Fixed that when using "Add products that are below defined min. stock amount", the calculated missing amount was wrong for products which had the new product option `Treat opened as out of stock` set and when having at least one opened stock entry
|
||||
|
||||
### Recipes
|
||||
@ -61,7 +61,7 @@
|
||||
|
||||
- The `Daily` period type has been changed to schedule the chore at the _same time_ (based on the start date) each `n` days
|
||||
- This period type scheduled chores `n` days _after the last execution_ before, which is also possible by using the `Hourly` period type and a corresponding period interval; all existing `Daily` schedules will be converted to that on migration
|
||||
- It's now possible to manually reschedule chores
|
||||
- It's now possible to manually reschedule / assign chores
|
||||
- New entry "Reschedule next execution" in the context/more menu on the chores overview page
|
||||
- If you have rescheduled a chore and want to continue the normal schedule instead, use the "Clear" button in the dialog
|
||||
- Rescheduled chores will be highlighted with an corresponding icon next to the "next estiamted tracking date"
|
||||
|
@ -98,7 +98,7 @@ class ChoresController extends BaseController
|
||||
$currentChores = $this->getChoresService()->GetCurrent();
|
||||
foreach ($currentChores as $currentChore)
|
||||
{
|
||||
if (FindObjectInArrayByPropertyValue($chores, 'id', $currentChore->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
||||
if (!empty($currentChore->next_estimated_execution_time))
|
||||
{
|
||||
if ($currentChore->next_estimated_execution_time < date('Y-m-d H:i:s'))
|
||||
{
|
||||
|
@ -5246,6 +5246,9 @@
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"rescheduled_next_execution_assigned_to_user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@ -5516,6 +5519,12 @@
|
||||
"next_execution_assigned_to_user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_rescheduled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_reassigned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"next_execution_assigned_user": {
|
||||
"$ref": "#/components/schemas/UserDto"
|
||||
}
|
||||
|
@ -2353,3 +2353,6 @@ msgstr ""
|
||||
|
||||
msgid "Automatically add products that are below their defined min. stock amount to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reassigned"
|
||||
msgstr ""
|
||||
|
83
migrations/0185.sql
Normal file
83
migrations/0185.sql
Normal file
@ -0,0 +1,83 @@
|
||||
ALTER TABLE chores
|
||||
ADD rescheduled_next_execution_assigned_to_user_id INT;
|
||||
|
||||
DROP VIEW chores_current;
|
||||
CREATE VIEW chores_current
|
||||
AS
|
||||
SELECT
|
||||
x.chore_id AS id, -- Dummy, LessQL needs an id column
|
||||
x.chore_id,
|
||||
x.chore_name,
|
||||
x.last_tracked_time,
|
||||
CASE WHEN x.rollover = 1 AND DATETIME('now', 'localtime') > x.next_estimated_execution_time THEN
|
||||
CASE WHEN IFNULL(x.track_date_only, 0) = 1 THEN
|
||||
DATETIME(STRFTIME('%Y-%m-%d', DATETIME('now', 'localtime')) || ' 23:59:59')
|
||||
ELSE
|
||||
DATETIME(STRFTIME('%Y-%m-%d', DATETIME('now', 'localtime')) || ' ' || STRFTIME('%H:%M:%S', x.next_estimated_execution_time))
|
||||
END
|
||||
ELSE
|
||||
CASE WHEN IFNULL(x.track_date_only, 0) = 1 THEN
|
||||
DATETIME(STRFTIME('%Y-%m-%d', x.next_estimated_execution_time) || ' 23:59:59')
|
||||
ELSE
|
||||
x.next_estimated_execution_time
|
||||
END
|
||||
END AS next_estimated_execution_time,
|
||||
x.track_date_only,
|
||||
x.next_execution_assigned_to_user_id,
|
||||
CASE WHEN IFNULL(x.rescheduled_date, '') != '' THEN 1 ELSE 0 END AS is_rescheduled,
|
||||
CASE WHEN IFNULL(x.rescheduled_next_execution_assigned_to_user_id, '') != '' THEN 1 ELSE 0 END AS is_reassigned
|
||||
FROM (
|
||||
|
||||
SELECT
|
||||
h.id AS chore_id,
|
||||
h.name AS chore_name,
|
||||
MAX(l.tracked_time) AS last_tracked_time,
|
||||
CASE WHEN IFNULL(h.rescheduled_date, '') != '' THEN
|
||||
h.rescheduled_date
|
||||
ELSE
|
||||
CASE WHEN MAX(l.tracked_time) IS NULL AND h.period_type != 'manually' THEN
|
||||
h.start_date
|
||||
ELSE
|
||||
CASE h.period_type
|
||||
WHEN 'manually' THEN NULL
|
||||
WHEN 'hourly' THEN DATETIME(MAX(l.tracked_time), '+' || CAST(h.period_interval AS TEXT) || ' hour')
|
||||
WHEN 'daily' THEN DATETIME(SUBSTR(CAST(DATETIME(MAX(l.tracked_time), '+' || CAST(h.period_interval AS TEXT) || ' days') AS TEXT), 1, 11) || SUBSTR(CAST(h.start_date AS TEXT), -8))
|
||||
WHEN 'weekly' THEN (
|
||||
SELECT next
|
||||
FROM (
|
||||
SELECT 'sunday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 0') AS next
|
||||
UNION
|
||||
SELECT 'monday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 1') AS next
|
||||
UNION
|
||||
SELECT 'tuesday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 2') AS next
|
||||
UNION
|
||||
SELECT 'wednesday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 3') AS next
|
||||
UNION
|
||||
SELECT 'thursday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 4') AS next
|
||||
UNION
|
||||
SELECT 'friday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 5') AS next
|
||||
UNION
|
||||
SELECT 'saturday' AS day, DATETIME((SELECT tracked_time FROM chores_log WHERE chore_id = h.id ORDER BY tracked_time DESC LIMIT 1), '1 days', '+' || CAST((h.period_interval - 1) * 7 AS TEXT) || ' days', 'weekday 6') AS next
|
||||
)
|
||||
WHERE INSTR(period_config, day) > 0
|
||||
ORDER BY next
|
||||
LIMIT 1
|
||||
)
|
||||
WHEN 'monthly' THEN DATETIME(MAX(l.tracked_time), 'start of month', '+' || CAST(h.period_interval AS TEXT) || ' month', '+' || CAST(h.period_days - 1 AS TEXT) || ' day')
|
||||
WHEN 'yearly' THEN DATETIME(SUBSTR(CAST(DATETIME(MAX(l.tracked_time), '+' || CAST(h.period_interval AS TEXT) || ' years') AS TEXT), 1, 4) || SUBSTR(CAST(h.start_date AS TEXT), 5, 6) || SUBSTR(CAST(DATETIME(MAX(l.tracked_time), '+' || CAST(h.period_interval AS TEXT) || ' years') AS TEXT), -9))
|
||||
WHEN 'adaptive' THEN DATETIME(MAX(l.tracked_time), '+' || CAST(IFNULL((SELECT average_frequency_hours FROM chores_execution_average_frequency WHERE chore_id = h.id), 0) AS TEXT) || ' hour')
|
||||
END
|
||||
END
|
||||
END AS next_estimated_execution_time,
|
||||
h.track_date_only,
|
||||
h.rollover,
|
||||
h.next_execution_assigned_to_user_id,
|
||||
h.rescheduled_date,
|
||||
h.rescheduled_next_execution_assigned_to_user_id
|
||||
FROM chores h
|
||||
LEFT JOIN chores_log l
|
||||
ON h.id = l.chore_id
|
||||
AND l.undone = 0
|
||||
WHERE h.active = 1
|
||||
GROUP BY h.id, h.name, h.period_days
|
||||
) x;
|
@ -152,18 +152,28 @@ $(document).on('click', '.track-chore-button', function(e)
|
||||
$('#chore-' + choreId + '-last-tracked-time').text(trackedTime);
|
||||
$('#chore-' + choreId + '-last-tracked-time-timeago').attr('datetime', trackedTime);
|
||||
|
||||
if (result.chore.period_type != "manually")
|
||||
if (result.next_estimated_execution_time != null && !result.next_estimated_execution_time.isEmpty())
|
||||
{
|
||||
$('#chore-' + choreId + '-next-execution-time').text(result.next_estimated_execution_time);
|
||||
$('#chore-' + choreId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#chore-' + choreId + '-next-execution-time').text("-");
|
||||
$('#chore-' + choreId + '-next-execution-time-timeago').removeAttr('datetime');
|
||||
}
|
||||
|
||||
if (result.chore.next_execution_assigned_to_user_id != null)
|
||||
{
|
||||
$('#chore-' + choreId + '-next-execution-assigned-user').text(result.next_execution_assigned_user.display_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#chore-' + choreId + '-next-execution-assigned-user').text("-");
|
||||
}
|
||||
|
||||
$('#chore-' + choreId + '-reschedule-icon').remove();
|
||||
$('#chore-' + choreId + '-rescheduled-icon').remove();
|
||||
$('#chore-' + choreId + '-reassigned-icon').remove();
|
||||
|
||||
Grocy.FrontendHelpers.EndUiBusy();
|
||||
toastr.success(__t('Tracked execution of chore %1$s on %2$s', choreName, trackedTime));
|
||||
@ -280,7 +290,7 @@ $(document).on("click", ".reschedule-chore-button", function(e)
|
||||
Grocy.EditObjectId = choreId;
|
||||
Grocy.Api.Get("chores/" + choreId, function(choreDetails)
|
||||
{
|
||||
var prefillDate = choreDetails.next_estimated_execution_time;
|
||||
var prefillDate = choreDetails.next_estimated_execution_time || moment().format("YYYY-MM-DD HH:mm:ss");
|
||||
if (choreDetails.chore.rescheduled_date != null && !choreDetails.chore.rescheduled_date.isEmpty())
|
||||
{
|
||||
prefillDate = choreDetails.chore.rescheduled_date;
|
||||
@ -297,6 +307,16 @@ $(document).on("click", ".reschedule-chore-button", function(e)
|
||||
Grocy.Components.DateTimePicker.SetValue(moment(prefillDate).format("YYYY-MM-DD HH:mm:ss"));
|
||||
}
|
||||
|
||||
if (choreDetails.chore.next_execution_assigned_to_user_id != null && !choreDetails.chore.next_execution_assigned_to_user_id.isEmpty())
|
||||
{
|
||||
Grocy.Components.UserPicker.SetId(choreDetails.chore.next_execution_assigned_to_user_id)
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Components.UserPicker.SetValue("");
|
||||
Grocy.Components.UserPicker.SetId(null);
|
||||
}
|
||||
|
||||
$("#reschedule-chore-modal-title").text(choreDetails.chore.name);
|
||||
$("#reschedule-chore-modal").modal("show");
|
||||
});
|
||||
@ -311,10 +331,19 @@ $("#reschedule-chore-save-button").on("click", function(e)
|
||||
return;
|
||||
}
|
||||
|
||||
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, { "rescheduled_date": Grocy.Components.DateTimePicker.GetValue() },
|
||||
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, { "rescheduled_date": Grocy.Components.DateTimePicker.GetValue(), "rescheduled_next_execution_assigned_to_user_id": Grocy.Components.UserPicker.GetValue() },
|
||||
function(result)
|
||||
{
|
||||
window.location.reload();
|
||||
Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId },
|
||||
function(result)
|
||||
{
|
||||
window.location.reload();
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
@ -327,10 +356,19 @@ $("#reschedule-chore-clear-button").on("click", function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, { "rescheduled_date": null },
|
||||
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, { "rescheduled_date": null, "rescheduled_next_execution_assigned_to_user_id": null },
|
||||
function(result)
|
||||
{
|
||||
window.location.reload();
|
||||
Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId },
|
||||
function(result)
|
||||
{
|
||||
window.location.reload();
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
|
@ -34,66 +34,74 @@ class ChoresService extends BaseService
|
||||
}
|
||||
|
||||
$chore = $this->getDatabase()->chores($choreId);
|
||||
$choreLastTrackedTime = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time');
|
||||
$lastChoreLogRow = $this->getDatabase()->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->orderBy('row_created_timestamp', 'DESC')->fetch();
|
||||
$lastDoneByUserId = $lastChoreLogRow->done_by_user_id;
|
||||
|
||||
$users = $this->getUsersService()->GetUsersAsDto();
|
||||
$assignedUsers = [];
|
||||
foreach ($users as $user)
|
||||
if (!empty($chore->rescheduled_next_execution_assigned_to_user_id))
|
||||
{
|
||||
if (in_array($user->id, explode(',', $chore->assignment_config)))
|
||||
{
|
||||
$assignedUsers[] = $user;
|
||||
}
|
||||
$nextExecutionUserId = $chore->rescheduled_next_execution_assigned_to_user_id;
|
||||
}
|
||||
|
||||
$nextExecutionUserId = null;
|
||||
if ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_RANDOM)
|
||||
else
|
||||
{
|
||||
// Random assignment and only 1 user in the group? Well, ok - will be hard to guess the next one...
|
||||
if (count($assignedUsers) == 1)
|
||||
{
|
||||
$nextExecutionUserId = array_shift($assignedUsers)->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$nextExecutionUserId = $assignedUsers[array_rand($assignedUsers)]->id;
|
||||
}
|
||||
}
|
||||
elseif ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER)
|
||||
{
|
||||
usort($assignedUsers, function ($a, $b) {
|
||||
return strcmp($a->display_name, $b->display_name);
|
||||
});
|
||||
$choreLastTrackedTime = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time');
|
||||
$lastChoreLogRow = $this->getDatabase()->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->orderBy('row_created_timestamp', 'DESC')->fetch();
|
||||
$lastDoneByUserId = $lastChoreLogRow->done_by_user_id;
|
||||
|
||||
$nextRoundMatches = false;
|
||||
foreach ($assignedUsers as $user)
|
||||
$users = $this->getUsersService()->GetUsersAsDto();
|
||||
$assignedUsers = [];
|
||||
foreach ($users as $user)
|
||||
{
|
||||
if ($nextRoundMatches)
|
||||
if (in_array($user->id, explode(',', $chore->assignment_config)))
|
||||
{
|
||||
$nextExecutionUserId = $user->id;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($user->id == $lastDoneByUserId)
|
||||
{
|
||||
$nextRoundMatches = true;
|
||||
$assignedUsers[] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing has matched, probably it was the last user in the sorted list -> the first one is the next one
|
||||
if ($nextExecutionUserId == null)
|
||||
$nextExecutionUserId = null;
|
||||
if ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_RANDOM)
|
||||
{
|
||||
$nextExecutionUserId = array_shift($assignedUsers)->id;
|
||||
// Random assignment and only 1 user in the group? Well, ok - will be hard to guess the next one...
|
||||
if (count($assignedUsers) == 1)
|
||||
{
|
||||
$nextExecutionUserId = array_shift($assignedUsers)->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$nextExecutionUserId = $assignedUsers[array_rand($assignedUsers)]->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_WHO_LEAST_DID_FIRST)
|
||||
{
|
||||
$row = $this->getDatabase()->chores_execution_users_statistics()->where('chore_id = :1', $choreId)->orderBy('execution_count')->limit(1)->fetch();
|
||||
if ($row != null)
|
||||
elseif ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER)
|
||||
{
|
||||
$nextExecutionUserId = $row->user_id;
|
||||
usort($assignedUsers, function ($a, $b) {
|
||||
return strcmp($a->display_name, $b->display_name);
|
||||
});
|
||||
|
||||
$nextRoundMatches = false;
|
||||
foreach ($assignedUsers as $user)
|
||||
{
|
||||
if ($nextRoundMatches)
|
||||
{
|
||||
$nextExecutionUserId = $user->id;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($user->id == $lastDoneByUserId)
|
||||
{
|
||||
$nextRoundMatches = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing has matched, probably it was the last user in the sorted list -> the first one is the next one
|
||||
if ($nextExecutionUserId == null)
|
||||
{
|
||||
$nextExecutionUserId = array_shift($assignedUsers)->id;
|
||||
}
|
||||
}
|
||||
elseif ($chore->assignment_type == self::CHORE_ASSIGNMENT_TYPE_WHO_LEAST_DID_FIRST)
|
||||
{
|
||||
$row = $this->getDatabase()->chores_execution_users_statistics()->where('chore_id = :1', $choreId)->orderBy('execution_count')->limit(1)->fetch();
|
||||
if ($row != null)
|
||||
{
|
||||
$nextExecutionUserId = $row->user_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,8 +205,6 @@ class ChoresService extends BaseService
|
||||
$logRow->save();
|
||||
$lastInsertId = $this->getDatabase()->lastInsertId();
|
||||
|
||||
$this->CalculateNextExecutionAssignment($choreId);
|
||||
|
||||
if ($chore->consume_product_on_execution == 1 && !empty($chore->product_id))
|
||||
{
|
||||
$transactionId = uniqid();
|
||||
@ -212,6 +218,15 @@ class ChoresService extends BaseService
|
||||
]);
|
||||
}
|
||||
|
||||
if (!empty($chore->rescheduled_next_execution_assigned_to_user_id))
|
||||
{
|
||||
$chore->update([
|
||||
'rescheduled_next_execution_assigned_to_user_id' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$this->CalculateNextExecutionAssignment($choreId);
|
||||
|
||||
return $lastInsertId;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
</button>
|
||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item reschedule-chore-button @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type == \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) disabled @endif"
|
||||
<a class="dropdown-item reschedule-chore-button"
|
||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||
type="button"
|
||||
href="#">
|
||||
@ -210,16 +210,18 @@
|
||||
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
@if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
||||
@if(!empty($curentChoreEntry->next_estimated_execution_time))
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||
datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
||||
@else
|
||||
<span>-</span>
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">-</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"></time>
|
||||
@endif
|
||||
@if($curentChoreEntry->is_rescheduled == 1)
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-reschedule-icon"
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-rescheduled-icon"
|
||||
class="text-muted"
|
||||
data-toggle="tooltip"
|
||||
title="{{ $__t('Rescheduled') }}">
|
||||
@ -228,10 +230,16 @@
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if(!empty($curentChoreEntry->last_tracked_time))
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||
datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
||||
@else
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">-</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"></time>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="@if(!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif">
|
||||
@ -241,6 +249,14 @@
|
||||
@else
|
||||
<span>-</span>
|
||||
@endif
|
||||
@if($curentChoreEntry->is_reassigned == 1)
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-reassigned-icon"
|
||||
class="text-muted"
|
||||
data-toggle="tooltip"
|
||||
title="{{ $__t('Reassigned') }}">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
</span>
|
||||
@endif
|
||||
</span>
|
||||
</td>
|
||||
<td id="chore-{{ $curentChoreEntry->chore_id }}-due-filter-column"
|
||||
@ -309,6 +325,11 @@
|
||||
'invalidFeedback' => $__t('This can only be in the future')
|
||||
))
|
||||
|
||||
@include('components.userpicker', array(
|
||||
'label' => 'Assigned to',
|
||||
'users' => $users
|
||||
))
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
Loading…
x
Reference in New Issue
Block a user