Make "nullable" property dependent on visibility field value

hinted-selects
Vitaliy Filippov 2014-06-23 19:57:26 +04:00
parent 6167bfd72f
commit 9d71d573e4
10 changed files with 99 additions and 56 deletions

View File

@ -933,15 +933,16 @@ sub fieldvaluecontrol
if (!$cache->{fieldvaluecontrol})
{
$cache->{fieldvaluecontrol} = $class->dbh->selectall_arrayref(
'SELECT c.*, (CASE WHEN c.value_id=0 THEN f.visibility_field_id ELSE f.value_field_id END) visibility_field_id'.
'SELECT c.*, (CASE WHEN c.value_id <= 0 THEN f.visibility_field_id ELSE f.value_field_id END) visibility_field_id'.
' FROM fieldvaluecontrol c, fielddefs f WHERE f.id=c.field_id'.
' ORDER BY c.field_id, c.value_id, (CASE WHEN c.value_id=0 THEN f.visibility_field_id ELSE f.value_field_id END), c.visibility_value_id', {Slice=>{}}
);
my $has = {};
for (@{$cache->{fieldvaluecontrol}})
{
if ($_->{value_id})
if ($_->{value_id} > 0)
{
# Show value_id if value_field==visibility_value_id
$has->{$_->{visibility_field_id}}
->{values}
->{$_->{field_id}}
@ -949,13 +950,22 @@ sub fieldvaluecontrol
->{$_->{visibility_value_id}}
->{is_default} = $_->{is_default};
}
else
elsif (!$_->{value_id})
{
# Show field if visibility_field==visibility_value_id
$has->{$_->{visibility_field_id}}
->{fields}
->{$_->{field_id}}
->{$_->{visibility_value_id}} = 1;
}
elsif ($_->{value_id} == -1)
{
# Allow NULL if visibility_field==visibility_value_id
$has->{$_->{visibility_field_id}}
->{null}
->{$_->{field_id}}
->{$_->{visibility_value_id}} = 1;
}
}
$cache->{fieldvaluecontrol_hash} = $has;
}

View File

@ -748,7 +748,7 @@ sub check_dependent_fields
if (!defined $value_objs)
{
# FIXME Implement default field values?
next if $field_obj->nullable;
next if $field_obj->check_is_nullable($self);
ThrowUserError('object_not_specified', { class => $field_obj->value_type });
}
$value_objs = [ $value_objs ] if ref $value_objs ne 'ARRAY';
@ -766,7 +766,7 @@ sub check_dependent_fields
}
}
# Check other custom fields for empty values
elsif (!$field_obj->nullable && $fn ne 'classification' &&
elsif (!$field_obj->check_is_nullable($self) && $fn ne 'classification' &&
(!$self->{$fn} || $field_obj->type == FIELD_TYPE_MULTI_SELECT && !@{$self->{$fn}}))
{
ThrowUserError('field_not_nullable', { field => $field_obj });

View File

@ -226,7 +226,6 @@ use constant FIELD_TABLE_SCHEMA => {
],
};
# FIXME make schema compatible with upstream 4.4
use constant ABSTRACT_SCHEMA => {
# BUG-RELATED TABLES
@ -580,6 +579,9 @@ use constant ABSTRACT_SCHEMA => {
},
# All value/value and value/field dependencies are stored here
# value_id > 0: value with this id is visible if value field has value visibility_value_id
# value_id == 0: field is visible if visibility field has value visibility_value_id
# value_id == -1: NULL is allowed if visibility field has value visibility_value_id
# (originally CustIS Bugs 53617, 91153)
fieldvaluecontrol => {
FIELDS => [

View File

@ -636,21 +636,9 @@ sub visibility_values
{
my $self = shift;
return undef if !$self->visibility_field_id;
my $f;
if ($self->visibility_field && !($f = $self->{visibility_values}))
{
$f = [ keys %{Bugzilla->fieldvaluecontrol_hash
->{$self->visibility_field_id}
->{fields}
->{$self->id} || {} } ];
if (@$f)
{
my $type = Bugzilla::Field::Choice->type($self->visibility_field);
$f = $type->match({ id => $f });
}
$self->{visibility_values} = $f;
}
return $f;
my $h = Bugzilla->fieldvaluecontrol_hash
->{$self->visibility_field_id}->{fields}->{$self->id};
return $h && %$h ? $h : undef;
}
sub has_visibility_value
@ -666,15 +654,13 @@ sub has_visibility_value
return !$hash || !%$hash || $hash->{$value};
}
sub has_all_visibility_values
sub null_visibility_values
{
my $self = shift;
return 1 if !$self->visibility_field_id;
my $hash = Bugzilla->fieldvaluecontrol_hash
->{$self->visibility_field_id}
->{fields}
->{$self->id};
return !$hash || !%$hash;
return undef if !$self->visibility_field_id;
my $h = Bugzilla->fieldvaluecontrol_hash
->{$self->value_field_id}->{null}->{$self->id};
return $h && %$h ? $h : undef;
}
# Check visibility of field for a bug or for a hashref with default value names
@ -687,6 +673,15 @@ sub check_visibility
return $value ? $self->has_visibility_value($value) : 1;
}
sub check_is_nullable
{
my $self = shift;
$self->nullable || return 0;
my $vf = $self->visibility_field || return 1;
my $value = bug_or_hash_value($bug, $vf);
return $value ? $self->null_visibility_values->{$value->id} : 1;
}
=pod
=over
@ -804,7 +799,6 @@ sub set_visibility_field
my ($self, $value) = @_;
$self->set('visibility_field_id', $value);
delete $self->{visibility_field};
delete $self->{visibility_values};
}
sub set_visibility_values
@ -812,7 +806,14 @@ sub set_visibility_values
my $self = shift;
my ($value_ids) = @_;
update_visibility_values($self, 0, $value_ids);
delete $self->{visibility_values};
return $value_ids && @$value_ids;
}
sub set_null_visibility_values
{
my $self = shift;
my ($value_ids) = @_;
update_visibility_values($self, -1, $value_ids);
return $value_ids && @$value_ids;
}
@ -1244,7 +1245,7 @@ sub update_visibility_values
{
my ($controlled_field, $controlled_value_id, $visibility_value_ids) = @_;
$visibility_value_ids ||= [];
my $vis_field = $controlled_value_id
my $vis_field = $controlled_value_id != 0
? $controlled_field->value_field
: $controlled_field->visibility_field;
if (!$vis_field)

View File

@ -128,15 +128,15 @@ sub fields {
}
my %field_data = (
id => $self->type('int', $field->id),
type => $self->type('int', $field->type),
is_custom => $self->type('boolean', $field->custom),
name => $self->type('string', $field->name),
display_name => $self->type('string', $field->description),
is_mandatory => $self->type('boolean', $field->is_mandatory),
is_on_bug_entry => $self->type('boolean', 1),
visibility_field => $self->type('string', $visibility_field),
visibility_values => [ map { $self->type('string', $_->name) } @{ $vis_values || [] } ],
id => $self->type('int', $field->id),
type => $self->type('int', $field->type),
is_custom => $self->type('boolean', $field->custom),
name => $self->type('string', $field->name),
display_name => $self->type('string', $field->description),
is_mandatory => $self->type('boolean', $field->is_mandatory),
is_on_bug_entry => $self->type('boolean', 1),
visibility_field => $self->type('string', $visibility_field),
visibility_values => [ map { $self->type('string', $_->name) } $field->visibility_field->value_type->new_from_list($vis_values) ],
);
if ($has_values) {
$field_data{value_field} = $self->type('string', $value_field);

View File

@ -75,6 +75,7 @@ elsif ($action eq 'new')
add_to_deps => scalar $cgi->param('add_to_deps'),
});
$field->set_visibility_values([ $cgi->param('visibility_value_id') ]);
$field->set_null_visibility_values([ $cgi->param('null_visibility_values') ]);
delete_token($token);
@ -115,19 +116,20 @@ elsif ($action eq 'update')
{
# TODO enter_bug could be edited for non-custom fields, too.
# At the moment, though, it has no effect for non-custom fields.
$field->set_enter_bug($cgi->param('enter_bug'));
$field->set_clone_bug($cgi->param('clone_bug'));
$field->set_value_field($cgi->param('value_field_id'));
$field->set_add_to_deps($cgi->param('add_to_deps'));
my $vf = $cgi->param('visibility_field_id');
if ($field->visibility_field_id != $vf)
if ($vf != $field->visibility_field_id)
{
$field->set_visibility_field($vf);
$field->set_visibility_values([]);
$field->set_null_visibility_values([]);
}
else
{
$field->set_visibility_values([ $cgi->param('visibility_value_id') ]);
$field->set_null_visibility_values([ $cgi->param('null_visibility_values') ]) if $field->is_select && $field->nullable;
}
}
$field->update();

View File

@ -68,9 +68,7 @@ if ($action eq 'update' && $token)
for my $cfield (@{$field->controls_visibility_of})
{
# check if it is 'visible for all'
next if $cfield->has_all_visibility_values;
my $visibility_values = Bugzilla->fieldvaluecontrol_hash
->{$field->id}->{fields}->{$cfield->id};
my $visibility_values = $cfield->visibility_values || next;
# check if changed
next unless ($ARGS->{'visible_'.$cfield->id} xor $visibility_values->{$value->id});
if ($ARGS->{'visible_'.$cfield->id})

View File

@ -40,4 +40,12 @@ function onChangeType()
u = type_field.value == constants.FIELD_TYPE_EXTURL;
document.getElementById('url_row').style.display
= u ? '' : 'none';
onChangeNullable();
}
function onChangeNullable()
{
var u = document.getElementById('nullable');
var n = document.getElementById('allow_null_in_row');
n.style.display = u.checked ? '' : 'none';
}

View File

@ -134,7 +134,7 @@ var constants = {
[% IF !field.id || field.type && field.type != constants.FIELD_TYPE_BUG_ID_REV %]
<th align="left"><label for="nullable">Allow empty value:</label></th>
<td>
<input type="checkbox" id="nullable" name="nullable"
<input type="checkbox" id="nullable" name="nullable" onclick="onChangeNullable()"
value="1" [%- " checked" IF field.nullable %] />
</td>
[% END %]
@ -219,16 +219,38 @@ var constants = {
</tr>
[% END %]
[% IF field.visibility_field %]
<tr valign="top" id="visibility_value_row">
<th colspan="2" align="left"><label for="visibility_value_id">
Show the field only if <span id="visibility_value_name_span">[% field.visibility_field.description | html %]</span> is set to:
</label></th>
<tr valign="top">
<th colspan="2" align="left">
<label for="visibility_value_id">Show the field only if [% field.visibility_field.description | html %] is set to:</label><br />
<span style="font-weight: normal">(<a href="javascript:void(0)"
onclick="document.getElementById('visibility_value_id').selectedIndex=-1">clear options</a>
to make this field always appear)</span>
</th>
<td colspan="2">
[% SET all = field.has_all_visibility_values %]
[% SET all = field.visibility_values %]
<select style="width: 400px" id="visibility_value_id"
name="visibility_value_id" size="7" multiple="multiple">
[% FOREACH value = field.visibility_field.legal_values %]
<option value="[% value.id | html %]"[% ' selected="selected"' IF !all && field.has_visibility_value(value.id) %]>
<option value="[% value.id | html %]"[% ' selected="selected"' IF all && all.${value.id} %]>
[% value.name | html %]
</option>
[% END %]
</select>
</td>
</tr>
<tr valign="top" id="allow_null_in_row">
<th colspan="2" align="left">
<label for="null_visibility_values">Allow empty value only if [% field.visibility_field.description | html %] is set to:</label><br />
<span style="font-weight: normal">(<a href="javascript:void(0)"
onclick="document.getElementById('null_visibility_values').selectedIndex=-1">clear options</a>
to always allow empty value)</span>
</th>
<td colspan="2">
[% SET all = field.null_visibility_values %]
<select style="width: 400px" id="null_visibility_values"
name="null_visibility_values" size="7" multiple="multiple">
[% FOREACH value = field.visibility_field.legal_values %]
<option value="[% value.id | html %]"[% ' selected="selected"' IF field.nullable && all && all.${value.id} %]>
[% value.name | html %]
</option>
[% END %]
@ -255,7 +277,7 @@ var constants = {
</p>
<script>
onChangeEnterBug();
onChangeNullable();
[% IF !field.id %]
onChangeType();
[% END %]

View File

@ -35,11 +35,11 @@
<td>[% cfield.description | html %]</td>
<td align="center">
<input type="checkbox" name="visible_[% cfield.id %]" value="1"
[% "checked=\"checked\"" IF cfield.has_visibility_value(value) %]
[% "disabled=\"disabled\"" IF cfield.has_all_visibility_values %] />
[% "checked=\"checked\"" IF !cfield.visibility_values || cfield.visibility_values.${value.id} %]
[% "disabled=\"disabled\"" IF !cfield.visibility_values %] />
</td>
<td>
[% IF cfield.has_all_visibility_values %]
[% IF !cfield.visibility_values %]
Поле видимо для всех значений поля <strong>[% field.description | html %]</strong><br/>
<a href="editfields.cgi?action=edit&name=[% cfield.name | url_quote %]">Редактировать</a>
[% END %]