Add an option to make Userfields mandatory (closes #1339)

This commit is contained in:
Bernd Bestel 2021-07-11 22:05:08 +02:00
parent 21c221b520
commit 6659a5cd08
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
6 changed files with 74 additions and 15 deletions

View File

@ -76,7 +76,8 @@
- => The on chore execution tracking entered information is then visible on the corresponding chore journal entry - => The on chore execution tracking entered information is then visible on the corresponding chore journal entry
- Fixed that tracking chores with "Done by" a different user was not possible - Fixed that tracking chores with "Done by" a different user was not possible
### Userfield fixes ### Userfield improvements/fixes
- Userfields can now be configured as mandatory (new Userfield option, defaults to disabled)
- Fixed that numeric Userfields were initialised with `1.0` - Fixed that numeric Userfields were initialised with `1.0`
- Fixed that shortcuts (up/down key) and the format did not work correctly when using multiple date/time Userfields per object - Fixed that shortcuts (up/down key) and the format did not work correctly when using multiple date/time Userfields per object
- Fixed that Userfields were not saved when adding a product or a recipe (only on editing) - Fixed that Userfields were not saved when adding a product or a recipe (only on editing)

View File

@ -2157,3 +2157,12 @@ msgstr ""
msgid "Mark this item as undone" msgid "Mark this item as undone"
msgstr "" msgstr ""
msgid "Mandatory"
msgstr ""
msgid "Mandatory Userfield"
msgstr ""
msgid "When enabled, then this field must be filled on the destination form"
msgstr ""

2
migrations/0145.sql Normal file
View File

@ -0,0 +1,2 @@
ALTER TABLE userfields
ADD input_required TINYINT NOT NULL DEFAULT 0 CHECK(input_required IN (0, 1));

View File

@ -158,6 +158,11 @@ Grocy.Components.UserfieldsForm.Load = function()
input.val(value); input.val(value);
} }
}); });
$("form").each(function()
{
Grocy.FrontendHelpers.ValidateForm(this.id);
});
}, },
function(xhr) function(xhr)
{ {
@ -179,3 +184,11 @@ $(".userfield-link").keyup(function(e)
formRow.find(".userfield-input").val(JSON.stringify(value)); formRow.find(".userfield-input").val(JSON.stringify(value));
}); });
$(".userfield-input").change(function(e)
{
$("form").each(function()
{
Grocy.FrontendHelpers.ValidateForm(this.id);
});
});

View File

@ -19,14 +19,18 @@
<label>{{ $userfield->caption }}</label> <label>{{ $userfield->caption }}</label>
<input type="text" <input type="text"
class="form-control userfield-input" class="form-control userfield-input"
data-userfield-name="{{ $userfield->name }}"> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_SINGLE_MULTILINE_TEXT) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_SINGLE_MULTILINE_TEXT)
<div class="form-group"> <div class="form-group">
<label for="description">{{ $userfield->caption }}</label> <label for="description">{{ $userfield->caption }}</label>
<textarea class="form-control userfield-input" <textarea class="form-control userfield-input"
rows="4" rows="4"
data-userfield-name="{{ $userfield->name }}"></textarea> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif></textarea>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_INTEGRAL_NUMBER) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_INTEGRAL_NUMBER)
@include('components.numberpicker', array( @include('components.numberpicker', array(
@ -34,7 +38,7 @@
'label' => $userfield->caption, 'label' => $userfield->caption,
'noNameAttribute' => true, 'noNameAttribute' => true,
'min' => 0, 'min' => 0,
'isRequired' => false, 'isRequired' => $userfield->input_required == 1,
'additionalCssClasses' => 'userfield-input', 'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"', 'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"',
'value' => '' 'value' => ''
@ -46,7 +50,7 @@
'noNameAttribute' => true, 'noNameAttribute' => true,
'min' => 0, 'min' => 0,
'decimals' => 4, 'decimals' => 4,
'isRequired' => false, 'isRequired' => $userfield->input_required == 1,
'additionalCssClasses' => 'userfield-input', 'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"', 'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"',
'value' => '' 'value' => ''
@ -61,7 +65,7 @@
'limitEndToNow' => false, 'limitEndToNow' => false,
'limitStartToNow' => false, 'limitStartToNow' => false,
'additionalGroupCssClasses' => 'date-only-datetimepicker', 'additionalGroupCssClasses' => 'date-only-datetimepicker',
'isRequired' => false, 'isRequired' => $userfield->input_required == 1,
'additionalCssClasses' => 'userfield-input', 'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"' 'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
)) ))
@ -74,7 +78,7 @@
'initWithNow' => false, 'initWithNow' => false,
'limitEndToNow' => false, 'limitEndToNow' => false,
'limitStartToNow' => false, 'limitStartToNow' => false,
'isRequired' => false, 'isRequired' => $userfield->input_required == 1,
'additionalCssClasses' => 'userfield-input', 'additionalCssClasses' => 'userfield-input',
'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"' 'additionalAttributes' => 'data-userfield-name="' . $userfield->name . '"'
)) ))
@ -85,21 +89,25 @@
type="checkbox" type="checkbox"
id="userfield-{{ $userfield->name }}" id="userfield-{{ $userfield->name }}"
data-userfield-name="{{ $userfield->name }}" data-userfield-name="{{ $userfield->name }}"
value="1"> value="1"
@if($userfield->input_required == 1) required @endif>
<label class="form-check-label custom-control-label" <label class="form-check-label custom-control-label"
for="userfield-{{ $userfield->name }}">{{ $userfield->caption }}</label> for="userfield-{{ $userfield->name }}">{{ $userfield->caption }}</label>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_PRESET_LIST) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_PRESET_LIST)
<div class="form-group"> <div class="form-group">
<label for="{{ $userfield->name }}">{{ $userfield->caption }}</label> <label for="{{ $userfield->name }}">{{ $userfield->caption }}</label>
<select class="custom-control custom-select userfield-input" <select class="custom-control custom-select userfield-input"
data-userfield-name="{{ $userfield->name }}"> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif>
<option></option> <option></option>
@foreach(preg_split('/\r\n|\r|\n/', $userfield->config) as $option) @foreach(preg_split('/\r\n|\r|\n/', $userfield->config) as $option)
<option value="{{ $option }}">{{ $option }}</option> <option value="{{ $option }}">{{ $option }}</option>
@endforeach @endforeach
</select> </select>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_PRESET_CHECKLIST) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_PRESET_CHECKLIST)
<div class="form-group"> <div class="form-group">
@ -108,18 +116,21 @@
class="form-control userfield-input selectpicker" class="form-control userfield-input selectpicker"
data-userfield-name="{{ $userfield->name }}" data-userfield-name="{{ $userfield->name }}"
data-actions-Box="true" data-actions-Box="true"
data-live-search="true"> data-live-search="true"
@if($userfield->input_required == 1) required @endif>
@foreach(preg_split('/\r\n|\r|\n/', $userfield->config) as $option) @foreach(preg_split('/\r\n|\r|\n/', $userfield->config) as $option)
<option value="{{ $option }}">{{ $option }}</option> <option value="{{ $option }}">{{ $option }}</option>
@endforeach @endforeach
</select> </select>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_LINK) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_LINK)
<div class="form-group"> <div class="form-group">
<label>{{ $userfield->caption }}</label> <label>{{ $userfield->caption }}</label>
<input type="link" <input type="link"
class="form-control userfield-input" class="form-control userfield-input"
data-userfield-name="{{ $userfield->name }}"> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif>
</div> </div>
@elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_LINK_WITH_TITLE) @elseif($userfield->type == \Grocy\Services\UserfieldsService::USERFIELD_TYPE_LINK_WITH_TITLE)
<div class="form-group"> <div class="form-group">
@ -128,13 +139,16 @@
<div class="col-4"> <div class="col-4">
<input type="text" <input type="text"
class="form-control userfield-link userfield-link-title" class="form-control userfield-link userfield-link-title"
placeholder="{{ $__t('Title') }}"> placeholder="{{ $__t('Title') }}"
@if($userfield->input_required == 1) required @endif>
</div> </div>
<div class="col-8"> <div class="col-8">
<input type="link" <input type="link"
class="form-control userfield-link userfield-link-link" class="form-control userfield-link userfield-link-link"
placeholder="{{ $__t('Link') }}"> placeholder="{{ $__t('Link') }}"
@if($userfield->input_required == 1) required @endif>
</div> </div>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
<input data-userfield-type="link" <input data-userfield-type="link"
type="hidden" type="hidden"
class="userfield-input" class="userfield-input"
@ -148,11 +162,13 @@
<div class="custom-file"> <div class="custom-file">
<input type="file" <input type="file"
class="custom-file-input userfield-input" class="custom-file-input userfield-input"
data-userfield-name="{{ $userfield->name }}"> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif>
<label class="custom-file-label" <label class="custom-file-label"
for="{{ $userfield->name }}"> for="{{ $userfield->name }}">
{{ $__t('No file selected') }} {{ $__t('No file selected') }}
</label> </label>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
<div class="input-group-append userfield-file-delete"> <div class="input-group-append userfield-file-delete">
<span class="input-group-text"><i class="fas fa-trash"></i></span> <span class="input-group-text"><i class="fas fa-trash"></i></span>
@ -171,11 +187,13 @@
<div class="custom-file"> <div class="custom-file">
<input type="file" <input type="file"
class="custom-file-input userfield-input" class="custom-file-input userfield-input"
data-userfield-name="{{ $userfield->name }}"> data-userfield-name="{{ $userfield->name }}"
@if($userfield->input_required == 1) required @endif>
<label class="custom-file-label" <label class="custom-file-label"
for="{{ $userfield->name }}"> for="{{ $userfield->name }}">
{{ $__t('No file selected') }} {{ $__t('No file selected') }}
</label> </label>
<div class="invalid-feedback">{{ $__t('Mandatory Userfield') }}</div>
</div> </div>
<div class="input-group-append userfield-file-delete"> <div class="input-group-append userfield-file-delete">
<span class="input-group-text"><i class="fas fa-trash"></i></span> <span class="input-group-text"><i class="fas fa-trash"></i></span>

View File

@ -128,6 +128,22 @@
</div> </div>
</div> </div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input @if($mode=='edit'
&&
$userfield->input_required == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="input_required" name="input_required" value="1">
<label class="form-check-label custom-control-label"
for="input_required">
{{ $__t('Mandatory') }}
&nbsp;<i class="fas fa-question-circle text-muted"
data-toggle="tooltip"
data-trigger="hover click"
title="{{ $__t('When enabled, then this field must be filled on the destination form') }}"></i>
</label>
</div>
</div>
<button id="save-userfield-button" <button id="save-userfield-button"
class="btn btn-success">{{ $__t('Save') }}</button> class="btn btn-success">{{ $__t('Save') }}</button>