mirror of
https://github.com/grocy/grocy.git
synced 2025-08-15 02:04:38 +00:00
Squashed commit
Updated dependencies Added the possibility to skip chore schedules (closes #1486) Show the meal plan section on the corresponding calendar events (closes #1582) Make it possible to define a time for meal plan sections and use that time for the corresponding calendar events (references #1582) Added a changelog template Make it possible to toggle the meal plan calendar view on bigger screens (closes #1678)
This commit is contained in:
@@ -13,6 +13,6 @@ del "%releasePath%\grocy_%version%.zip"
|
|||||||
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock -xr!docs
|
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock -xr!docs
|
||||||
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\public\.htaccess"
|
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\public\.htaccess"
|
||||||
7za rn "%releasePath%\grocy_%version%.zip" .htaccess public\.htaccess
|
7za rn "%releasePath%\grocy_%version%.zip" .htaccess public\.htaccess
|
||||||
7za d "%releasePath%\grocy_%version%.zip" data\*.* data\storage data\viewcache\*
|
7za d "%releasePath%\grocy_%version%.zip" data\*.* data\storage data\viewcache\* changelog\__TEMPLATE.md
|
||||||
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\data\.htaccess"
|
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\data\.htaccess"
|
||||||
7za rn "%releasePath%\grocy_%version%.zip" .htaccess data\.htaccess
|
7za rn "%releasePath%\grocy_%version%.zip" .htaccess data\.htaccess
|
||||||
|
@@ -88,7 +88,7 @@ The following shorthands are available:
|
|||||||
- Example: `20210417` will be converted to `2021-04-17`
|
- Example: `20210417` will be converted to `2021-04-17`
|
||||||
- `YYYYMMe` or `YYYYMM+` gets expanded to the end of the given month in the given year in proper notation
|
- `YYYYMMe` or `YYYYMM+` gets expanded to the end of the given month in the given year in proper notation
|
||||||
- Example: `202107e` will be converted to `2021-07-31`
|
- Example: `202107e` will be converted to `2021-07-31`
|
||||||
- `[+/-]n[d/m/y]` gets expanded to a date relative to today, while adding `+` or subtracting `-` the number of days/months/years, in proper notation
|
- `[+/-]n[d/m/y]` gets expanded to a date relative to today, while adding (**+**) or subtracting (**-**) the **n**umber of**d**ays/**m**onths/**y**ears, in proper notation
|
||||||
- Example: `+1m` will be converted to the same day next month
|
- Example: `+1m` will be converted to the same day next month
|
||||||
- `x` gets expanded to `2999-12-31` (which is an alias for "never overdue")
|
- `x` gets expanded to `2999-12-31` (which is an alias for "never overdue")
|
||||||
- Down/up arrow keys will increase/decrease the date by 1 day
|
- Down/up arrow keys will increase/decrease the date by 1 day
|
||||||
|
@@ -1,27 +1,83 @@
|
|||||||
|
> ⚠️ xxxBREAKING CHANGESxxx
|
||||||
|
|
||||||
|
> ❗ xxxImportant upgrade informationXXX
|
||||||
|
|
||||||
|
### New feature: xxxx
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
- Stock entry labels get now also printed on inventory (only when adding products, same option "Stock entry label" like on the purchase page)
|
- Stock entry labels get now also printed on inventory (only when adding products, same option "Stock entry label" like on the purchase page)
|
||||||
- Added a separate status filter and table row highlighting (blue) on the chores, tasks and batteries overview pages for items due today
|
- The `config.php` option `FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT` was removed and is now a new product option `Treat opened as out of stock`, means, if opened stock entries will be counted as missing for calculating if a product is below its minimum stock amount, can now be configured per product
|
||||||
- Additionally, the "due soon" days of chores/tasks/batteries (top right corner settings menu) can be set to `0` to disable that filter/highlighting
|
|
||||||
- The `config.php` option `FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT` was removed and is now a new product option `Treat opened as out of stock`, means, if opened items will be counted as missing for calculating if a product is below its minimum stock amount, can now be configured per product
|
|
||||||
- The existing option will be migrated to all existing products, so no changed behavior after the update
|
- The existing option will be migrated to all existing products, so no changed behavior after the update
|
||||||
- There is also a new stock setting (section "Presets for new products") which can be used to configure the default when adding products (also that will be set based on the old setting on migration)
|
- There is also a new stock setting (section "Presets for new products") which can be used to configure the default when adding products (also that will be set based on the old setting on migration)
|
||||||
- When using/scanning a stock entry grocycode on the consume page, the amount is now prefilled by the stock entry amount (making it essentially possible to consume the corresponding stock entry in one go)
|
- When using/scanning a stock entry grocycode on the consume page, the amount is now prefilled by the stock entry amount (making it essentially possible to consume the corresponding stock entry in one go)
|
||||||
- Optimized relative time display (also fixed a phrasing problem for some languages, e.g. Hungarian) (thanks @Tallyrald)
|
|
||||||
- When using LDAP authentication, the configured `LDAP_UID_ATTR` is now used to compare if the user already exists instead of the username entered on the login page (that prevents creating multiple users if you entere the username in different notations) (thanks @FloSet)
|
|
||||||
- When using reverse proxy authentication (`ReverseProxyAuthMiddleware`), it's now also possible to pass the username in an environment variable instead of an HTTP header (new `config.php` option `REVERSE_PROXY_AUTH_USE_ENV`) (thanks @Forceu)
|
|
||||||
- Performance improvements (page loading time) of the recipes page
|
|
||||||
- New input shorthand `[+/-]n[d/m/y]` for date fields to quickly input a date relative to today (adding `+` or subtracting `-` the number of days/months/years, see the full list of available shorthands [here](https://github.com/grocy/grocy#input-shorthands-for-date-fields))
|
|
||||||
- Added a "Save & add another task"-button on the add task dialog to quickly create multiple tasks without having to close/reopen the dialog
|
|
||||||
- Fixed that stock entry labels on purchase were printed, even when "No label" was selected (was only a problem when running label printer WebHooks server side)
|
- Fixed that stock entry labels on purchase were printed, even when "No label" was selected (was only a problem when running label printer WebHooks server side)
|
||||||
- Fixed that when adding missing recipe ingredients, with the option "Only check if any amount is in stock" enabled, to the shopping list, unit conversions (if any) weren't considered
|
|
||||||
- Fixed that the recipe stock fulfillment information about shopping list amounts was not correct when the ingredient had a decimal amount
|
|
||||||
- Fixed that the meal plan showed the total calories per recipe (instead of per serving as stated by the suffix)
|
|
||||||
- Fixed that when having a quantity unit matching any application string, the translation of that string was used to display that unit
|
|
||||||
- Fixed that formatted (HTML) text for the (hidden by default) product description column on the stock overview page was not correctly displayed
|
- Fixed that formatted (HTML) text for the (hidden by default) product description column on the stock overview page was not correctly displayed
|
||||||
- Fixed that numeric and date-time sorting of table columns on the stock entries page did not work correctly (thanks @MasterofJOKers)
|
- Fixed that numeric and date-time sorting of table columns on the stock entries page did not work correctly (thanks @MasterofJOKers)
|
||||||
- Fixed that the barcode lookup for the "Stock by-barcode" API endpoints was case sensitive
|
|
||||||
- Fixed that the logout button/menu was missing when using external authentication (e.g. LDAP)
|
|
||||||
- Fixed that the consume page/dialog wasn't properly initialized when opening it from the stock entries page
|
- Fixed that the consume page/dialog wasn't properly initialized when opening it from the stock entries page
|
||||||
- Fixed that entries for not existing users were missing on the stock journal
|
- Fixed that entries for not existing users were missing on the stock journal
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- Performance improvements (page loading time) of the recipes page
|
||||||
|
- Fixed that when adding missing recipe ingredients, with the option "Only check if any amount is in stock" enabled, to the shopping list, unit conversions (if any) weren't considered
|
||||||
|
- Fixed that the recipe stock fulfillment information about shopping list amounts was not correct when the ingredient had a decimal amount
|
||||||
|
|
||||||
|
### Meal plan
|
||||||
|
|
||||||
|
- Meal plan sections can now (optionally) define a time, which will then be displayed on the meal plan section header and used for the corresponding calendar events
|
||||||
|
- Additionally the correspnding calendar event now also mentions the meal plan section name
|
||||||
|
- The day/week view can now be toggled
|
||||||
|
- New button on top right corner of the meal plan (only visible on bigger screens)
|
||||||
|
- On smaller screen the day view is still the default (no change)
|
||||||
|
- Fixed that the meal plan showed the total calories per recipe (instead of per serving as stated by the suffix)
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
|
||||||
|
- Chore schedules can now be skipped
|
||||||
|
- New button on the chores overview and chore tracking page
|
||||||
|
- Skipped schedules will be highlighted accordingly on the chore journal
|
||||||
|
|
||||||
|
### Calendar
|
||||||
|
|
||||||
- Fixed that when having a task without a due date, the iCal export was broken
|
- Fixed that when having a task without a due date, the iCal export was broken
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
- Added a "Save & add another task"-button on the add task dialog to quickly create multiple tasks without having to close/reopen the dialog
|
||||||
- Fixed that when editing a task without a due date, `1970-01-01` was shown
|
- Fixed that when editing a task without a due date, `1970-01-01` was shown
|
||||||
|
|
||||||
|
### Batteries
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Equipment
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Added a separate status filter and table row highlighting (blue) on the chores, tasks and batteries overview pages for items due today
|
||||||
|
- Additionally, the "due soon" days of chores/tasks/batteries (top right corner settings menu) can be set to `0` to disable that filter/highlighting
|
||||||
|
- Optimized relative time display (also fixed a phrasing problem for some languages, e.g. Hungarian) (thanks @Tallyrald)
|
||||||
|
- When using LDAP authentication, the configured `LDAP_UID_ATTR` is now used to compare if the user already exists instead of the username entered on the login page (that prevents creating multiple users if you enter the username in different notations) (thanks @FloSet)
|
||||||
|
- When using reverse proxy authentication (`ReverseProxyAuthMiddleware`), it's now also possible to pass the username in an environment variable instead of an HTTP header (new `config.php` option `REVERSE_PROXY_AUTH_USE_ENV`) (thanks @Forceu)
|
||||||
|
- New input shorthand `[+/-]n[d/m/y]` for date fields to quickly input a date relative to today (adding (**+**) or subtracting (**-**) the **n**umber of **d**ays/**m**onths/**y**ears, see the full list of available shorthands [here](https://github.com/grocy/grocy#input-shorthands-for-date-fields))
|
||||||
|
- Fixed that when having a quantity unit matching any application string, the translation of that string was used to display that unit
|
||||||
|
- Fixed that the logout button/menu was missing when using external authentication (e.g. LDAP)
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
- The API endpoint `/stock/shoppinglist/clear` has now a new optional request body parameter `done_only` (to only remove done items from the given shopping list, defaults to `false`)
|
- The API endpoint `/stock/shoppinglist/clear` has now a new optional request body parameter `done_only` (to only remove done items from the given shopping list, defaults to `false`)
|
||||||
|
- The API endpoint `/chores/{choreId}/execute` has now a new optional request body parameter `skipped` (to skip the next chore schedule)
|
||||||
|
- Fixed that the barcode lookup for the "Stock by-barcode" API endpoints was case sensitive
|
||||||
|
55
changelog/__TEMPLATE.md
Normal file
55
changelog/__TEMPLATE.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
> ⚠️ xxxBREAKING CHANGESxxx
|
||||||
|
|
||||||
|
> ❗ xxxImportant upgrade informationXXX
|
||||||
|
|
||||||
|
### New feature: xxxx
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Stock
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Shopping list
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Recipes
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Meal plan
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Calendar
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Batteries
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Equipment
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### Userfields
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- xxx
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- xxx
|
401
composer.lock
generated
401
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -73,6 +73,12 @@ class ChoresApiController extends BaseApiController
|
|||||||
$trackedTime = $requestBody['tracked_time'];
|
$trackedTime = $requestBody['tracked_time'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$skipped = false;
|
||||||
|
if (array_key_exists('skipped', $requestBody) && filter_var($requestBody['skipped'], FILTER_VALIDATE_BOOLEAN) !== false)
|
||||||
|
{
|
||||||
|
$skipped = $requestBody['skipped'];
|
||||||
|
}
|
||||||
|
|
||||||
$doneBy = GROCY_USER_ID;
|
$doneBy = GROCY_USER_ID;
|
||||||
if (array_key_exists('done_by', $requestBody) && !empty($requestBody['done_by']))
|
if (array_key_exists('done_by', $requestBody) && !empty($requestBody['done_by']))
|
||||||
{
|
{
|
||||||
@@ -84,7 +90,7 @@ class ChoresApiController extends BaseApiController
|
|||||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION);
|
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
$choreExecutionId = $this->getChoresService()->TrackChore($args['choreId'], $trackedTime, $doneBy);
|
$choreExecutionId = $this->getChoresService()->TrackChore($args['choreId'], $trackedTime, $doneBy, $skipped);
|
||||||
return $this->ApiResponse($response, $this->getDatabase()->chores_log($choreExecutionId));
|
return $this->ApiResponse($response, $this->getDatabase()->chores_log($choreExecutionId));
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
|
@@ -2003,7 +2003,7 @@
|
|||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`True` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`true` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
@@ -2234,7 +2234,7 @@
|
|||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`True` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`true` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
@@ -2532,7 +2532,7 @@
|
|||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`True` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`rue` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
@@ -2755,7 +2755,7 @@
|
|||||||
},
|
},
|
||||||
"allow_subproduct_substitution": {
|
"allow_subproduct_substitution": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "`True` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
"description": "`rue` when any in-stock sub product should be used when the given product is a parent product and currently not in-stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": {
|
"example": {
|
||||||
@@ -3616,6 +3616,11 @@
|
|||||||
"done_by": {
|
"done_by": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "A valid user id of who executed this chore, when omitted, the currently authenticated user will be used"
|
"description": "A valid user id of who executed this chore, when omitted, the currently authenticated user will be used"
|
||||||
|
},
|
||||||
|
"skipped": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "`true` when the execution should be tracked as skipped, defaults to `false` when omitted"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4341,6 +4346,9 @@
|
|||||||
"shopping_location_id": {
|
"shopping_location_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"treat_opened_as_out_of_stock": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"userfields": {
|
"userfields": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Key/value pairs of userfields"
|
"description": "Key/value pairs of userfields"
|
||||||
|
@@ -2292,3 +2292,12 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "When enabled, opened items will be counted as missing for calculating if this product is below its minimum stock amount"
|
msgid "When enabled, opened items will be counted as missing for calculating if this product is below its minimum stock amount"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Skipped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Skip next chore schedule"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Time"
|
||||||
|
msgstr ""
|
||||||
|
5
migrations/0163.sql
Normal file
5
migrations/0163.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE chores_log
|
||||||
|
ADD skipped TINYINT NOT NULL DEFAULT 0 CHECK(skipped IN (0, 1));
|
||||||
|
|
||||||
|
ALTER TABLE meal_plan_sections
|
||||||
|
ADD time_info TEXT;
|
@@ -205,5 +205,10 @@ function CleanFileName(fileName)
|
|||||||
|
|
||||||
function nl2br(s)
|
function nl2br(s)
|
||||||
{
|
{
|
||||||
|
if (s == null || s === undefined)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
return s.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1<br>$2");
|
return s.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1<br>$2");
|
||||||
}
|
}
|
||||||
|
@@ -393,6 +393,7 @@ Grocy.FrontendHelpers.ValidateForm = function(formId)
|
|||||||
if (form.checkValidity() === true)
|
if (form.checkValidity() === true)
|
||||||
{
|
{
|
||||||
$(form).find(':submit').removeClass('disabled');
|
$(form).find(':submit').removeClass('disabled');
|
||||||
|
$(form).find('.keep-disabled').addClass('disabled');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -24,7 +24,6 @@
|
|||||||
$('#battery_id_text_input').focus();
|
$('#battery_id_text_input').focus();
|
||||||
$('#battery_id_text_input').val('');
|
$('#battery_id_text_input').val('');
|
||||||
$('#tracked_time').find('input').val(moment().format('YYYY-MM-DD HH:mm:ss'));
|
$('#tracked_time').find('input').val(moment().format('YYYY-MM-DD HH:mm:ss'));
|
||||||
$('#tracked_time').find('input').trigger('change');
|
|
||||||
$('#battery_id_text_input').trigger('change');
|
$('#battery_id_text_input').trigger('change');
|
||||||
Grocy.FrontendHelpers.ValidateForm('batterytracking-form');
|
Grocy.FrontendHelpers.ValidateForm('batterytracking-form');
|
||||||
},
|
},
|
||||||
|
@@ -92,6 +92,7 @@ $(document).on('click', '.track-chore-button', function(e)
|
|||||||
|
|
||||||
var choreId = $(e.currentTarget).attr('data-chore-id');
|
var choreId = $(e.currentTarget).attr('data-chore-id');
|
||||||
var choreName = $(e.currentTarget).attr('data-chore-name');
|
var choreName = $(e.currentTarget).attr('data-chore-name');
|
||||||
|
var skipped = $(e.currentTarget).hasClass("skip");
|
||||||
|
|
||||||
Grocy.Api.Get('objects/chores/' + choreId,
|
Grocy.Api.Get('objects/chores/' + choreId,
|
||||||
function(chore)
|
function(chore)
|
||||||
@@ -102,7 +103,7 @@ $(document).on('click', '.track-chore-button', function(e)
|
|||||||
trackedTime = moment().format('YYYY-MM-DD');
|
trackedTime = moment().format('YYYY-MM-DD');
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Post('chores/' + choreId + '/execute', { 'tracked_time': trackedTime },
|
Grocy.Api.Post('chores/' + choreId + '/execute', { 'tracked_time': trackedTime, 'skipped': skipped },
|
||||||
function()
|
function()
|
||||||
{
|
{
|
||||||
Grocy.Api.Get('chores/' + choreId,
|
Grocy.Api.Get('chores/' + choreId,
|
||||||
@@ -132,7 +133,7 @@ $(document).on('click', '.track-chore-button', function(e)
|
|||||||
$('#chore-' + choreId + '-last-tracked-time').text(trackedTime);
|
$('#chore-' + choreId + '-last-tracked-time').text(trackedTime);
|
||||||
$('#chore-' + choreId + '-last-tracked-time-timeago').attr('datetime', trackedTime);
|
$('#chore-' + choreId + '-last-tracked-time-timeago').attr('datetime', trackedTime);
|
||||||
|
|
||||||
if (result.chore.period_type == "dynamic-regular")
|
if (result.chore.period_type != "manually")
|
||||||
{
|
{
|
||||||
$('#chore-' + choreId + '-next-execution-time').text(result.next_estimated_execution_time);
|
$('#chore-' + choreId + '-next-execution-time').text(result.next_estimated_execution_time);
|
||||||
$('#chore-' + choreId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time);
|
$('#chore-' + choreId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
$('#save-choretracking-button').on('click', function(e)
|
$('.save-choretracking-button').on('click', function(e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -7,13 +7,15 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var skipped = $(e.currentTarget).hasClass("skip");
|
||||||
|
|
||||||
var jsonForm = $('#choretracking-form').serializeJSON();
|
var jsonForm = $('#choretracking-form').serializeJSON();
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("choretracking-form");
|
Grocy.FrontendHelpers.BeginUiBusy("choretracking-form");
|
||||||
|
|
||||||
Grocy.Api.Get('chores/' + jsonForm.chore_id,
|
Grocy.Api.Get('chores/' + jsonForm.chore_id,
|
||||||
function(choreDetails)
|
function(choreDetails)
|
||||||
{
|
{
|
||||||
Grocy.Api.Post('chores/' + jsonForm.chore_id + '/execute', { 'tracked_time': Grocy.Components.DateTimePicker.GetValue(), 'done_by': $("#user_id").val() },
|
Grocy.Api.Post('chores/' + jsonForm.chore_id + '/execute', { 'tracked_time': Grocy.Components.DateTimePicker.GetValue(), 'done_by': $("#user_id").val(), 'skipped': skipped },
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
Grocy.EditObjectId = result.id;
|
Grocy.EditObjectId = result.id;
|
||||||
@@ -58,6 +60,7 @@ $('#chore_id').on('change', function(e)
|
|||||||
Grocy.Api.Get('objects/chores/' + choreId,
|
Grocy.Api.Get('objects/chores/' + choreId,
|
||||||
function(chore)
|
function(chore)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (chore.track_date_only == 1)
|
if (chore.track_date_only == 1)
|
||||||
{
|
{
|
||||||
Grocy.Components.DateTimePicker.ChangeFormat("YYYY-MM-DD");
|
Grocy.Components.DateTimePicker.ChangeFormat("YYYY-MM-DD");
|
||||||
@@ -68,6 +71,17 @@ $('#chore_id').on('change', function(e)
|
|||||||
Grocy.Components.DateTimePicker.ChangeFormat("YYYY-MM-DD HH:mm:ss");
|
Grocy.Components.DateTimePicker.ChangeFormat("YYYY-MM-DD HH:mm:ss");
|
||||||
Grocy.Components.DateTimePicker.SetValue(moment().format("YYYY-MM-DD HH:mm:ss"));
|
Grocy.Components.DateTimePicker.SetValue(moment().format("YYYY-MM-DD HH:mm:ss"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chore.period_type == "manually")
|
||||||
|
{
|
||||||
|
$(".save-choretracking-button.skip").addClass("keep-disabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$(".save-choretracking-button.skip").removeClass("keep-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
@@ -114,7 +128,7 @@ $('#choretracking-form input').keydown(function(event)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$('#save-choretracking-button').click();
|
$('.save-choretracking-button').first().click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -20,8 +20,6 @@ Grocy.Components.DateTimePicker.SetValue = function(value, inputElement = Grocy.
|
|||||||
$("#datetimepicker-shortcut").click();
|
$("#datetimepicker-shortcut").click();
|
||||||
}
|
}
|
||||||
inputElement.val(value);
|
inputElement.val(value);
|
||||||
inputElement.trigger('change');
|
|
||||||
|
|
||||||
inputElement.keyup();
|
inputElement.keyup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,8 +20,6 @@ Grocy.Components.DateTimePicker2.SetValue = function(value, inputElement = Grocy
|
|||||||
$("#datetimepicker2-shortcut").click();
|
$("#datetimepicker2-shortcut").click();
|
||||||
}
|
}
|
||||||
inputElement.val(value);
|
inputElement.val(value);
|
||||||
inputElement.trigger('change');
|
|
||||||
|
|
||||||
inputElement.keyup();
|
inputElement.keyup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,11 +19,18 @@ $(".calendar").each(function()
|
|||||||
var isPrimarySection = BoolVal(container.attr("data-primary-section"));
|
var isPrimarySection = BoolVal(container.attr("data-primary-section"));
|
||||||
var isLastSection = BoolVal(container.attr("data-last-section"));
|
var isLastSection = BoolVal(container.attr("data-last-section"));
|
||||||
|
|
||||||
|
var rightButtonList = "agendaWeek,agendaDay,prev,today,next";
|
||||||
|
if ($(window).width() < 768)
|
||||||
|
{
|
||||||
|
var rightButtonList = "prev,today,next";
|
||||||
|
}
|
||||||
|
|
||||||
var headerConfig = {
|
var headerConfig = {
|
||||||
"left": "title",
|
"left": "title",
|
||||||
"center": "",
|
"center": "",
|
||||||
"right": "prev,today,next"
|
"right": rightButtonList
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isPrimarySection)
|
if (!isPrimarySection)
|
||||||
{
|
{
|
||||||
headerConfig = {
|
headerConfig = {
|
||||||
@@ -39,7 +46,7 @@ $(".calendar").each(function()
|
|||||||
"weekNumbers": false,
|
"weekNumbers": false,
|
||||||
"eventLimit": false,
|
"eventLimit": false,
|
||||||
"eventSources": fullcalendarEventSources,
|
"eventSources": fullcalendarEventSources,
|
||||||
"defaultView": ($(window).width() < 768) ? "agendaDay" : "agendaWeek",
|
"defaultView": ($(window).width() < 768 || GetUriParam("days") == "0") ? "agendaDay" : "agendaWeek",
|
||||||
"allDayText": sectionName,
|
"allDayText": sectionName,
|
||||||
"allDayHtml": sectionName,
|
"allDayHtml": sectionName,
|
||||||
"minTime": "00:00:00",
|
"minTime": "00:00:00",
|
||||||
@@ -310,6 +317,15 @@ $(".calendar").each(function()
|
|||||||
{
|
{
|
||||||
UpdateUriParam("start", view.start.format("YYYY-MM-DD"));
|
UpdateUriParam("start", view.start.format("YYYY-MM-DD"));
|
||||||
|
|
||||||
|
if (view.name == "agendaDay")
|
||||||
|
{
|
||||||
|
UpdateUriParam("days", "0");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveUriParam("days");
|
||||||
|
}
|
||||||
|
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
firstRender = false
|
firstRender = false
|
||||||
|
@@ -14,6 +14,11 @@ class ApplicationService extends BaseService
|
|||||||
$fileName = basename($file);
|
$fileName = basename($file);
|
||||||
$fileNameParts = explode('_', $fileName);
|
$fileNameParts = explode('_', $fileName);
|
||||||
|
|
||||||
|
if ($fileName == '__TEMPLATE.md')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$fileContent = file_get_contents($file);
|
$fileContent = file_get_contents($file);
|
||||||
$version = $fileNameParts[1];
|
$version = $fileNameParts[1];
|
||||||
$releaseDate = explode('.', $fileNameParts[2])[0];
|
$releaseDate = explode('.', $fileNameParts[2])[0];
|
||||||
|
@@ -100,48 +100,75 @@ class CalendarService extends BaseService
|
|||||||
$mealPlanProductEvents = [];
|
$mealPlanProductEvents = [];
|
||||||
if (GROCY_FEATURE_FLAG_RECIPES)
|
if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
{
|
{
|
||||||
$recipes = $this->getDatabase()->recipes();
|
$mealPlanSections = $this->getDatabase()->meal_plan_sections();
|
||||||
$mealPlanDayRecipes = $this->getDatabase()->recipes()->where('type', 'mealplan-day');
|
|
||||||
$titlePrefix = $this->getLocalizationService()->__t('Meal plan recipe') . ': ';
|
|
||||||
|
|
||||||
|
$recipes = $this->getDatabase()->recipes()->where('type', 'normal');
|
||||||
|
$mealPlanDayRecipes = $this->getDatabase()->meal_plan()->where('type', 'recipe');
|
||||||
|
$titlePrefix = $this->getLocalizationService()->__t('Meal plan recipe') . ': ';
|
||||||
foreach ($mealPlanDayRecipes as $mealPlanDayRecipe)
|
foreach ($mealPlanDayRecipes as $mealPlanDayRecipe)
|
||||||
{
|
{
|
||||||
$recipesOfCurrentDay = $this->getDatabase()->recipes_nestings_resolved()->where('recipe_id = :1 AND includes_recipe_id != :1', $mealPlanDayRecipe->id);
|
$start = $mealPlanDayRecipe->day;
|
||||||
|
$dateFormat = 'date';
|
||||||
foreach ($recipesOfCurrentDay as $recipeOfCurrentDay)
|
$section = FindObjectInArrayByPropertyValue($mealPlanSections, 'id', $mealPlanDayRecipe->section_id);
|
||||||
|
if (!empty($section->time_info))
|
||||||
{
|
{
|
||||||
$mealPlanRecipeEvents[] = [
|
$start = $mealPlanDayRecipe->day . ' ' . $section->time_info . ':00';
|
||||||
'title' => $titlePrefix . FindObjectInArrayByPropertyValue($recipes, 'id', $recipeOfCurrentDay->includes_recipe_id)->name,
|
$dateFormat = 'datetime';
|
||||||
'start' => FindObjectInArrayByPropertyValue($recipes, 'id', $recipeOfCurrentDay->recipe_id)->name,
|
|
||||||
'date_format' => 'date',
|
|
||||||
'description' => $this->UrlManager->ConstructUrl('/mealplan' . '?week=' . FindObjectInArrayByPropertyValue($recipes, 'id', $recipeOfCurrentDay->recipe_id)->name),
|
|
||||||
'link' => $this->UrlManager->ConstructUrl('/recipes' . '?recipe=' . $recipeOfCurrentDay->includes_recipe_id . '#fullscreen')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$titlePrefix2 = '';
|
||||||
|
if (!empty($section->name))
|
||||||
|
{
|
||||||
|
$titlePrefix2 = $section->name . ': ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$mealPlanRecipeEvents[] = [
|
||||||
|
'title' => $titlePrefix . $titlePrefix2 . FindObjectInArrayByPropertyValue($recipes, 'id', $mealPlanDayRecipe->recipe_id)->name,
|
||||||
|
'start' => $start,
|
||||||
|
'date_format' => $dateFormat,
|
||||||
|
'description' => $this->UrlManager->ConstructUrl('/mealplan' . '?week=' . $mealPlanDayRecipe->day),
|
||||||
|
'link' => $this->UrlManager->ConstructUrl('/recipes' . '?recipe=' . $mealPlanDayRecipe->recipe_id . '#fullscreen')
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$mealPlanDayNotes = $this->getDatabase()->meal_plan()->where('type', 'note');
|
$mealPlanDayNotes = $this->getDatabase()->meal_plan()->where('type', 'note');
|
||||||
$titlePrefix = $this->getLocalizationService()->__t('Meal plan note') . ': ';
|
$titlePrefix = $this->getLocalizationService()->__t('Meal plan note') . ': ';
|
||||||
|
|
||||||
foreach ($mealPlanDayNotes as $mealPlanDayNote)
|
foreach ($mealPlanDayNotes as $mealPlanDayNote)
|
||||||
{
|
{
|
||||||
|
$start = $mealPlanDayNote->day;
|
||||||
|
$dateFormat = 'date';
|
||||||
|
$section = FindObjectInArrayByPropertyValue($mealPlanSections, 'id', $mealPlanDayNote->section_id);
|
||||||
|
if (!empty($section->time_info))
|
||||||
|
{
|
||||||
|
$start = $mealPlanDayNote->day . ' ' . $section->time_info . ':00';
|
||||||
|
$dateFormat = 'datetime';
|
||||||
|
}
|
||||||
|
|
||||||
$mealPlanNotesEvents[] = [
|
$mealPlanNotesEvents[] = [
|
||||||
'title' => $titlePrefix . $mealPlanDayNote->note,
|
'title' => $titlePrefix . $mealPlanDayNote->note,
|
||||||
'start' => $mealPlanDayNote->day,
|
'start' => $start,
|
||||||
'date_format' => 'date'
|
'date_format' => $dateFormat
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$products = $this->getDatabase()->products();
|
$products = $this->getDatabase()->products();
|
||||||
$mealPlanDayProducts = $this->getDatabase()->meal_plan()->where('type', 'product');
|
$mealPlanDayProducts = $this->getDatabase()->meal_plan()->where('type', 'product');
|
||||||
$titlePrefix = $this->getLocalizationService()->__t('Meal plan product') . ': ';
|
$titlePrefix = $this->getLocalizationService()->__t('Meal plan product') . ': ';
|
||||||
|
|
||||||
foreach ($mealPlanDayProducts as $mealPlanDayProduct)
|
foreach ($mealPlanDayProducts as $mealPlanDayProduct)
|
||||||
{
|
{
|
||||||
|
$start = $mealPlanDayProduct->day;
|
||||||
|
$dateFormat = 'date';
|
||||||
|
$section = FindObjectInArrayByPropertyValue($mealPlanSections, 'id', $mealPlanDayProduct->section_id);
|
||||||
|
if (!empty($section->time_info))
|
||||||
|
{
|
||||||
|
$start = $mealPlanDayProduct->day . ' ' . $section->time_info . ':00';
|
||||||
|
$dateFormat = 'datetime';
|
||||||
|
}
|
||||||
|
|
||||||
$mealPlanProductEvents[] = [
|
$mealPlanProductEvents[] = [
|
||||||
'title' => $titlePrefix . FindObjectInArrayByPropertyValue($products, 'id', $mealPlanDayProduct->product_id)->name,
|
'title' => $titlePrefix . FindObjectInArrayByPropertyValue($products, 'id', $mealPlanDayProduct->product_id)->name,
|
||||||
'start' => $mealPlanDayProduct->day,
|
'start' => $start,
|
||||||
'date_format' => 'date'
|
'date_format' => $dateFormat
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -110,8 +110,8 @@ class ChoresService extends BaseService
|
|||||||
$users = $this->getUsersService()->GetUsersAsDto();
|
$users = $this->getUsersService()->GetUsersAsDto();
|
||||||
|
|
||||||
$chore = $this->getDatabase()->chores($choreId);
|
$chore = $this->getDatabase()->chores($choreId);
|
||||||
$choreTrackedCount = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->count();
|
$choreTrackedCount = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0 AND skipped = 0', $choreId)->count();
|
||||||
$choreLastTrackedTime = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time');
|
$choreLastTrackedTime = $this->getDatabase()->chores_log()->where('chore_id = :1 AND undone = 0 AND skipped = 0', $choreId)->max('tracked_time');
|
||||||
$nextExecutionTime = $this->getDatabase()->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time');
|
$nextExecutionTime = $this->getDatabase()->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time');
|
||||||
|
|
||||||
$lastChoreLogRow = $this->getDatabase()->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->fetch();
|
$lastChoreLogRow = $this->getDatabase()->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->fetch();
|
||||||
@@ -157,7 +157,7 @@ class ChoresService extends BaseService
|
|||||||
return $chores;
|
return $chores;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function TrackChore(int $choreId, string $trackedTime, $doneBy = GROCY_USER_ID)
|
public function TrackChore(int $choreId, string $trackedTime, $doneBy = GROCY_USER_ID, $skipped = false)
|
||||||
{
|
{
|
||||||
if (!$this->ChoreExists($choreId))
|
if (!$this->ChoreExists($choreId))
|
||||||
{
|
{
|
||||||
@@ -176,10 +176,21 @@ class ChoresService extends BaseService
|
|||||||
$trackedTime = substr($trackedTime, 0, 10) . ' 00:00:00';
|
$trackedTime = substr($trackedTime, 0, 10) . ' 00:00:00';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($skipped)
|
||||||
|
{
|
||||||
|
if ($chore->period_type == self::CHORE_PERIOD_TYPE_MANUALLY)
|
||||||
|
{
|
||||||
|
throw new \Exception('Chores without a schedule can\'t be skipped');
|
||||||
|
}
|
||||||
|
|
||||||
|
$trackedTime = $this->getDatabase()->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time');
|
||||||
|
}
|
||||||
|
|
||||||
$logRow = $this->getDatabase()->chores_log()->createRow([
|
$logRow = $this->getDatabase()->chores_log()->createRow([
|
||||||
'chore_id' => $choreId,
|
'chore_id' => $choreId,
|
||||||
'tracked_time' => $trackedTime,
|
'tracked_time' => $trackedTime,
|
||||||
'done_by_user_id' => $doneBy
|
'done_by_user_id' => $doneBy,
|
||||||
|
'skipped' => BoolToInt($skipped)
|
||||||
]);
|
]);
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
$lastInsertId = $this->getDatabase()->lastInsertId();
|
$lastInsertId = $this->getDatabase()->lastInsertId();
|
||||||
|
@@ -102,7 +102,7 @@
|
|||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($choresLog as $choreLogEntry)
|
@foreach($choresLog as $choreLogEntry)
|
||||||
<tr id="chore-execution-{{ $choreLogEntry->id }}-row"
|
<tr id="chore-execution-{{ $choreLogEntry->id }}-row"
|
||||||
class="@if($choreLogEntry->undone == 1) text-muted @endif">
|
class="@if($choreLogEntry->undone == 1) text-muted @endif @if($choreLogEntry->skipped == 1) font-italic @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-secondary btn-xs undo-chore-execution-button permission-CHORE_UNDO_EXECUTION @if($choreLogEntry->undone == 1) disabled @endif"
|
<a class="btn btn-secondary btn-xs undo-chore-execution-button permission-CHORE_UNDO_EXECUTION @if($choreLogEntry->undone == 1) disabled @endif"
|
||||||
href="#"
|
href="#"
|
||||||
@@ -126,6 +126,9 @@
|
|||||||
<span>{{ $choreLogEntry->tracked_time }}</span>
|
<span>{{ $choreLogEntry->tracked_time }}</span>
|
||||||
<time class="timeago timeago-contextual @if(FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->track_date_only == 1) timeago-date-only @endif"
|
<time class="timeago timeago-contextual @if(FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->track_date_only == 1) timeago-date-only @endif"
|
||||||
datetime="{{ $choreLogEntry->tracked_time }}"></time>
|
datetime="{{ $choreLogEntry->tracked_time }}"></time>
|
||||||
|
@if($choreLogEntry->skipped == 1)
|
||||||
|
<span class="text-muted">{{ $__t('Skipped') }}</span>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
<td>
|
<td>
|
||||||
|
@@ -149,6 +149,15 @@
|
|||||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
<i class="fas fa-play"></i>
|
<i class="fas fa-play"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="btn btn-secondary btn-sm track-chore-button skip permission-CHORE_TRACK_EXECUTION @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type == \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) disabled @endif"
|
||||||
|
href="#"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="left"
|
||||||
|
title="{{ $__t('Skip next chore schedule') }}"
|
||||||
|
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||||
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
|
<i class="fas fa-forward"></i>
|
||||||
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary"
|
||||||
type="button"
|
type="button"
|
||||||
|
@@ -63,8 +63,9 @@
|
|||||||
'entity' => 'chores_log'
|
'entity' => 'chores_log'
|
||||||
))
|
))
|
||||||
|
|
||||||
<button id="save-choretracking-button"
|
<button class="btn btn-success save-choretracking-button">{{ $__t('OK') }}</button>
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
|
||||||
|
<button class="btn btn-secondary save-choretracking-button skip">{{ $__t('Skip') }}</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -36,12 +36,20 @@
|
|||||||
.fc-axis div {
|
.fc-axis div {
|
||||||
transform: translateX(-50%) translateY(-50%) rotate(-90deg);
|
transform: translateX(-50%) translateY(-50%) rotate(-90deg);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.8em;
|
font-size: 1.75em;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 0;
|
left: 0;
|
||||||
margin-left: 15px;
|
margin-left: 17px;
|
||||||
|
min-width: 100px;
|
||||||
|
line-height: 0.55;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-axis .small {
|
||||||
|
font-size: 60%;
|
||||||
|
letter-spacing: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-content-skeleton {
|
.fc-content-skeleton {
|
||||||
@@ -112,9 +120,11 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="calendar"
|
<div class="calendar"
|
||||||
data-section-id="{{ $mealplanSection->id }}"
|
data-section-id="{{ $mealplanSection->id }}"
|
||||||
data-section-name="{{ $mealplanSection->name }}"
|
data-section-name="{{ $mealplanSection->name }}<br><span class='small text-muted'>{{ $mealplanSection->time_info }}</span>"
|
||||||
data-primary-section="{{ BoolToString($loop->first) }}"
|
data-primary-section="{{ BoolToString($loop->first) }}"
|
||||||
{{-- $loop->last doesn't work however, is always null... --}}
|
{{--
|
||||||
|
$loop->last doesn't work however, is always null...
|
||||||
|
--}}
|
||||||
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -53,6 +53,15 @@
|
|||||||
'hint' => $__t('Sections will be ordered by that number on the meal plan')
|
'hint' => $__t('Sections will be ordered by that number on the meal plan')
|
||||||
))
|
))
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="time_info">{{ $__t('Time') }}</label>
|
||||||
|
<input type="time"
|
||||||
|
class="form-control"
|
||||||
|
id="time_info"
|
||||||
|
name="time_info"
|
||||||
|
value="@if($mode == 'edit'){{ $mealplanSection->time_info }}@endif">
|
||||||
|
</div>
|
||||||
|
|
||||||
<button id="save-mealplansection-button"
|
<button id="save-mealplansection-button"
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
|
|
||||||
|
@@ -75,6 +75,7 @@
|
|||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Sort number') }}</th>
|
<th>{{ $__t('Sort number') }}</th>
|
||||||
|
<th>{{ $__t('Time') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@@ -102,6 +103,9 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ $mealplanSection->sort_number }}
|
{{ $mealplanSection->sort_number }}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ $mealplanSection->time_info }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
|
78
yarn.lock
78
yarn.lock
@@ -29,9 +29,9 @@
|
|||||||
ndarray-linear-interpolate "^1.0.0"
|
ndarray-linear-interpolate "^1.0.0"
|
||||||
|
|
||||||
"@fontsource/noto-sans@^4.4.5":
|
"@fontsource/noto-sans@^4.4.5":
|
||||||
version "4.5.1"
|
version "4.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/@fontsource/noto-sans/-/noto-sans-4.5.1.tgz#b0674a0b903adccb2cdafcc61b7a7f48805b826f"
|
resolved "https://registry.yarnpkg.com/@fontsource/noto-sans/-/noto-sans-4.5.3.tgz#124c4475a885257b65fe4167af6615ab1bba477b"
|
||||||
integrity sha512-2Piw8UHz4XNomZgIUdurkv7cLcDOQvzZ8lagHF+Q7faYTukVCXZhdRLcVJ7qXMcsgYxg0wYYUYrF5sdnh6CzSQ==
|
integrity sha512-pBKuG/g7pMv1dCJ+x3piXqRfWuE/quPlPYaeGf3FwKUBGZyHl4LvM4bA8YmSlQzoMvH/MhcnvVHBhQ5x0fhseA==
|
||||||
|
|
||||||
"@fortawesome/fontawesome-free@^5.14.0":
|
"@fortawesome/fontawesome-free@^5.14.0":
|
||||||
version "5.15.4"
|
version "5.15.4"
|
||||||
@@ -238,12 +238,12 @@ datatables.net-bs4@1.10.16:
|
|||||||
datatables.net "1.10.16"
|
datatables.net "1.10.16"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-bs4@>=1.11.3, datatables.net-bs4@^1.10.15, datatables.net-bs4@^1.10.22:
|
datatables.net-bs4@>=1.11.3, datatables.net-bs4@^1.10.22:
|
||||||
version "1.11.3"
|
version "1.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.3.tgz#04817c5d9457f1b9807a1330f12c37a541596328"
|
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.4.tgz#caa82ab1a989bf1462f075b91213df865060d1ec"
|
||||||
integrity sha512-UPT2F1nvZZzKJSSHb+3+bTeQy1ULLMT1BexBHCkh5PhMnAZNPbTEZD+6To1RCBfUF1rtPwIJTwJ+Jjjxy86xRw==
|
integrity sha512-4V2uSxFloX1jRIsy4eAt1INyp5M5Pq5SV017/naq3zpVKraaFwqFjLhtkx64UHGXqcPj7egvj27dVcdnNIKnNA==
|
||||||
dependencies:
|
dependencies:
|
||||||
datatables.net ">=1.10.25"
|
datatables.net ">=1.11.3"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-colreorder-bs4@^1.5.2:
|
datatables.net-colreorder-bs4@^1.5.2:
|
||||||
@@ -264,9 +264,9 @@ datatables.net-colreorder@>=1.5.4, datatables.net-colreorder@^1.5.2:
|
|||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-plugins@^1.10.20:
|
datatables.net-plugins@^1.10.20:
|
||||||
version "1.10.24"
|
version "1.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.10.24.tgz#2b3cb4c30298da5762d1e1dd37640db6cd3b6c92"
|
resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.11.4.tgz#8eb7915cd9f43ba8ba256b89e06917aa24d1ac41"
|
||||||
integrity sha512-A0+q4BuPoiRkHXtn/D0bEUR+IiS+hpAp71CtB5BLZqG3R6UPp+OD306FwTZ/z6JUT7cIlf7BsM5fKxpOjhaGoA==
|
integrity sha512-39yyyoCCavagE0mO1BFsrRPeak5BwOlbtSACdGpPNf3jG5Lm7D6vEUPPcpGy6eLxjCiG/orMxlAqb8E5lSZtoA==
|
||||||
|
|
||||||
datatables.net-rowgroup-bs4@^1.1.2:
|
datatables.net-rowgroup-bs4@^1.1.2:
|
||||||
version "1.1.4"
|
version "1.1.4"
|
||||||
@@ -286,20 +286,20 @@ datatables.net-rowgroup@>=1.1.3, datatables.net-rowgroup@^1.1.2:
|
|||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-select-bs4@^1.3.1:
|
datatables.net-select-bs4@^1.3.1:
|
||||||
version "1.3.3"
|
version "1.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-select-bs4/-/datatables.net-select-bs4-1.3.3.tgz#daf0fa29ad6c438808b7d8d750abec6ade9805aa"
|
resolved "https://registry.yarnpkg.com/datatables.net-select-bs4/-/datatables.net-select-bs4-1.3.4.tgz#07336260be0aa7741a61b82188350f4d1e422a02"
|
||||||
integrity sha512-jXYNXoDPXQOMvJtIOmy8kiVbiSVJvwQIWUu5dNRAGLWBsCjReukjI7lhaljRocKvfrYam2zw9Z16XDz8nzxTDQ==
|
integrity sha512-hXxxTwR9Mx8xwD55g8hNiLt035afguKZ9Ejsdm5/mo3wmm9ml7gs8QG5fJuMRwtrdP9EKcnjc54+zVoHymEcgw==
|
||||||
dependencies:
|
dependencies:
|
||||||
datatables.net-bs4 "^1.10.15"
|
datatables.net-bs4 ">=1.11.3"
|
||||||
datatables.net-select "1.3.3"
|
datatables.net-select ">=1.3.3"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-select@1.3.3, datatables.net-select@^1.3.1:
|
datatables.net-select@>=1.3.3, datatables.net-select@^1.3.1:
|
||||||
version "1.3.3"
|
version "1.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.3.3.tgz#9259f70bf257e5d32198f38424d005808b78dc6d"
|
resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.3.4.tgz#7970587a8d8db8ba70a4cccb89b8519bb518116d"
|
||||||
integrity sha512-M4e9Qx790IPt+tc+CLgk7gPram3i+M2OmhIkhIpp7RcZ2Ay4App4ouQZcEx3j1MTRIWxtOz47xjpWrwVfJ23YQ==
|
integrity sha512-iQ/dBHIWkhfCBxzNdtef79seCNO1ZsA5zU0Uiw3R2mlwmjcJM1xn6pFNajke6SX7VnlzndGDHGqzzEljSqz4pA==
|
||||||
dependencies:
|
dependencies:
|
||||||
datatables.net "^1.10.15"
|
datatables.net ">=1.11.3"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net@1.10.16:
|
datatables.net@1.10.16:
|
||||||
@@ -309,10 +309,10 @@ datatables.net@1.10.16:
|
|||||||
dependencies:
|
dependencies:
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net@>=1.10.25, datatables.net@>=1.11.3, datatables.net@^1.10.15, datatables.net@^1.10.22:
|
datatables.net@>=1.11.3, datatables.net@^1.10.22:
|
||||||
version "1.11.3"
|
version "1.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.3.tgz#80e691036efcd62467558ee64c07dd566cb761b4"
|
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.4.tgz#5f3e1ec134fa532e794fbd47c13f8333d7a5c455"
|
||||||
integrity sha512-VMj5qEaTebpNurySkM6jy6sGpl+s6onPK8xJhYr296R/vUBnz1+id16NVqNf9z5aR076OGcpGHCuiTuy4E05oQ==
|
integrity sha512-z9LG4O0VYOYzp+rnArLExvnUWV8ikyWBcHYZEKDfVuz7BKxQdEq4a/tpO0Trbm+FL1+RY7UEIh+UcYNY/hwGxA==
|
||||||
dependencies:
|
dependencies:
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
@@ -513,10 +513,10 @@ json-schema-traverse@^0.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||||
|
|
||||||
json-schema@0.2.3:
|
json-schema@0.4.0:
|
||||||
version "0.2.3"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
|
||||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
|
||||||
|
|
||||||
json-stringify-safe@~5.0.1:
|
json-stringify-safe@~5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
@@ -524,13 +524,13 @@ json-stringify-safe@~5.0.1:
|
|||||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||||
|
|
||||||
jsprim@^1.2.2:
|
jsprim@^1.2.2:
|
||||||
version "1.4.1"
|
version "1.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
|
||||||
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
|
integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
|
||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "1.0.0"
|
assert-plus "1.0.0"
|
||||||
extsprintf "1.3.0"
|
extsprintf "1.3.0"
|
||||||
json-schema "0.2.3"
|
json-schema "0.4.0"
|
||||||
verror "1.10.0"
|
verror "1.10.0"
|
||||||
|
|
||||||
lodash@^4.17.21:
|
lodash@^4.17.21:
|
||||||
@@ -641,9 +641,9 @@ punycode@^2.1.0, punycode@^2.1.1:
|
|||||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||||
|
|
||||||
qs@~6.5.2:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
||||||
|
|
||||||
regenerator-runtime@^0.13.4:
|
regenerator-runtime@^0.13.4:
|
||||||
version "0.13.9"
|
version "0.13.9"
|
||||||
@@ -692,9 +692,9 @@ sprintf-js@^1.0.3, sprintf-js@^1.1.2:
|
|||||||
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
|
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
|
||||||
|
|
||||||
sshpk@^1.7.0:
|
sshpk@^1.7.0:
|
||||||
version "1.16.1"
|
version "1.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5"
|
||||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
asn1 "~0.2.3"
|
asn1 "~0.2.3"
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
Reference in New Issue
Block a user