Finalize user-defined-fields (closes #176)

This commit is contained in:
Bernd Bestel 2019-04-23 09:06:18 +02:00
parent 72a3f63546
commit c5993ad994
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
25 changed files with 262 additions and 80 deletions

View File

@ -35,3 +35,10 @@ minimum_perc = 0
source_file = localization/en/demo_data.php source_file = localization/en/demo_data.php
source_lang = en source_lang = en
type = PHP_ARRAY type = PHP_ARRAY
[grocy.userfield_typesphp]
file_filter = localization/<lang>/userfield_types.php
minimum_perc = 0
source_file = localization/en/userfield_types.php
source_lang = en
type = PHP_ARRAY

View File

@ -2,13 +2,24 @@
namespace Grocy\Controllers; namespace Grocy\Controllers;
use \Grocy\Services\UserfieldsService;
class EquipmentController extends BaseController class EquipmentController extends BaseController
{ {
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->UserfieldsService = new UserfieldsService();
}
protected $UserfieldsService;
public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
{ {
return $this->AppContainer->view->render($response, 'equipment', [ return $this->AppContainer->view->render($response, 'equipment', [
'equipment' => $this->Database->equipment()->orderBy('name') 'equipment' => $this->Database->equipment()->orderBy('name'),
'userfields' => $this->UserfieldsService->GetFields('equipment'),
'userfieldValues' => $this->UserfieldsService->GetAllValues('equipment')
]); ]);
} }
@ -17,14 +28,16 @@ class EquipmentController extends BaseController
if ($args['equipmentId'] == 'new') if ($args['equipmentId'] == 'new')
{ {
return $this->AppContainer->view->render($response, 'equipmentform', [ return $this->AppContainer->view->render($response, 'equipmentform', [
'mode' => 'create' 'mode' => 'create',
'userfields' => $this->UserfieldsService->GetFields('equipment')
]); ]);
} }
else else
{ {
return $this->AppContainer->view->render($response, 'equipmentform', [ return $this->AppContainer->view->render($response, 'equipmentform', [
'equipment' => $this->Database->equipment($args['equipmentId']), 'equipment' => $this->Database->equipment($args['equipmentId']),
'mode' => 'edit' 'mode' => 'edit',
'userfields' => $this->UserfieldsService->GetFields('equipment')
]); ]);
} }
} }

View File

@ -3,6 +3,7 @@
namespace Grocy\Controllers; namespace Grocy\Controllers;
use \Grocy\Services\RecipesService; use \Grocy\Services\RecipesService;
use \Grocy\Services\UserfieldsService;
class RecipesController extends BaseController class RecipesController extends BaseController
{ {
@ -10,9 +11,11 @@ class RecipesController extends BaseController
{ {
parent::__construct($container); parent::__construct($container);
$this->RecipesService = new RecipesService(); $this->RecipesService = new RecipesService();
$this->UserfieldsService = new UserfieldsService();
} }
protected $RecipesService; protected $RecipesService;
protected $UserfieldsService;
public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
{ {
@ -57,7 +60,9 @@ class RecipesController extends BaseController
'selectedRecipeSubRecipes' => $selectedRecipeSubRecipes, 'selectedRecipeSubRecipes' => $selectedRecipeSubRecipes,
'selectedRecipeSubRecipesPositions' => $selectedRecipeSubRecipesPositions, 'selectedRecipeSubRecipesPositions' => $selectedRecipeSubRecipesPositions,
'includedRecipeIdsAbsolute' => $includedRecipeIdsAbsolute, 'includedRecipeIdsAbsolute' => $includedRecipeIdsAbsolute,
'selectedRecipeTotalCosts' => FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->costs 'selectedRecipeTotalCosts' => FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->costs,
'userfields' => $this->UserfieldsService->GetFields('recipes'),
'userfieldValues' => $this->UserfieldsService->GetAllValues('recipes')
]); ]);
} }
@ -83,7 +88,8 @@ class RecipesController extends BaseController
'recipePositionsResolved' => $this->RecipesService->GetRecipesPosResolved(), 'recipePositionsResolved' => $this->RecipesService->GetRecipesPosResolved(),
'recipesResolved' => $this->RecipesService->GetRecipesResolved(), 'recipesResolved' => $this->RecipesService->GetRecipesResolved(),
'recipes' => $this->Database->recipes()->orderBy('name'), 'recipes' => $this->Database->recipes()->orderBy('name'),
'recipeNestings' => $this->Database->recipes_nestings()->where('recipe_id', $recipeId) 'recipeNestings' => $this->Database->recipes_nestings()->where('recipe_id', $recipeId),
'userfields' => $this->UserfieldsService->GetFields('recipes')
]); ]);
} }

View File

@ -36,7 +36,9 @@ class TasksController extends BaseController
'tasks' => $tasks, 'tasks' => $tasks,
'nextXDays' => $nextXDays, 'nextXDays' => $nextXDays,
'taskCategories' => $this->Database->task_categories()->orderBy('name'), 'taskCategories' => $this->Database->task_categories()->orderBy('name'),
'users' => $this->Database->users() 'users' => $this->Database->users(),
'userfields' => $this->UserfieldsService->GetFields('tasks'),
'userfieldValues' => $this->UserfieldsService->GetAllValues('tasks')
]); ]);
} }

View File

@ -380,5 +380,18 @@ return array(
'Thursday' => 'Thursday', 'Thursday' => 'Thursday',
'Friday' => 'Friday', 'Friday' => 'Friday',
'Saturday' => 'Saturday', 'Saturday' => 'Saturday',
'Sunday' => 'Sunday' 'Sunday' => 'Sunday',
'Configure userfields' => 'Configure userfields',
'Userfields' => 'Userfields',
'Filter by entity' => 'Filter by entity',
'Entity' => 'Entity',
'Caption' => 'Caption',
'Type' => 'Type',
'Create userfield' => 'Create userfield',
'A entity is required' => 'A entity is required',
'A caption is required' => 'A caption is required',
'A type is required' => 'A type is required',
'Show as column in tables' => 'Show as column in tables',
'This is required and can only contain letters and numbers' => 'This is required and can only contain letters and numbers',
'Edit userfield' => 'Edit userfield'
); );

View File

@ -7,7 +7,7 @@ Grocy.Components.UserfieldsForm.Save = function(success, error)
$("#userfields-form .userfield-input").each(function() $("#userfields-form .userfield-input").each(function()
{ {
var input = $(this); var input = $(this);
var fieldName = input.attr("id"); var fieldName = input.attr("data-userfield-name");
var fieldValue = input.val(); var fieldValue = input.val();
if (input.attr("type") == "checkbox") if (input.attr("type") == "checkbox")
@ -49,7 +49,7 @@ Grocy.Components.UserfieldsForm.Load = function()
{ {
$.each(result, function(key, value) $.each(result, function(key, value)
{ {
var input = $("#" + key + ".userfield-input"); var input = $(".userfield-input[data-userfield-name='" + key + "']");
if (input.attr("type") == "checkbox" && value == 1) if (input.attr("type") == "checkbox" && value == 1)
{ {

View File

@ -21,24 +21,28 @@
Grocy.Api.Post('objects/equipment', jsonData, Grocy.Api.Post('objects/equipment', jsonData,
function(result) function(result)
{ {
if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave) Grocy.EditObjectId = result.created_object_id;
Grocy.Components.UserfieldsForm.Save(function()
{ {
Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name, if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave)
function(result) {
{ Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name,
window.location.href = U('/equipment'); function (result)
}, {
function(xhr) window.location.href = U('/equipment');
{ },
Grocy.FrontendHelpers.EndUiBusy("equipment-form"); function (xhr)
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) {
} Grocy.FrontendHelpers.EndUiBusy("equipment-form");
); Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
} }
else );
{ }
window.location.href = U('/equipment'); else
} {
window.location.href = U('/equipment');
}
});
}, },
function(xhr) function(xhr)
{ {
@ -67,24 +71,27 @@
Grocy.Api.Put('objects/equipment/' + Grocy.EditObjectId, jsonData, Grocy.Api.Put('objects/equipment/' + Grocy.EditObjectId, jsonData,
function(result) function(result)
{ {
if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave) Grocy.Components.UserfieldsForm.Save(function()
{ {
Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name, if (jsonData.hasOwnProperty("instruction_manual_file_name") && !Grocy.DeleteInstructionManualOnSave)
function(result) {
{ Grocy.Api.UploadFile($("#instruction-manual")[0].files[0], 'equipmentmanuals', jsonData.instruction_manual_file_name,
window.location.href = U('/equipment');; function(result)
}, {
function(xhr) window.location.href = U('/equipment');;
{ },
Grocy.FrontendHelpers.EndUiBusy("equipment-form"); function(xhr)
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) {
} Grocy.FrontendHelpers.EndUiBusy("equipment-form");
); Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
} }
else );
{ }
window.location.href = U('/equipment');; else
} {
window.location.href = U('/equipment');;
}
});
}, },
function(xhr) function(xhr)
{ {
@ -133,5 +140,6 @@ $('#description').summernote({
ResizeResponsiveEmbeds(); ResizeResponsiveEmbeds();
Grocy.Components.UserfieldsForm.Load();
$('#name').focus(); $('#name').focus();
Grocy.FrontendHelpers.ValidateForm('equipment-form'); Grocy.FrontendHelpers.ValidateForm('equipment-form');

View File

@ -31,24 +31,27 @@
Grocy.Api.Put('objects/recipes/' + Grocy.EditObjectId, jsonData, Grocy.Api.Put('objects/recipes/' + Grocy.EditObjectId, jsonData,
function(result) function(result)
{ {
if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteRecipePictureOnSave) Grocy.Components.UserfieldsForm.Save(function()
{ {
Grocy.Api.UploadFile($("#recipe-picture")[0].files[0], 'recipepictures', jsonData.picture_file_name, if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteRecipePictureOnSave)
function(result) {
{ Grocy.Api.UploadFile($("#recipe-picture")[0].files[0], 'recipepictures', jsonData.picture_file_name,
window.location.href = U('/recipes?recipe=' + Grocy.EditObjectId); function (result)
}, {
function (xhr) window.location.href = U('/recipes?recipe=' + Grocy.EditObjectId);
{ },
Grocy.FrontendHelpers.EndUiBusy("recipe-form"); function (xhr)
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) {
} Grocy.FrontendHelpers.EndUiBusy("recipe-form");
); Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
} }
else );
{ }
window.location.href = U('/recipes?recipe=' + Grocy.EditObjectId); else
} {
window.location.href = U('/recipes?recipe=' + Grocy.EditObjectId);
}
});
}, },
function(xhr) function(xhr)
{ {
@ -345,3 +348,5 @@ $('#description').summernote({
minHeight: '300px', minHeight: '300px',
lang: L('summernote_locale') lang: L('summernote_locale')
}); });
Grocy.Components.UserfieldsForm.Load();

View File

@ -14,7 +14,11 @@
Grocy.Api.Post('objects/tasks', jsonData, Grocy.Api.Post('objects/tasks', jsonData,
function(result) function(result)
{ {
window.location.href = U('/tasks'); Grocy.EditObjectId = result.created_object_id;
Grocy.Components.UserfieldsForm.Save(function()
{
window.location.href = U('/tasks');
});
}, },
function(xhr) function(xhr)
{ {
@ -28,7 +32,10 @@
Grocy.Api.Put('objects/tasks/' + Grocy.EditObjectId, jsonData, Grocy.Api.Put('objects/tasks/' + Grocy.EditObjectId, jsonData,
function(result) function(result)
{ {
window.location.href = U('/tasks'); Grocy.Components.UserfieldsForm.Save(function()
{
window.location.href = U('/tasks');
});
}, },
function(xhr) function(xhr)
{ {
@ -61,6 +68,7 @@ $('#task-form input').keydown(function(event)
} }
}); });
Grocy.Components.UserfieldsForm.Load();
$('#name').focus(); $('#name').focus();
Grocy.Components.DateTimePicker.GetInputElement().trigger('input'); Grocy.Components.DateTimePicker.GetInputElement().trigger('input');
Grocy.FrontendHelpers.ValidateForm('task-form'); Grocy.FrontendHelpers.ValidateForm('task-form');

View File

@ -5,12 +5,18 @@
var jsonData = $('#userfield-form').serializeJSON(); var jsonData = $('#userfield-form').serializeJSON();
Grocy.FrontendHelpers.BeginUiBusy("userfield-form"); Grocy.FrontendHelpers.BeginUiBusy("userfield-form");
var redirectUrl = U("/userfields");
if (typeof GetUriParam("entity") !== "undefined" && !GetUriParam("entity").isEmpty())
{
redirectUrl = U("/userfields?entity=" + GetUriParam("entity"));
}
if (Grocy.EditMode === 'create') if (Grocy.EditMode === 'create')
{ {
Grocy.Api.Post('objects/userfields', jsonData, Grocy.Api.Post('objects/userfields', jsonData,
function(result) function(result)
{ {
window.location.href = U('/userfields'); window.location.href = redirectUrl;
}, },
function(xhr) function(xhr)
{ {
@ -24,7 +30,7 @@
Grocy.Api.Put('objects/userfields/' + Grocy.EditObjectId, jsonData, Grocy.Api.Put('objects/userfields/' + Grocy.EditObjectId, jsonData,
function(result) function(result)
{ {
window.location.href = U('/userfields'); window.location.href = redirectUrl;
}, },
function(xhr) function(xhr)
{ {
@ -64,7 +70,7 @@ $('#userfield-form input').keydown(function(event)
$('#entity').focus(); $('#entity').focus();
if (typeof GetUriParam("entity") !== "undefined") if (typeof GetUriParam("entity") !== "undefined" && !GetUriParam("entity").isEmpty())
{ {
$("#entity").val(GetUriParam("entity")); $("#entity").val(GetUriParam("entity"));
$("#entity").trigger("change"); $("#entity").trigger("change");

View File

@ -41,6 +41,7 @@ $("#entity-filter").on("change", function()
} }
userfieldsTable.column(1).search(value).draw(); userfieldsTable.column(1).search(value).draw();
$("#new-userfield-button").attr("href", U("/userfield/new?entity=" + value));
}); });
$(document).on('click', '.userfield-delete-button', function (e) $(document).on('click', '.userfield-delete-button', function (e)
@ -79,7 +80,7 @@ $(document).on('click', '.userfield-delete-button', function (e)
}); });
}); });
if (typeof GetUriParam("entity") !== "undefined") if (typeof GetUriParam("entity") !== "undefined" && !GetUriParam("entity").isEmpty())
{ {
$("#entity-filter").val(GetUriParam("entity")); $("#entity-filter").val(GetUriParam("entity"));
$("#entity-filter").trigger("change"); $("#entity-filter").trigger("change");

View File

@ -6,6 +6,13 @@
@php if(!isset($initialValue)) { $initialValue = ''; } @endphp @php if(!isset($initialValue)) { $initialValue = ''; } @endphp
@php if(empty($earlierThanInfoLimit)) { $earlierThanInfoLimit = ''; } @endphp @php if(empty($earlierThanInfoLimit)) { $earlierThanInfoLimit = ''; } @endphp
@php if(empty($earlierThanInfoText)) { $earlierThanInfoText = ''; } @endphp @php if(empty($earlierThanInfoText)) { $earlierThanInfoText = ''; } @endphp
@php if(empty($additionalCssClasses)) { $additionalCssClasses = ''; } @endphp
@php if(empty($additionalGroupCssClasses)) { $additionalGroupCssClasses = ''; } @endphp
@php if(empty($invalidFeedback)) { $invalidFeedback = ''; } @endphp
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
@php if(!isset($nextInputSelector)) { $nextInputSelector = false; } @endphp
@php if(empty($additionalAttributes)) { $additionalAttributes = ''; } @endphp
<div class="form-group"> <div class="form-group">
<label for="{{ $id }}">{{ $L($label) }} <label for="{{ $id }}">{{ $L($label) }}
@ -15,8 +22,8 @@
</span> </span>
</label> </label>
<div class="input-group"> <div class="input-group">
<div class="input-group date datetimepicker @if(!empty($additionalCssClasses)){{ $additionalCssClasses }}@endif" id="{{ $id }}" data-target-input="nearest"> <div class="input-group date datetimepicker @if(!empty($additionalGroupCssClasses)){{ $additionalGroupCssClasses }}@endif" id="{{ $id }}" @if(!$noNameAttribute) name="{{ $id }}" @endif data-target-input="nearest">
<input type="text" @if($isRequired) required @endif class="form-control datetimepicker-input" <input {!! $additionalAttributes !!} type="text" @if($isRequired) @if($isRequired) required @endif @endif class="form-control datetimepicker-input @if(!empty($additionalCssClasses)){{ $additionalCssClasses }}@endif"
data-target="#{{ $id }}" data-format="{{ $format }}" data-target="#{{ $id }}" data-format="{{ $format }}"
data-init-with-now="{{ BoolToString($initWithNow) }}" data-init-with-now="{{ BoolToString($initWithNow) }}"
data-init-value="{{ $initialValue }}" data-init-value="{{ $initialValue }}"

View File

@ -14,11 +14,12 @@
@php if(empty($additionalHtmlElements)) { $additionalHtmlElements = ''; } @endphp @php if(empty($additionalHtmlElements)) { $additionalHtmlElements = ''; } @endphp
@php if(empty($additionalHtmlContextHelp)) { $additionalHtmlContextHelp = ''; } @endphp @php if(empty($additionalHtmlContextHelp)) { $additionalHtmlContextHelp = ''; } @endphp
@php if(!isset($isRequired)) { $isRequired = true; } @endphp @php if(!isset($isRequired)) { $isRequired = true; } @endphp
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
<div class="form-group {{ $additionalGroupCssClasses }}"> <div class="form-group {{ $additionalGroupCssClasses }}">
<label for="{{ $id }}">{{ $L($label) }}&nbsp;&nbsp;<span id="{{ $hintId }}" class="small text-muted">{{ $hint }}</span>{!! $additionalHtmlContextHelp !!}</label> <label for="{{ $id }}">{{ $L($label) }}&nbsp;&nbsp;<span id="{{ $hintId }}" class="small text-muted">{{ $hint }}</span>{!! $additionalHtmlContextHelp !!}</label>
<div class="input-group"> <div class="input-group">
<input {!! $additionalAttributes !!} type="number" class="form-control numberpicker {{ $additionalCssClasses }}" id="{{ $id }}" name="{{ $id }}" value="{{ $value }}" min="{{ $min }}" max="{{ $max }}" step="{{ $step }}" @if($isRequired) required @endif> <input {!! $additionalAttributes !!} type="number" class="form-control numberpicker {{ $additionalCssClasses }}" id="{{ $id }}" @if(!$noNameAttribute) name="{{ $id }}" @endif value="{{ $value }}" min="{{ $min }}" max="{{ $max }}" step="{{ $step }}" @if($isRequired) required @endif>
<div class="input-group-append"> <div class="input-group-append">
<div class="input-group-text numberpicker-up-button"><i class="fas fa-arrow-up"></i></div> <div class="input-group-text numberpicker-up-button"><i class="fas fa-arrow-up"></i></div>
</div> </div>

View File

@ -7,7 +7,7 @@
@foreach($userfields as $userfield) @foreach($userfields as $userfield)
@if($userfield->show_as_column_in_tables == 1) @if($userfield->show_as_column_in_tables == 1)
<th>{{ $userfield->name }}</th> <th>{{ $userfield->caption }}</th>
@endif @endif
@endforeach @endforeach

View File

@ -12,14 +12,65 @@
@if($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_SINGLE_LINE_TEXT) @if($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_SINGLE_LINE_TEXT)
<div class="form-group"> <div class="form-group">
<label for="name">{{ $userfield->caption }}</label> <label for="name">{{ $userfield->caption }}</label>
<input type="text" class="form-control userfield-input" id="{{ $userfield->name }}" value=""> <input type="text" class="form-control userfield-input" data-userfield-name="{{ $userfield->name }}">
</div> </div>
@endif @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_SINGLE_MULTILINE_TEXT)
<div class="form-group">
@if($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_CHECKBOX) <label for="description">{{ $userfield->caption }}</label>
<textarea class="form-control userfield-input" rows="4" data-userfield-name="{{ $userfield->name }}"></textarea>
</div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_INTEGRAL_NUMBER)
@include('components.numberpicker', array(
'id' => $userfield->name,
'label' => $userfield->caption,
'noNameAttribute' => true,
'min' => 0,
'isRequired' => false,
'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
))
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_DECIMAL_NUMBER)
@include('components.numberpicker', array(
'id' => '',
'label' => $userfield->caption,
'noNameAttribute' => true,
'min' => 0,
'step' => 0.01,
'isRequired' => false,
'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
))
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_DATE)
@include('components.datetimepicker', array(
'id' => $userfield->name,
'label' => $userfield->caption,
'noNameAttribute' => true,
'format' => 'YYYY-MM-DD',
'initWithNow' => false,
'limitEndToNow' => false,
'limitStartToNow' => false,
'additionalGroupCssClasses' => 'date-only-datetimepicker',
'isRequired' => false,
'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
))
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_DATETIME)
@include('components.datetimepicker', array(
'id' => $userfield->name,
'label' => $userfield->caption,
'noNameAttribute' => true,
'format' => 'YYYY-MM-DD HH:mm:ss',
'initWithNow' => false,
'limitEndToNow' => false,
'limitStartToNow' => false,
'isRequired' => false,
'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
))
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_CHECKBOX)
<div class="form-group"> <div class="form-group">
<div class="form-check"> <div class="form-check">
<input class="form-check-input userfield-input" type="checkbox" id="{{ $userfield->name }}" value="1"> <input class="form-check-input userfield-input" type="checkbox" data-userfield-name="{{ $userfield->name }}" value="1">
<label class="form-check-label" for="{{ $userfield->name }}">{{ $userfield->caption }}</label> <label class="form-check-label" for="{{ $userfield->name }}">{{ $userfield->caption }}</label>
</div> </div>
</div> </div>

View File

@ -22,6 +22,11 @@
<thead> <thead>
<tr> <tr>
<th>{{ $L('Name') }}</th> <th>{{ $L('Name') }}</th>
@include('components.userfields_thead', array(
'userfields' => $userfields
))
</tr> </tr>
</thead> </thead>
<tbody class="d-none"> <tbody class="d-none">
@ -30,6 +35,12 @@
<td> <td>
{{ $equipmentItem->name }} {{ $equipmentItem->name }}
</td> </td>
@include('components.userfields_tbody', array(
'userfields' => $userfields,
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $equipmentItem->id)
))
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>

View File

@ -56,6 +56,11 @@
<textarea class="form-control" id="description" name="description">@if($mode == 'edit'){{ $equipment->description }}@endif</textarea> <textarea class="form-control" id="description" name="description">@if($mode == 'edit'){{ $equipment->description }}@endif</textarea>
</div> </div>
@include('components.userfieldsform', array(
'userfields' => $userfields,
'entity' => 'equipment'
))
<button id="save-equipment-button" class="btn btn-success">{{ $L('Save') }}</button> <button id="save-equipment-button" class="btn btn-success">{{ $L('Save') }}</button>
</form> </form>

View File

@ -38,7 +38,7 @@
'limitStartToNow' => false, 'limitStartToNow' => false,
'invalidFeedback' => $L('A best before date is required'), 'invalidFeedback' => $L('A best before date is required'),
'nextInputSelector' => '#best_before_date', 'nextInputSelector' => '#best_before_date',
'additionalCssClasses' => 'date-only-datetimepicker', 'additionalGroupCssClasses' => 'date-only-datetimepicker',
'shortcutValue' => '2999-12-31', 'shortcutValue' => '2999-12-31',
'shortcutLabel' => 'Never expires', 'shortcutLabel' => 'Never expires',
'earlierThanInfoLimit' => date('Y-m-d'), 'earlierThanInfoLimit' => date('Y-m-d'),

View File

@ -226,6 +226,12 @@
</a> </a>
</li> </li>
@endif @endif
<li data-nav-for-page="userfields" data-sub-menu-of="#top-nav-manager-master-data">
<a class="nav-link discrete-link" href="{{ $U('/userfields') }}">
<i class="fas fa-bookmark "></i>
<span class="nav-link-text">{{ $L('Userfields') }}</span>
</a>
</li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -82,6 +82,11 @@
</div> </div>
</div> </div>
@include('components.userfieldsform', array(
'userfields' => $userfields,
'entity' => 'recipes'
))
<button id="save-recipe-button" class="btn btn-success">{{ $L('Save') }}</button> <button id="save-recipe-button" class="btn btn-success">{{ $L('Save') }}</button>
</form> </form>

View File

@ -37,6 +37,11 @@
<th>{{ $L('Servings') }}</th> <th>{{ $L('Servings') }}</th>
<th>{{ $L('Requirements fulfilled') }}</th> <th>{{ $L('Requirements fulfilled') }}</th>
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th> <th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
@include('components.userfields_thead', array(
'userfields' => $userfields
))
</tr> </tr>
</thead> </thead>
<tbody class="d-none"> <tbody class="d-none">
@ -55,6 +60,12 @@
<td class="d-none"> <td class="d-none">
{{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }} {{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }}
</td> </td>
@include('components.userfields_tbody', array(
'userfields' => $userfields,
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $recipe->id)
))
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>

View File

@ -49,7 +49,7 @@
'limitStartToNow' => false, 'limitStartToNow' => false,
'invalidFeedback' => $L('A due date is required'), 'invalidFeedback' => $L('A due date is required'),
'nextInputSelector' => 'category_id', 'nextInputSelector' => 'category_id',
'additionalCssClasses' => 'date-only-datetimepicker', 'additionalGroupCssClasses' => 'date-only-datetimepicker',
'isRequired' => false 'isRequired' => false
)) ))
@ -76,6 +76,11 @@
'prefillByUserId' => $initUserId 'prefillByUserId' => $initUserId
)) ))
@include('components.userfieldsform', array(
'userfields' => $userfields,
'entity' => 'tasks'
))
<button id="save-task-button" class="btn btn-success">{{ $L('Save') }}</button> <button id="save-task-button" class="btn btn-success">{{ $L('Save') }}</button>
</form> </form>

View File

@ -62,6 +62,11 @@
<th class="d-none">Hidden category</th> <th class="d-none">Hidden category</th>
<th>{{ $L('Assigned to') }}</th> <th>{{ $L('Assigned to') }}</th>
<th class="d-none">Hidden status</th> <th class="d-none">Hidden status</th>
@include('components.userfields_thead', array(
'userfields' => $userfields
))
</tr> </tr>
</thead> </thead>
<tbody class="d-none"> <tbody class="d-none">
@ -98,6 +103,12 @@
<td class="d-none"> <td class="d-none">
@if($task->done == 1) text-muted @endif @if(!empty($task->due_date) && $task->due_date < date('Y-m-d')) overdue @elseif(!empty($task->due_date) && $task->due_date < date('Y-m-d', strtotime("+$nextXDays days"))) duesoon @endif @if($task->done == 1) text-muted @endif @if(!empty($task->due_date) && $task->due_date < date('Y-m-d')) overdue @elseif(!empty($task->due_date) && $task->due_date < date('Y-m-d', strtotime("+$nextXDays days"))) duesoon @endif
</td> </td>
@include('components.userfields_tbody', array(
'userfields' => $userfields,
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $task->id)
))
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>

View File

@ -34,8 +34,8 @@
<div class="form-group"> <div class="form-group">
<label for="name">{{ $L('Name') }}</label> <label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $userfield->name }}@endif"> <input type="text" class="form-control" required pattern="^[a-zA-Z0-9]*$" id="name" name="name" value="@if($mode == 'edit'){{ $userfield->name }}@endif">
<div class="invalid-feedback">{{ $L('A name is required') }}</div> <div class="invalid-feedback">{{ $L('This is required and can only contain letters and numbers') }}</div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -9,7 +9,7 @@
<div class="col"> <div class="col">
<h1> <h1>
@yield('title') @yield('title')
<a class="btn btn-outline-dark" href="{{ $U('/userfield/new') }}"> <a id="new-userfield-button" class="btn btn-outline-dark" href="{{ $U('/userfield/new') }}">
<i class="fas fa-plus"></i>&nbsp;{{ $L('Add') }} <i class="fas fa-plus"></i>&nbsp;{{ $L('Add') }}
</a> </a>
</h1> </h1>