diff --git a/controllers/EquipmentController.php b/controllers/EquipmentController.php new file mode 100644 index 00000000..a5804a5a --- /dev/null +++ b/controllers/EquipmentController.php @@ -0,0 +1,31 @@ +AppContainer->view->render($response, 'equipment', [ + 'equipment' => $this->Database->equipment()->orderBy('name') + ]); + } + + public function EditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + if ($args['equipmentId'] == 'new') + { + return $this->AppContainer->view->render($response, 'equipmentform', [ + 'mode' => 'create' + ]); + } + else + { + return $this->AppContainer->view->render($response, 'equipmentform', [ + 'equipment' => $this->Database->equipment($args['equipmentId']), + 'mode' => 'edit' + ]); + } + } +} diff --git a/grocy.openapi.json b/grocy.openapi.json index 59ee8cb4..4ab5c640 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -1677,7 +1677,8 @@ "recipes_pos", "tasks", "task_categories", - "product_groups" + "product_groups", + "equipment" ] }, "StockTransactionType": { diff --git a/migrations/0041.sql b/migrations/0041.sql new file mode 100644 index 00000000..78f3afec --- /dev/null +++ b/migrations/0041.sql @@ -0,0 +1,7 @@ +CREATE TABLE equipment ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, + name TEXT NOT NULL UNIQUE, + description TEXT, + instruction_manual_file_name TEXT, + row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime')) +) diff --git a/public/viewjs/equipment.js b/public/viewjs/equipment.js new file mode 100644 index 00000000..cfdec472 --- /dev/null +++ b/public/viewjs/equipment.js @@ -0,0 +1,81 @@ +var equipmentTable = $('#equipment-table').DataTable({ + 'paginate': false, + 'order': [[1, 'asc']], + 'columnDefs': [ + { 'orderable': false, 'targets': 0 } + ], + 'language': JSON.parse(L('datatables_localization')), + 'scrollY': false, + 'colReorder': true, + 'stateSave': true, + 'stateSaveParams': function(settings, data) + { + data.search.search = ""; + + data.columns.forEach(column => + { + column.search.search = ""; + }); + }, + 'select': 'single', + 'initComplete': function() + { + this.api().row({ order: 'current' }, 0).select(); + } +}); + +equipmentTable.on('select', function(e, dt, type, indexes) +{ + if (type === 'row') + { + var selectedEquipmentId = $(equipmentTable.row(indexes[0]).node()).data("equipment-id"); + console.log(selectedEquipmentId); + } +}); + +$("#search").on("keyup", function() +{ + var value = $(this).val(); + if (value === "all") + { + value = ""; + } + + equipmentTable.search(value).draw(); +}); + +$(document).on('click', '.equipment-delete-button', function (e) +{ + var objectName = $(e.currentTarget).attr('data-equipment-name'); + var objectId = $(e.currentTarget).attr('data-equipment-id'); + + bootbox.confirm({ + message: L('Are you sure to delete equipment "#1"?', objectName), + buttons: { + confirm: { + label: L('Yes'), + className: 'btn-success' + }, + cancel: { + label: L('No'), + className: 'btn-danger' + } + }, + callback: function(result) + { + if (result === true) + { + Grocy.Api.Get('delete-object/equipment/' + objectId, + function(result) + { + window.location.href = U('/equipment'); + }, + function(xhr) + { + console.error(xhr); + } + ); + } + } + }); +}); diff --git a/public/viewjs/equipmentform.js b/public/viewjs/equipmentform.js new file mode 100644 index 00000000..65cf405b --- /dev/null +++ b/public/viewjs/equipmentform.js @@ -0,0 +1,123 @@ +$('#save-equipment-button').on('click', function(e) +{ + e.preventDefault(); + + var jsonData = $('#equipment-form').serializeJSON(); + if ($("#instruction-manual")[0].files.length > 0) + { + var someRandomStuff = Math.random().toString(36).substring(2, 100) + Math.random().toString(36).substring(2, 100); + jsonData.instruction_manual_file_name = someRandomStuff + $("#instruction-manual")[0].files[0].name; + } + + if (Grocy.DeleteInstructionManualOnSave) + { + jsonData.instruction_manual_file_name = null; + } + + if (Grocy.EditMode === 'create') + { + Grocy.Api.Post('add-object/equipment', jsonData, + function(result) + { + if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave) + { + Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name, + function(result) + { + window.location.href = U('/equipment'); + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } + else + { + window.location.href = U('/equipment'); + } + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } + else + { + if (Grocy.DeleteInstructionManualOnSave) + { + Grocy.Api.DeleteFile(Grocy.InstructionManualFileNameName, 'equipmentmanuals', + function(result) + { + // Nothing to do + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + }; + + Grocy.Api.Post('edit-object/equipment/' + Grocy.EditObjectId, jsonData, + function(result) + { + if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave) + { + Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name, + function(result) + { + window.location.href = U('/equipment');; + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } + else + { + window.location.href = U('/equipment');; + } + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } +}); + +$('#equipment-form input').keyup(function(event) +{ + Grocy.FrontendHelpers.ValidateForm('equipment-form'); +}); + +$('#equipment-form input').keydown(function(event) +{ + if (event.keyCode === 13) //Enter + { + event.preventDefault(); + + if (document.getElementById('equipment-form').checkValidity() === false) //There is at least one validation error + { + return false; + } + else + { + $('#save-equipment-button').click(); + } + } +}); + +Grocy.DeleteInstructionManualOnSave = false; +$('#delete-current-instruction-manual-button').on('click', function (e) +{ + Grocy.DeleteInstructionManualOnSave = true; + //$("#current-instruction-manual").addClass("d-none"); + $("#delete-current-instruction-manual-on-save-hint").removeClass("d-none"); + $("#delete-current-instruction-manual-button").addClass("disabled"); +}); + +$('#name').focus(); +Grocy.FrontendHelpers.ValidateForm('equipment-form'); diff --git a/routes.php b/routes.php index b34fd8a8..4b3cbce7 100644 --- a/routes.php +++ b/routes.php @@ -61,6 +61,10 @@ $app->group('', function() $this->get('/taskcategories', '\Grocy\Controllers\TasksController:TaskCategoriesList'); $this->get('/taskcategory/{categoryId}', '\Grocy\Controllers\TasksController:TaskCategoryEditForm'); + // Equipment routes + $this->get('/equipment', '\Grocy\Controllers\EquipmentController:Overview'); + $this->get('/equipment/{equipmentId}', '\Grocy\Controllers\EquipmentController:EditForm'); + // OpenAPI routes $this->get('/api', '\Grocy\Controllers\OpenApiController:DocumentationUi'); $this->get('/manageapikeys', '\Grocy\Controllers\OpenApiController:ApiKeysList'); diff --git a/services/DemoDataGeneratorService.php b/services/DemoDataGeneratorService.php index 6bb97d06..ac144179 100644 --- a/services/DemoDataGeneratorService.php +++ b/services/DemoDataGeneratorService.php @@ -105,6 +105,9 @@ class DemoDataGeneratorService extends BaseService INSERT INTO tasks (name, due_date, assigned_to_user_id) VALUES ('{$localizationService->Localize('Find a solution for what to do when I forget the door keys')}', date(datetime('now', 'localtime'), '+3 day'), 1); INSERT INTO tasks (name, due_date, assigned_to_user_id) VALUES ('{$localizationService->Localize('Task')}3', date(datetime('now', 'localtime'), '+4 day'), 1); + INSERT INTO equipment (name, description) VALUES ('{$localizationService->Localize('Coffee machine')}', '{$loremIpsum}'); --1 + INSERT INTO equipment (name, description) VALUES ('{$localizationService->Localize('Dishwasher')}', '{$loremIpsum}'); --2 + INSERT INTO migrations (migration) VALUES (-1); "; diff --git a/views/equipment.blade.php b/views/equipment.blade.php new file mode 100644 index 00000000..f00ec448 --- /dev/null +++ b/views/equipment.blade.php @@ -0,0 +1,62 @@ +@extends('layout.default') + +@section('title', $L('Equipment')) +@section('activeNav', 'equipment') +@section('viewJsName', 'equipment') + +@section('content') +
+
+

+ @yield('title') + +  {{ $L('Add') }} + +

+
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + @foreach($equipment as $equipmentItem) + + + + + @endforeach + +
#{{ $L('Name') }}
+ + + + + + + + {{ $equipmentItem->name }} +
+
+ +
+

{{ $L('Instruction manual') }}

+

{{ $L('The selected equipment has no instruction manual') }}

+

TODO: Here the current instruction manual needs to be shown (PDF.js), if any...

+
+
+@stop diff --git a/views/equipmentform.blade.php b/views/equipmentform.blade.php new file mode 100644 index 00000000..5b290cb8 --- /dev/null +++ b/views/equipmentform.blade.php @@ -0,0 +1,65 @@ +@extends('layout.default') + +@if($mode == 'edit') + @section('title', $L('Edit equipment')) +@else + @section('title', $L('Create equipment')) +@endif + +@section('viewJsName', 'equipmentform') + +@section('content') +
+ +
+

@yield('title')

+ + + + @if($mode == 'edit') + + + @if(!empty($equipment->instruction_manual_file_name)) + + @endif + @endif + +
+ +
+ + +
{{ $L('A name is required') }}
+
+ +
+ +
+ + +
+

{{ $L('If you don\'t select a file, the current instruction manual will not be altered') }}

+
+ +
+ + +
+ + + +
+
+ +
+ + + @if(!empty($equipment->instruction_manual_file_name)) +

TODO: Here the current instruction manual needs to be shown (PDF.js), if any...

+

{{ $L('The current instruction manual will be deleted when you save the equipment') }}

+ @else +

{{ $L('No instruction manual') }}

+ @endif +
+
+@stop diff --git a/views/layout/default.blade.php b/views/layout/default.blade.php index 5cd74855..5d6490c2 100644 --- a/views/layout/default.blade.php +++ b/views/layout/default.blade.php @@ -93,6 +93,12 @@ {{ $L('Batteries overview') }} +