diff --git a/controllers/UsersApiController.php b/controllers/UsersApiController.php index e09dba35..d8341c31 100644 --- a/controllers/UsersApiController.php +++ b/controllers/UsersApiController.php @@ -219,6 +219,19 @@ class UsersApiController extends BaseApiController } } + public function DeleteUserSetting(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) + { + try + { + $value = $this->getUsersService()->DeleteUserSetting(GROCY_USER_ID, $args['settingKey']); + return $this->EmptyApiResponse($response); + } + catch (\Exception $ex) + { + return $this->GenericErrorResponse($response, $ex->getMessage()); + } + } + public function __construct(\DI\Container $container) { parent::__construct($container); diff --git a/grocy.openapi.json b/grocy.openapi.json index fa83b6f7..28f0da1d 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -1299,6 +1299,38 @@ } } } + }, + "delete": { + "summary": "Deletes the given setting of the currently logged in user", + "tags": [ + "Current user" + ], + "parameters": [ + { + "in": "path", + "name": "settingKey", + "required": true, + "description": "The key of the user setting", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "The operation was successful" + }, + "400": { + "description": "The operation was not successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error400" + } + } + } + } + } } }, "/stock": { diff --git a/localization/strings.pot b/localization/strings.pot index b6951360..0511cc95 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -1822,7 +1822,7 @@ msgstr "" msgid "Price per stock unit" msgstr "" -msgid "Hide/view columns" +msgid "Table options" msgstr "" msgid "This product is currently on a shopping list" @@ -2008,3 +2008,24 @@ msgstr "" msgid "Show on stock overview page" msgstr "" + +msgid "None" +msgstr "" + +msgid "Group by" +msgstr "" + +msgid "Ingredient group" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Are you sure to reset the table options?" +msgstr "" + +msgid "Table layout configuration" +msgstr "" + +msgid "Hide/view columns" +msgstr "" diff --git a/public/js/grocy.js b/public/js/grocy.js index 7684c0af..4766d8d6 100644 --- a/public/js/grocy.js +++ b/public/js/grocy.js @@ -433,6 +433,49 @@ Grocy.FrontendHelpers.ShowGenericError = function(message, exception) console.error(exception); } +Grocy.FrontendHelpers.SaveUserSetting = function(settingsKey, value) +{ + Grocy.UserSettings[settingsKey] = value; + + jsonData = {}; + jsonData.value = value; + Grocy.Api.Put('user/settings/' + settingsKey, jsonData, + function(result) + { + // Nothing to do... + }, + function(xhr) + { + if (!xhr.statusText.isEmpty()) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + } + ); +} + +Grocy.FrontendHelpers.DeleteUserSetting = function(settingsKey, reloadPageOnSuccess = false) +{ + delete Grocy.UserSettings[settingsKey]; + + Grocy.Api.Delete('user/settings/' + settingsKey, {}, + function(result) + { + if (reloadPageOnSuccess) + { + location.reload(); + } + }, + function(xhr) + { + if (!xhr.statusText.isEmpty()) + { + Grocy.FrontendHelpers.ShowGenericError('Error while deleting, please retry', xhr.response) + } + } + ); +} + $(document).on("keyup paste change", "input, textarea", function() { $(this).closest("form").addClass("is-dirty"); @@ -468,23 +511,7 @@ $(document).on("change", ".user-setting-control", function() var value = element.val(); } - Grocy.UserSettings[settingKey] = value; - - jsonData = {}; - jsonData.value = value; - Grocy.Api.Put('user/settings/' + settingKey, jsonData, - function(result) - { - // Nothing to do... - }, - function(xhr) - { - if (!xhr.statusText.isEmpty()) - { - Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) - } - } - ); + Grocy.FrontendHelpers.SaveUserSetting(settingKey, value); }); // Show file name Bootstrap custom file input @@ -713,25 +740,15 @@ $.extend(true, $.fn.dataTable.defaults, { 'stateSaveCallback': function(settings, data) { var settingKey = 'datatables_state_' + settings.sTableId; - var stateData = JSON.stringify(data); - - Grocy.UserSettings[settingKey] = stateData; - - jsonData = {}; - jsonData.value = stateData; - Grocy.Api.Put('user/settings/' + settingKey, jsonData, - function(result) - { - // Nothing to do... - }, - function(xhr) - { - if (!xhr.statusText.isEmpty()) - { - Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) - } - } - ); + if ($.isEmptyObject(data)) + { + //state.clear was called and unfortunately the table is not refresh, so we are reloading the page + Grocy.FrontendHelpers.DeleteUserSetting(settingKey, true); + } else + { + var stateData = JSON.stringify(data); + Grocy.FrontendHelpers.SaveUserSetting(settingKey, stateData); + } }, 'stateLoadCallback': function(settings, data) { @@ -746,9 +763,45 @@ $.extend(true, $.fn.dataTable.defaults, { return JSON.parse(Grocy.UserSettings[settingKey]); } }, + 'preDrawCallback': function(settings) + { + // Currently it is not possible to save the state of rowGroup via saveState events + var api = new $.fn.dataTable.Api(settings); + if (typeof api.rowGroup === "function") + { + var settingKey = 'datatables_rowGroup_' + settings.sTableId; + if (Grocy.UserSettings[settingKey] !== undefined) + { + var rowGroup = JSON.parse(Grocy.UserSettings[settingKey]); + + // Check if there way changed. the draw event is called often therefore we have to check if it's really necessary + if (rowGroup.enable !== api.rowGroup().enabled() + || ("dataSrc" in rowGroup && rowGroup.dataSrc !== api.rowGroup().dataSrc())) + { + + api.rowGroup().enable(rowGroup.enable); + + if ("dataSrc" in rowGroup) + { + api.rowGroup().dataSrc(rowGroup.dataSrc); + + // Apply fixed order for group column + var fixedOrder = { + pre: [rowGroup.dataSrc, 'asc'] + }; + + api.order.fixed(fixedOrder); + } + } + } + } + }, 'columnDefs': [ { type: 'chinese-string', targets: '_all' } - ] + ], + 'rowGroup': { + enable: false + } }); // serializeJSON defaults @@ -847,6 +900,28 @@ $(".change-table-columns-visibility-button").on("click", function(e) var dataTable = $(dataTableSelector).DataTable(); var columnCheckBoxesHtml = ""; + var rowGroupRadioBoxesHtml = ""; + + var rowGroupDefined = typeof dataTable.rowGroup === "function"; + + if (rowGroupDefined) + { + var rowGroupChecked = (dataTable.rowGroup().enabled()) ? "" : "checked"; + rowGroupRadioBoxesHtml = ' \ +
\ + \ + \ +
'; + } + dataTable.columns().every(function() { var index = this.index(); @@ -864,7 +939,7 @@ $(".change-table-columns-visibility-button").on("click", function(e) checked = ""; } - columnCheckBoxesHtml += '
\ + columnCheckBoxesHtml += ' \
\ ' + title + ' \ \ -
\ -
' + '; + + if (rowGroupDefined) + { + var rowGroupChecked = ""; + if (dataTable.rowGroup().enabled() && dataTable.rowGroup().dataSrc() == index) + { + rowGroupChecked = "checked"; + } + + rowGroupRadioBoxesHtml += ' \ +
\ + \ + \ +
'; + } }); + var message = '
' + __t('Table options') + '

' + __t('Hide/view columns') + '
' + columnCheckBoxesHtml + '
'; + if (rowGroupDefined) + { + message += '
' + __t('Group by') + '
' + rowGroupRadioBoxesHtml + '
'; + } + bootbox.dialog({ - message: '
' + __t('Hide/view columns') + '

' + columnCheckBoxesHtml + '
', + message: message, size: 'small', backdrop: true, closeButton: false, + onEscape: true, buttons: { - cancel: { + reset: { + label: __t('Reset'), + className: 'btn-outline-danger float-left responsive-button', + callback: function() + { + bootbox.confirm({ + swapButtonOrder: true, + message: __t("Are you sure to reset the table options?"), + buttons: { + confirm: { + label: 'Yes', + className: 'btn-danger' + }, + cancel: { + label: 'No', + className: 'btn-primary' + } + }, + callback: function(result) + { + if (result) + { + var dataTable = $(dataTableSelector).DataTable(); + var tableId = dataTable.settings()[0].sTableId; + + // Delete rowgroup settings + Grocy.FrontendHelpers.DeleteUserSetting('datatables_rowGroup_' + tableId); + + // Delete state settings + dataTable.state.clear(); + } + bootbox.hideAll(); + } + }); + } + }, + ok: { label: __t('OK'), className: 'btn-primary responsive-button', callback: function() @@ -896,6 +1036,7 @@ $(".change-table-columns-visibility-button").on("click", function(e) } }); }); + $(document).on("click", ".change-table-columns-visibility-toggle", function() { var dataTableSelector = $(this).attr("data-table-selector"); @@ -904,3 +1045,45 @@ $(document).on("click", ".change-table-columns-visibility-toggle", function() dataTable.columns(columnIndex).visible(this.checked); }); + + +$(document).on("click", ".change-table-columns-rowgroup-toggle", function() +{ + var dataTableSelector = $(this).attr("data-table-selector"); + var columnIndex = $(this).attr("data-column-index"); + var dataTable = $(dataTableSelector).DataTable(); + var rowGroup; + + if (columnIndex == -1) + { + rowGroup = { + enable: false + }; + + dataTable.rowGroup().enable(false); + + //remove fixed order + dataTable.order.fixed({}); + } + else + { + rowGroup = { + enable: true, + dataSrc: columnIndex + } + + dataTable.rowGroup().enable(true); + dataTable.rowGroup().dataSrc(columnIndex); + + //apply fixed order for group column + var fixedOrder = { + pre: [columnIndex, 'asc'] + }; + dataTable.order.fixed(fixedOrder); + } + + var settingKey = 'datatables_rowGroup_' + dataTable.settings()[0].sTableId; + Grocy.FrontendHelpers.SaveUserSetting(settingKey, JSON.stringify(rowGroup)); + + dataTable.draw(); +}); diff --git a/public/viewjs/productform.js b/public/viewjs/productform.js index dac03001..8e7dfef8 100644 --- a/public/viewjs/productform.js +++ b/public/viewjs/productform.js @@ -275,6 +275,7 @@ var quConversionsTable = $('#qu-conversions-table-products').DataTable({ { 'visible': false, 'targets': 4 } ].concat($.fn.dataTable.defaults.columnDefs), 'rowGroup': { + enable: true, dataSrc: 4 } }); diff --git a/public/viewjs/recipeform.js b/public/viewjs/recipeform.js index 0df9a397..4833dac5 100644 --- a/public/viewjs/recipeform.js +++ b/public/viewjs/recipeform.js @@ -82,6 +82,7 @@ var recipesPosTables = $('#recipes-pos-table').DataTable({ { 'visible': false, 'targets': 4 } ].concat($.fn.dataTable.defaults.columnDefs), 'rowGroup': { + enable: true, dataSrc: 4 } }); diff --git a/public/viewjs/shoppinglist.js b/public/viewjs/shoppinglist.js index 35fb577b..084b7438 100644 --- a/public/viewjs/shoppinglist.js +++ b/public/viewjs/shoppinglist.js @@ -9,6 +9,7 @@ var shoppingListTable = $('#shoppinglist-table').DataTable({ { 'visible': false, 'targets': 3 } ].concat($.fn.dataTable.defaults.columnDefs), 'rowGroup': { + enable: true, dataSrc: 3, startRender: function(rows, group) { diff --git a/public/viewjs/tasks.js b/public/viewjs/tasks.js index 29cdb4e7..0f28445b 100644 --- a/public/viewjs/tasks.js +++ b/public/viewjs/tasks.js @@ -6,6 +6,7 @@ { 'visible': false, 'targets': 3 } ].concat($.fn.dataTable.defaults.columnDefs), 'rowGroup': { + enable: true, dataSrc: 3 } }); diff --git a/routes.php b/routes.php index e101b730..7d39a5ae 100644 --- a/routes.php +++ b/routes.php @@ -175,6 +175,7 @@ $app->group('/api', function (RouteCollectorProxy $group) { $group->get('/user/settings', '\Grocy\Controllers\UsersApiController:GetUserSettings'); $group->get('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:GetUserSetting'); $group->put('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:SetUserSetting'); + $group->delete('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:DeleteUserSetting'); // Stock if (GROCY_FEATURE_FLAG_STOCK) diff --git a/services/UsersService.php b/services/UsersService.php index 2dd4c4f6..3c5e822d 100644 --- a/services/UsersService.php +++ b/services/UsersService.php @@ -114,6 +114,11 @@ class UsersService extends BaseService } } + public function DeleteUserSetting($userId, $settingKey) + { + $this->getDatabase()->user_settings()->where('user_id = :1 AND key = :2', $userId, $settingKey)->delete(); + } + private function UserExists($userId) { $userRow = $this->getDatabase()->users()->where('id = :1', $userId)->fetch(); diff --git a/views/batteries.blade.php b/views/batteries.blade.php index 33f8166d..8f949562 100644 --- a/views/batteries.blade.php +++ b/views/batteries.blade.php @@ -72,7 +72,7 @@ diff --git a/views/batteriesjournal.blade.php b/views/batteriesjournal.blade.php index 4531e259..0e96eacb 100644 --- a/views/batteriesjournal.blade.php +++ b/views/batteriesjournal.blade.php @@ -68,7 +68,7 @@ diff --git a/views/batteriesoverview.blade.php b/views/batteriesoverview.blade.php index 2a05ae9f..03f339f8 100644 --- a/views/batteriesoverview.blade.php +++ b/views/batteriesoverview.blade.php @@ -90,7 +90,7 @@ diff --git a/views/chores.blade.php b/views/chores.blade.php index 553103da..09343c06 100644 --- a/views/chores.blade.php +++ b/views/chores.blade.php @@ -73,7 +73,7 @@ diff --git a/views/choresjournal.blade.php b/views/choresjournal.blade.php index 0c8f0a96..717783fc 100644 --- a/views/choresjournal.blade.php +++ b/views/choresjournal.blade.php @@ -68,7 +68,7 @@ diff --git a/views/choresoverview.blade.php b/views/choresoverview.blade.php index 3c6a79e0..d20605c0 100644 --- a/views/choresoverview.blade.php +++ b/views/choresoverview.blade.php @@ -112,7 +112,7 @@ diff --git a/views/equipment.blade.php b/views/equipment.blade.php index 5ad96c06..ae0067bf 100644 --- a/views/equipment.blade.php +++ b/views/equipment.blade.php @@ -63,7 +63,7 @@ diff --git a/views/layout/default.blade.php b/views/layout/default.blade.php index 173b20f8..9c4d1238 100644 --- a/views/layout/default.blade.php +++ b/views/layout/default.blade.php @@ -65,6 +65,8 @@ rel="stylesheet"> + - - + + + + @@ -746,4 +750,4 @@ @endif - + \ No newline at end of file diff --git a/views/locations.blade.php b/views/locations.blade.php index 82f1d26f..c71b7c3d 100644 --- a/views/locations.blade.php +++ b/views/locations.blade.php @@ -73,7 +73,7 @@ diff --git a/views/manageapikeys.blade.php b/views/manageapikeys.blade.php index 728f1256..783d4996 100644 --- a/views/manageapikeys.blade.php +++ b/views/manageapikeys.blade.php @@ -78,7 +78,7 @@ diff --git a/views/productform.blade.php b/views/productform.blade.php index bdc2d5c7..0c734526 100644 --- a/views/productform.blade.php +++ b/views/productform.blade.php @@ -10,15 +10,11 @@ @push('pageScripts') - - @endpush @push('pageStyles') - @endpush @section('content') @@ -472,7 +468,7 @@ @@ -573,14 +569,14 @@ {{ $__t('Quantity unit from') }} {{ $__t('Quantity unit to') }} {{ $__t('Factor') }} - Hidden group + {{ $__t('Group')}} diff --git a/views/productgroups.blade.php b/views/productgroups.blade.php index 229ca7fc..53c9de16 100644 --- a/views/productgroups.blade.php +++ b/views/productgroups.blade.php @@ -73,7 +73,7 @@ diff --git a/views/products.blade.php b/views/products.blade.php index 7b8f1d65..b60cd1e7 100644 --- a/views/products.blade.php +++ b/views/products.blade.php @@ -102,7 +102,7 @@ diff --git a/views/quantityunitform.blade.php b/views/quantityunitform.blade.php index fdd11da5..0aae953e 100644 --- a/views/quantityunitform.blade.php +++ b/views/quantityunitform.blade.php @@ -128,7 +128,7 @@ diff --git a/views/quantityunits.blade.php b/views/quantityunits.blade.php index 7784ca43..8386c97d 100644 --- a/views/quantityunits.blade.php +++ b/views/quantityunits.blade.php @@ -73,7 +73,7 @@ diff --git a/views/recipeform.blade.php b/views/recipeform.blade.php index ad17f57a..9433d306 100644 --- a/views/recipeform.blade.php +++ b/views/recipeform.blade.php @@ -8,16 +8,6 @@ @section('viewJsName', 'recipeform') -@push('pageScripts') - - -@endpush - -@push('pageStyles') - -@endpush - @section('content')
@@ -149,14 +139,14 @@ {{ $__t('Product') }} {{ $__t('Amount') }} {{ $__t('Note') }} - Hidden ingredient group + {{ $__t('Ingredient group') }} @@ -252,7 +242,7 @@ diff --git a/views/recipes.blade.php b/views/recipes.blade.php index f1963603..f2cfabe9 100644 --- a/views/recipes.blade.php +++ b/views/recipes.blade.php @@ -102,7 +102,7 @@ diff --git a/views/shoppinglist.blade.php b/views/shoppinglist.blade.php index 35b67cbe..7f40cff9 100644 --- a/views/shoppinglist.blade.php +++ b/views/shoppinglist.blade.php @@ -5,16 +5,12 @@ @section('viewJsName', 'shoppinglist') @push('pageScripts') - - @endpush @push('pageStyles') -