Commit 0e70cd46 authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 344875: Implement a UI to manage custom fields and remove customfield.pl -…

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
parent 045e9648
......@@ -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) {
......
#!/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.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Myk Melez <myk@mozilla.org>
################################################################################
# Script Initialization
################################################################################
use strict;
use lib ".";
use Bugzilla;
use Bugzilla::Field;
use Getopt::Long;
my ($name, $desc);
my $result = GetOptions("name=s" => \$name,
"description|desc=s" => \$desc);
if (!$name or !$desc) {
my $command =
$^O =~ /MSWin32/i ? "perl -T customfield.pl" : "./customfield.pl";
print <<END;
Usage:
Use this script to add a custom field to your Bugzilla installation
by invoking it with the --name and --desc command-line options:
$command --name=<field_name> --desc="<field description>"
<field_name> is the name of the custom field in the database.
The string "cf_" will be prepended to this name to distinguish
the field from standard fields. This name must conform to the
naming rules for the database server you use.
<field description> is a short string describing the field. It will
be displayed to Bugzilla users in several parts of Bugzilla's UI,
for example as the label for the field on the "show bug" page.
Warning:
Custom fields can make Bugzilla less usable. See this URL
for alternatives to custom fields:
http://www.gerv.net/hacking/custom-fields.html
You should try to implement applicable alternatives before using
this script to add a custom field.
END
exit;
}
# Prepend cf_ to the custom field name to distinguish it from standard fields.
$name =~ /^cf_/
or $name = "cf_" . $name;
# Exit gracefully if there is already a field with the given name.
if ( new Bugzilla::Field({name => $name}) ) {
print "There is already a field named $name. Please choose " .
"a different name.\n";
exit;
}
# Create the field.
print "Creating custom field $name ...\n";
Bugzilla::Field::create_or_update(
{name => $name, desc => $desc, custom => 1});
print "Custom field $name created.\n";
#!/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'});
}
[%# 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>&nbsp;</th>
<td>&nbsp;</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 %]
[%# 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>&nbsp;</th>
<td>&nbsp;</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 %]
[%# 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&amp;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'} %]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment