зеркало из https://github.com/mozilla/pjs.git
Bug 344875: Implement a UI to manage custom fields and remove customfield.pl - Patch by Fr�d�ric Buclin <LpSolit@gmail.com> r=mkanat a=myk
This commit is contained in:
Родитель
4b71efb9c7
Коммит
9710d19f24
|
@ -93,6 +93,8 @@ use constant DB_COLUMNS => (
|
|||
'description',
|
||||
'type',
|
||||
'custom',
|
||||
'mailhead',
|
||||
'sortkey',
|
||||
'obsolete',
|
||||
'enter_bug',
|
||||
);
|
||||
|
@ -216,6 +218,31 @@ sub custom { return $_[0]->{custom} }
|
|||
|
||||
=over
|
||||
|
||||
=item C<in_new_bugmail>
|
||||
|
||||
a boolean specifying whether or not the field is displayed in bugmail
|
||||
for newly-created bugs;
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub in_new_bugmail { return $_[0]->{mailhead} }
|
||||
|
||||
=over
|
||||
|
||||
=item C<sortkey>
|
||||
|
||||
an integer specifying the sortkey of the field.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub sortkey { return $_[0]->{sortkey} }
|
||||
|
||||
=over
|
||||
|
||||
=item C<obsolete>
|
||||
|
||||
a boolean specifying whether or not the field is obsolete;
|
||||
|
@ -256,8 +283,14 @@ Params: This function takes named parameters in a hashref:
|
|||
C<desc> - string - The field label to display in the UI.
|
||||
C<in_new_bugmail> - boolean - Whether this field appears at the
|
||||
top of the bugmail for a newly-filed bug.
|
||||
|
||||
The following parameters are only available on field creation:
|
||||
C<custom> - boolean - True if this is a Custom Field. The field
|
||||
will be added to the C<bugs> table if it does not exist.
|
||||
C<sortkey> - integer - The sortkey of the field.
|
||||
C<editable_on_enter_bug> - boolean - Whether this field is
|
||||
editable on the bug creation form.
|
||||
C<is_obsolete> - boolean - Whether this field is obsolete.
|
||||
|
||||
Returns: a C<Bugzilla::Field> object.
|
||||
|
||||
|
@ -267,12 +300,16 @@ Returns: a C<Bugzilla::Field> object.
|
|||
|
||||
sub create_or_update {
|
||||
my ($params) = @_;
|
||||
|
||||
|
||||
my $custom = $params->{custom} ? 1 : 0;
|
||||
my $name = $params->{name};
|
||||
my $in_new_bugmail = $params->{in_new_bugmail} ? 1 : 0;
|
||||
my $sortkey = $params->{sortkey} || 0;
|
||||
my $enter_bug = $params->{editable_on_enter_bug} ? 1 : 0;
|
||||
my $is_obsolete = $params->{is_obsolete} ? 1 : 0;
|
||||
|
||||
# Some day we'll allow invocants to specify the field type.
|
||||
# We don't care about $params->{type} yet.
|
||||
my $type = $custom ? FIELD_TYPE_FREETEXT : FIELD_TYPE_UNKNOWN;
|
||||
|
||||
my $field = new Bugzilla::Field({name => $name});
|
||||
|
@ -285,16 +322,15 @@ sub create_or_update {
|
|||
undef, $params->{desc}, $in_new_bugmail, $field->id);
|
||||
}
|
||||
else {
|
||||
# Some day we'll allow invocants to specify the sort key.
|
||||
my ($sortkey) = $dbh->selectrow_array(
|
||||
$sortkey ||= $dbh->selectrow_array(
|
||||
"SELECT MAX(sortkey) + 100 FROM fielddefs") || 100;
|
||||
|
||||
# Add the field to the list of fields at this Bugzilla installation.
|
||||
$dbh->do("INSERT INTO fielddefs (name, description, sortkey, type,
|
||||
custom, mailhead)
|
||||
VALUES (?, ?, ?, ?, ?, ?)", undef,
|
||||
custom, mailhead, obsolete, enter_bug)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)", undef,
|
||||
$name, $params->{desc}, $sortkey, $type, $custom,
|
||||
$in_new_bugmail);
|
||||
$in_new_bugmail, $is_obsolete, $enter_bug);
|
||||
}
|
||||
|
||||
if (!$dbh->bz_column_info('bugs', $name) && $custom) {
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/perl -wT
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
|
||||
|
||||
use strict;
|
||||
use lib ".";
|
||||
|
||||
use Bugzilla;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Util;
|
||||
use Bugzilla::Field;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
my $template = Bugzilla->template;
|
||||
my $vars = {};
|
||||
|
||||
# Make sure the user is logged in and is an administrator.
|
||||
my $user = Bugzilla->login(LOGIN_REQUIRED);
|
||||
$user->in_group('admin')
|
||||
|| ThrowUserError('auth_failure', {group => 'admin',
|
||||
action => 'edit',
|
||||
object => 'custom_fields'});
|
||||
|
||||
my $action = trim($cgi->param('action') || '');
|
||||
|
||||
print $cgi->header();
|
||||
|
||||
# List all existing custom fields if no action is given.
|
||||
if (!$action) {
|
||||
$vars->{'custom_fields'} = [Bugzilla->get_fields({'custom' => 1})];
|
||||
|
||||
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
# Interface to add a new custom field.
|
||||
elsif ($action eq 'add') {
|
||||
$template->process('admin/custom_fields/create.html.tmpl')
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
elsif ($action eq 'new') {
|
||||
my $name = clean_text($cgi->param('name') || '');
|
||||
my $desc = clean_text($cgi->param('desc') || '');
|
||||
# For now, there is only one type available for custom fields.
|
||||
# In the future, we will have to look at $cgi->param('type').
|
||||
my $type = FIELD_TYPE_FREETEXT;
|
||||
my $sortkey = $cgi->param('sortkey') || 0;
|
||||
|
||||
# Validate these fields.
|
||||
$name || ThrowUserError('customfield_missing_name');
|
||||
# Prepend cf_ to the custom field name to distinguish it from standard fields.
|
||||
if ($name !~ /^cf_/) {
|
||||
$name = 'cf_' . $name;
|
||||
}
|
||||
my $field = new Bugzilla::Field({'name' => $name});
|
||||
ThrowUserError('customfield_already_exists', {'field' => $field }) if $field;
|
||||
|
||||
$desc || ThrowUserError('customfield_missing_description', {'name' => $name});
|
||||
|
||||
my $skey = $sortkey;
|
||||
detaint_natural($sortkey)
|
||||
|| ThrowUserError('customfield_invalid_sortkey', {'name' => $name,
|
||||
'sortkey' => $skey});
|
||||
|
||||
# All fields have been validated. We can create this new custom field.
|
||||
trick_taint($name);
|
||||
trick_taint($desc);
|
||||
|
||||
$vars->{'name'} = $name;
|
||||
$vars->{'desc'} = $desc;
|
||||
$vars->{'sortkey'} = $sortkey;
|
||||
$vars->{'type'} = $type;
|
||||
$vars->{'custom'} = 1;
|
||||
$vars->{'in_new_bugmail'} = $cgi->param('new_bugmail') ? 1 : 0;
|
||||
$vars->{'editable_on_enter_bug'} = $cgi->param('enter_bug') ? 1 : 0;
|
||||
$vars->{'is_obsolete'} = $cgi->param('obsolete') ? 1 : 0;
|
||||
|
||||
Bugzilla::Field::create_or_update($vars);
|
||||
|
||||
$vars->{'custom_fields'} = [Bugzilla->get_fields({'custom' => 1})];
|
||||
|
||||
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
elsif ($action eq 'edit') {
|
||||
my $name = $cgi->param('name') || ThrowUserError('customfield_missing_name');
|
||||
trick_taint($name);
|
||||
my @field = Bugzilla->get_fields({'name' => $name, 'custom' => 1});
|
||||
scalar(@field) || ThrowUserError('customfield_nonexistent', {'name' => $name});
|
||||
|
||||
$vars->{'field'} = $field[0];
|
||||
|
||||
$template->process('admin/custom_fields/edit.html.tmpl', $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
elsif ($action eq 'update') {
|
||||
die "not yet implemented...\n";
|
||||
}
|
||||
elsif ($action eq 'del') {
|
||||
die "not yet implemented...\n";
|
||||
}
|
||||
elsif ($action eq 'delete') {
|
||||
die "not yet implemented...\n";
|
||||
}
|
||||
else {
|
||||
ThrowUserError('no_valid_action', {'field' => 'custom_field'});
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
[%# 1.0@bugzilla.org %]
|
||||
[%# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# none
|
||||
#%]
|
||||
|
||||
[% PROCESS "global/field-descs.none.tmpl" %]
|
||||
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Add a new Custom Field"
|
||||
onload = "document.getElementById('new_bugmail').disabled = true;" %]
|
||||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
// Disable a checkbox based on the state of another one.
|
||||
function toggleCheckbox(this_checkbox, other_checkbox_id) {
|
||||
var other_checkbox = document.getElementById(other_checkbox_id);
|
||||
other_checkbox.disabled = !this_checkbox.checked;
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
|
||||
<p>
|
||||
Adding custom fields can make the interface of [% terms.Bugzilla %] very
|
||||
complicated. Many admins who are new to [% terms.Bugzilla %] start off
|
||||
adding many custom fields, and then their users complain that the interface
|
||||
is "too complex". Please think carefully before adding any custom fields.
|
||||
It may be the case that [% terms.Bugzilla %] already does what you need,
|
||||
and you just haven't enabled the correct feature yet.
|
||||
|
||||
<ul>
|
||||
<li>Custom field names must begin with "cf_" to distinguish them from standard
|
||||
fields. If you omit "cf_" from the name, it will automatically be appended.</li>
|
||||
<li>Descriptions are a very short string describing the field and will be used
|
||||
as the label for this field in the user interface.</li>
|
||||
</ul>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<form id="add_field" action="editfields.cgi" method="GET">
|
||||
<table border="0" cellspacing="0" cellpadding="5">
|
||||
<tr>
|
||||
<th align="right"><label for="name">Name:</label></th>
|
||||
<td>
|
||||
<input type="text" id="name" name="name" value="cf_" size="40" maxlength="64">
|
||||
</td>
|
||||
|
||||
<th align="right">
|
||||
<label for="enter_bug">Can be set on [% terms.bug %] creation:</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="checkbox" id="enter_bug" name="enter_bug" value="1"
|
||||
onchange="toggleCheckbox(this, 'new_bugmail');">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="desc">Description:</label></th>
|
||||
<td><input type="text" id="desc" name="desc" value="" size="40"></td>
|
||||
|
||||
<th align="right">
|
||||
<label for="new_bugmail">Displayed in bugmail for new [% terms.bugs %]:</label>
|
||||
</th>
|
||||
<td><input type="checkbox" id="new_bugmail" name="new_bugmail" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="type">Type:</label></th>
|
||||
<td>
|
||||
[%# Only one field type is valid right now. But let's prepare the UI
|
||||
# for future new types. %]
|
||||
<select id="type" name="type">
|
||||
<option value="FIELD_TYPE_FREETEXT">Free Text</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<th align="right"><label for="obsolete">Is obsolete:</label></th>
|
||||
<td><input type="checkbox" id="obsolete" name="obsolete" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="sortkey">Sortkey:</label></th>
|
||||
<td>
|
||||
<input type="text" id="sortkey" name="sortkey" value="0" size="6" maxlength="6">
|
||||
</td>
|
||||
|
||||
<th> </th>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<input type="hidden" name="action" value="new">
|
||||
<input type="submit" id="create" value="Create">
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<a href="editfields.cgi">Back to the list of existing custom fields</a>
|
||||
</p>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -0,0 +1,99 @@
|
|||
[%# 1.0@bugzilla.org %]
|
||||
[%# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# none
|
||||
#%]
|
||||
|
||||
[% PROCESS "global/field-descs.none.tmpl" %]
|
||||
|
||||
[% title = BLOCK %]
|
||||
Edit the Custom Field '[% field.name FILTER html %]' ([% field.description FILTER html %])
|
||||
[% END %]
|
||||
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = title
|
||||
onload = "toggleCheckbox(document.getElementById('enter_bug'), 'new_bugmail');" %]
|
||||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
// Disable a checkbox based on the state of another one.
|
||||
function toggleCheckbox(this_checkbox, other_checkbox_id) {
|
||||
var other_checkbox = document.getElementById(other_checkbox_id);
|
||||
other_checkbox.disabled = !this_checkbox.checked;
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
|
||||
<p>
|
||||
Descriptions are a very short string describing the field and will be used as
|
||||
the label for this field in the user interface.
|
||||
</p>
|
||||
|
||||
<form id="edit_field" action="editfields.cgi" method="GET">
|
||||
<table border="0" cellspacing="0" cellpadding="5">
|
||||
<tr>
|
||||
<th align="right">Name:</th>
|
||||
<td>[% field.name FILTER html %]</td>
|
||||
|
||||
<th align="right">
|
||||
<label for="enter_bug">Can be set on [% terms.bug %] creation:</label>
|
||||
</th>
|
||||
<td><input type="checkbox" id="enter_bug" name="enter_bug" value="1"
|
||||
[%- " checked" IF field.enter_bug %]
|
||||
onchange="toggleCheckbox(this, 'new_bugmail');"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="desc">Description:</label></th>
|
||||
<td><input type="text" id="desc" name="desc" size="40"
|
||||
value="[% field.description FILTER html %]"></td>
|
||||
|
||||
<th align="right">
|
||||
<label for="new_bugmail">Displayed in bugmail for new [% terms.bugs %]:</label>
|
||||
</th>
|
||||
<td><input type="checkbox" id="new_bugmail" name="new_bugmail" value="1"
|
||||
[%- " checked" IF field.mailhead %]></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right">Type:</th>
|
||||
<td>Free Text</td>
|
||||
|
||||
<th align="right"><label for="obsolete">Is obsolete:</label></th>
|
||||
<td><input type="checkbox" id="obsolete" name="obsolete" value="1"
|
||||
[%- " checked" IF field.obsolete %]></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="right"><label for="sortkey">Sortkey:</label></th>
|
||||
<td>
|
||||
<input type="text" id="sortkey" name="sortkey" size="6" maxlength="6"
|
||||
value="[% field.sortkey FILTER html %]">
|
||||
</td>
|
||||
|
||||
<th> </th>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<input type="hidden" name="action" value="update">
|
||||
<input type="hidden" name="name" value="[% field.name FILTER html %]">
|
||||
<input type="submit" id="edit" value="Submit" disabled="disabled">
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<a href="editfields.cgi">Back to the list of existing custom fields</a>
|
||||
</p>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -0,0 +1,63 @@
|
|||
[%# 1.0@bugzilla.org %]
|
||||
[%# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# custom_fields: a list of Bugzilla::Field objects, representing custom fields.
|
||||
#%]
|
||||
|
||||
[% PROCESS "global/field-descs.none.tmpl" %]
|
||||
|
||||
[% PROCESS global/header.html.tmpl title = "Custom Fields" %]
|
||||
|
||||
[% columns = [
|
||||
{
|
||||
name => "name"
|
||||
heading => "Edit custom field..."
|
||||
contentlink => "editfields.cgi?action=edit&name=%%name%%"
|
||||
},
|
||||
{
|
||||
name => "description"
|
||||
heading => "Description"
|
||||
},
|
||||
{
|
||||
name => "sortkey"
|
||||
heading => "Sortkey"
|
||||
},
|
||||
{
|
||||
name => "enter_bug"
|
||||
heading => "Editable on Bug Creation"
|
||||
},
|
||||
{
|
||||
name => "mailhead"
|
||||
heading => "In Bugmail on Bug Creation"
|
||||
},
|
||||
{
|
||||
name => "obsolete"
|
||||
heading => "Is Obsolete"
|
||||
}
|
||||
]
|
||||
%]
|
||||
|
||||
[% PROCESS admin/table.html.tmpl
|
||||
columns = columns
|
||||
data = custom_fields
|
||||
%]
|
||||
|
||||
<p>
|
||||
<a href="editfields.cgi?action=add">Add a new custom field</a>
|
||||
</p>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
|
@ -158,6 +158,8 @@
|
|||
classifications
|
||||
[% ELSIF object == "components" %]
|
||||
components
|
||||
[% ELSIF object == "custom_fields" %]
|
||||
custom fields
|
||||
[% ELSIF object == "flagtypes" %]
|
||||
flag types
|
||||
[% ELSIF object == "group_access" %]
|
||||
|
@ -307,9 +309,27 @@
|
|||
Product [% product FILTER html %] does not have a component
|
||||
named [% name FILTER html %].
|
||||
|
||||
[% ELSIF error == "product_doesnt_exist" %]
|
||||
[% title = "Specified Product Does Not Exist" %]
|
||||
The product '[% product FILTER html %]' does not exist.
|
||||
[% ELSIF error == "customfield_already_exists" %]
|
||||
[% title = "Field Already Exists" %]
|
||||
The field '[% field.name FILTER html %]' ([% field.description FILTER html %])
|
||||
already exists. Please choose another name.
|
||||
|
||||
[% ELSIF error == "customfield_nonexistent" %]
|
||||
[% title = "Unknown Custom Field" %]
|
||||
There is no custom field with the name '[% name FILTER html %]'.
|
||||
|
||||
[% ELSIF error == "customfield_invalid_sortkey" %]
|
||||
[% title = "Invalid Sortkey for Field" %]
|
||||
The sortkey [% sortkey FILTER html %] that you have provided for
|
||||
the '[% name FILTER html %]' field is not a valid positive integer.
|
||||
|
||||
[% ELSIF error == "customfield_missing_description" %]
|
||||
[% title = "Missing Description for Field" %]
|
||||
You must enter a description for the '[% name FILTER html %]' field.
|
||||
|
||||
[% ELSIF error == "customfield_missing_name" %]
|
||||
[% title = "Missing Name for Field" %]
|
||||
You must enter a name for this field.
|
||||
|
||||
[% ELSIF error == "dependency_loop_multi" %]
|
||||
[% title = "Dependency Loop Detected" %]
|
||||
|
@ -1086,6 +1106,10 @@
|
|||
Patches cannot be more than [% Param('maxpatchsize') %] KB in size.
|
||||
Try breaking your patch into several pieces.
|
||||
|
||||
[% ELSIF error == "product_doesnt_exist" %]
|
||||
[% title = "Specified Product Does Not Exist" %]
|
||||
The product '[% product FILTER html %]' does not exist.
|
||||
|
||||
[% ELSIF error == "product_votes_per_bug_must_be_nonnegative" %]
|
||||
[% title = "Maximum Votes Must Be Non-negative" %]
|
||||
[% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %]
|
||||
|
|
Загрузка…
Ссылка в новой задаче