]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 616191: Implement UI to easily tag bugs from the bug report directly (and get...
authorFrédéric Buclin <LpSolit@gmail.com>
Mon, 7 May 2012 15:58:22 +0000 (17:58 +0200)
committerFrédéric Buclin <LpSolit@gmail.com>
Mon, 7 May 2012 15:58:22 +0000 (17:58 +0200)
r=timello a=LpSolit

21 files changed:
Bugzilla/Field.pm
Bugzilla/Install.pm
Bugzilla/Template.pm
buglist.cgi
js/field.js
process_bug.cgi
skins/standard/IE-fixes.css
skins/standard/global.css
skins/standard/search_form.css
skins/standard/show_bug.css
template/en/default/bug/edit.html.tmpl
template/en/default/bug/field-help.none.tmpl
template/en/default/bug/field.html.tmpl
template/en/default/filterexceptions.pl
template/en/default/global/field-descs.none.tmpl
template/en/default/global/messages.html.tmpl
template/en/default/global/per-bug-queries.html.tmpl [deleted file]
template/en/default/global/setting-descs.none.tmpl
template/en/default/global/useful-links.html.tmpl
template/en/default/search/field.html.tmpl
template/en/default/search/form.html.tmpl

index 4ec592164aa7bb7c74002820c10d57247d06c3c3..c244e66d9f34c2ef144b7948cc0a6f00c32944d7 100644 (file)
@@ -248,7 +248,8 @@ use constant DEFAULT_FIELDS => (
     {name => "owner_idle_time",       desc => "Time Since Assignee Touched"},
     {name => 'see_also',              desc => "See Also",
      type => FIELD_TYPE_BUG_URLS},
-    {name => 'tag',                   desc => 'Tags', buglist => 1},
+    {name => 'tag',                   desc => 'Tags', buglist => 1,
+     type => FIELD_TYPE_KEYWORDS},
 );
 
 ################
index bd591ecc822948c4bfe97e719f9654c0615ca51f..f2c3902e4ba0a18bdc0baa2461c28e2649d578d8 100644 (file)
@@ -61,8 +61,6 @@ sub SETTINGS {
     csv_colsepchar     => { options => [',',';'], default => ',' },
     # 2005-10-26 wurblzap@gmail.com -- Bug 291459
     zoom_textareas     => { options => ["on", "off"], default => "on" },
-    # 2005-10-21 LpSolit@gmail.com -- Bug 313020
-    per_bug_queries    => { options => ['on', 'off'], default => 'off' },
     # 2006-05-01 olav@bkor.dhs.org -- Bug 7710
     state_addselfcc    => { options => ['always', 'never',  'cc_unless_role'],
                             default => 'cc_unless_role' },
@@ -192,6 +190,9 @@ sub update_settings {
                     $settings{$setting}->{subclass}, undef,
                     !$any_settings);
     }
+
+    # Delete the obsolete 'per_bug_queries' user preference. Bug 616191.
+    $dbh->do('DELETE FROM setting WHERE name = ?', undef, 'per_bug_queries');
 }
 
 sub update_system_groups {
index 78c537cc374be7d65f37a7827f05e7856d63d7e5..e5bd8edb74773f5c2f9b9ebebbc7b20f74d637e4 100644 (file)
@@ -928,7 +928,9 @@ sub create {
             'use_keywords' => sub { return Bugzilla::Keyword->any_exist; },
 
             # All the keywords.
-            'all_keywords' => sub { return Bugzilla::Keyword->get_all(); },
+            'all_keywords' => sub {
+                return [map { $_->name } Bugzilla::Keyword->get_all()];
+            },
 
             'feature_enabled' => sub { return Bugzilla->feature(@_); },
 
index 89ba3fe465199c773e59e2facbd8f506c9f12005..f0e77846492d6bb199af276dd7a006cf0ca0c1e0 100755 (executable)
@@ -23,10 +23,8 @@ use Bugzilla::Search;
 use Bugzilla::Search::Quicksearch;
 use Bugzilla::Search::Recent;
 use Bugzilla::Search::Saved;
-use Bugzilla::User;
 use Bugzilla::Bug;
 use Bugzilla::Product;
-use Bugzilla::Keyword;
 use Bugzilla::Field;
 use Bugzilla::Status;
 use Bugzilla::Token;
@@ -445,51 +443,18 @@ elsif (($cmdtype eq "doit") && defined $cgi->param('remtype')) {
         my $new_query = $cgi->param('newquery');
         my $token = $cgi->param('token');
         check_hash_token($token, ['savedsearch']);
-        # If list_of_bugs is true, we are adding/removing tags to/from
-        # individual bugs.
-        if ($cgi->param('list_of_bugs')) {
-            # We add/remove tags based on the action choosen.
-            my $action = trim($cgi->param('action') || '');
-            $action =~ /^(add|remove)$/
-              || ThrowUserError('unknown_action', {action => $action});
-
-            my $method = "${action}_tag";
-
-            # If no new tag name has been given, use the selected one.
-            $query_name ||= $cgi->param('oldqueryname')
-              or ThrowUserError('no_tag_to_edit', {action => $action});
-
-            my @buglist;
-            # Validate all bug IDs before editing tags in any of them.
-            foreach my $bug_id (split(/[\s,]+/, $cgi->param('bug_ids'))) {
-                next unless $bug_id;
-                push(@buglist, Bugzilla::Bug->check($bug_id));
-            }
-
-            foreach my $bug (@buglist) {
-                $bug->$method($query_name);
-            }
-
-            $vars->{'message'} = 'tag_updated';
-            $vars->{'action'} = $action;
-            $vars->{'tag'} = $query_name;
-            $vars->{'buglist'} = [map { $_->id } @buglist];
+        my $existed_before = InsertNamedQuery($query_name, $new_query, 1);
+        if ($existed_before) {
+            $vars->{'message'} = "buglist_updated_named_query";
         }
         else {
-            my $existed_before = InsertNamedQuery($query_name, $new_query, 1);
-            if ($existed_before) {
-                $vars->{'message'} = "buglist_updated_named_query";
-            }
-            else {
-                $vars->{'message'} = "buglist_new_named_query";
-            }
-
-            # Make sure to invalidate any cached query data, so that the footer is
-            # correctly displayed
-            $user->flush_queries_cache();
-
-            $vars->{'queryname'} = $query_name;
+            $vars->{'message'} = "buglist_new_named_query";
         }
+        $vars->{'queryname'} = $query_name;
+
+        # Make sure to invalidate any cached query data, so that the footer is
+        # correctly displayed
+        $user->flush_queries_cache();
 
         print $cgi->header();
         $template->process("global/message.html.tmpl", $vars)
index 9583db02c7107059f4be4b2ed5e32302e4f042f8..1e559508134581f914a44522d194e8035837e0f2 100644 (file)
@@ -870,27 +870,29 @@ YAHOO.bugzilla.userAutocomplete = {
     }
 };
 
-YAHOO.bugzilla.keywordAutocomplete = {
-    dataSource : null,
-    init_ds : function(){
-        this.dataSource = new YAHOO.util.LocalDataSource( YAHOO.bugzilla.keyword_array );
+YAHOO.bugzilla.fieldAutocomplete = {
+    dataSource : [],
+    init_ds : function( field ) {
+        this.dataSource[field] =
+          new YAHOO.util.LocalDataSource( YAHOO.bugzilla.field_array[field] );
     },
     init : function( field, container ) {
-        if( this.dataSource == null ){
-            this.init_ds();
+        if( this.dataSource[field] == null ) {
+            this.init_ds( field );
         }
-        var keywordAutoComp = new YAHOO.widget.AutoComplete(field, container, this.dataSource);
-        keywordAutoComp.maxResultsDisplayed = YAHOO.bugzilla.keyword_array.length;
-        keywordAutoComp.minQueryLength = 0;
-        keywordAutoComp.useIFrame = true;
-        keywordAutoComp.delimChar = [","," "];
-        keywordAutoComp.resultTypeList = false;
-        keywordAutoComp.queryDelay = 0;
-        /*  Causes all the possibilities in the keyword to appear when a user 
+        var fieldAutoComp =
+          new YAHOO.widget.AutoComplete(field, container, this.dataSource[field]);
+        fieldAutoComp.maxResultsDisplayed = YAHOO.bugzilla.field_array[field].length;
+        fieldAutoComp.minQueryLength = 0;
+        fieldAutoComp.useIFrame = true;
+        fieldAutoComp.delimChar = [","," "];
+        fieldAutoComp.resultTypeList = false;
+        fieldAutoComp.queryDelay = 0;
+        /*  Causes all the possibilities in the field to appear when a user
          *  focuses on the textbox 
          */
-        keywordAutoComp.textboxFocusEvent.subscribe( function(){
-            var sInputValue = YAHOO.util.Dom.get('keywords').value;
+        fieldAutoComp.textboxFocusEvent.subscribe( function(){
+            var sInputValue = YAHOO.util.Dom.get(field).value;
             if( sInputValue.length === 0 ){
                 this.sendQuery(sInputValue);
                 this.collapseContainer();
index 30e30b622840353173fcee72e0f6634b9c221efb..29cc54e9f2a0459cf841bb86c3aac4d4a4f87adb 100755 (executable)
@@ -28,10 +28,6 @@ use Bugzilla::Bug;
 use Bugzilla::User;
 use Bugzilla::Util;
 use Bugzilla::Error;
-use Bugzilla::Field;
-use Bugzilla::Product;
-use Bugzilla::Component;
-use Bugzilla::Keyword;
 use Bugzilla::Flag;
 use Bugzilla::Status;
 use Bugzilla::Token;
@@ -330,6 +326,14 @@ if (defined $cgi->param('id')) {
     my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi(
         $first_bug, undef, $vars);
     $first_bug->set_flags($flags, $new_flags);
+
+    # Tags can only be set to one bug at once.
+    if (should_set('tag')) {
+        my @new_tags = split(/[\s,]+/, $cgi->param('tag'));
+        my ($tags_removed, $tags_added) = diff_arrays($first_bug->tags, \@new_tags);
+        $first_bug->remove_tag($_) foreach @$tags_removed;
+        $first_bug->add_tag($_) foreach @$tags_added;
+    }
 }
 
 ##############################
index 727667f738cb21dd1a333713d6126dd1e9674481..9574d5f9e9818aa47cd9ce98a05c18f6e0c9cff5 100644 (file)
@@ -44,7 +44,7 @@ form#Create #comp_desc {
     display: inline;
 }
 
-#keyword_container .yui-ac-content {
+#keywords_container .yui-ac-content {
     _height: 30em; /* ie6 */
 }
 
index 905a9715899d2101b31b926a1fc656ad21fa3ec5..07b289ec25c0ebdca6d421349bd08a0edfbe3592 100644 (file)
@@ -526,12 +526,12 @@ input.required, select.required, span.required_explanation {
     overflow-x: hidden;
 }
 
-#keyword_container {
+#keywords_container {
     padding-top: .2em;
 }
 
 
-#keyword_container .yui-ac-content {
+#keywords_container .yui-ac-content {
     margin-left: -1px;
 }
 
index aa04b6ffeb97b5585c3e40cebeb1fb4fec88620b..e3a2ba1c4541457687d604a18502c4fab7408383 100644 (file)
@@ -99,7 +99,7 @@
   width: inherit;
 }
 
-#keyword_container {
+#keywords_container {
   padding-bottom: 0;
 }
 
index 9c15599eed9d7c2f1e00a811c2d11a51604264ef..fb47335becb00ae77202a182ca56810ab6a4f674 100644 (file)
@@ -118,7 +118,7 @@ table#flags {
     float: right;
 }
 
-.text_input, .bz_userfield, #keyword_container {
+.text_input, .bz_userfield, #keywords_container, #tag_container {
     width: 100%;
 }
 .bz_bug .bz_alias_short_desc_container {
index d7c564fdb03b1ac4945c19a84040eef5d518584f..d8803e677a8345c2506c72280e5c65397a652138 100644 (file)
         [% INCLUDE bug/field.html.tmpl
            bug = bug, field = bug_fields.keywords, value = bug.keywords
            editable = bug.check_can_change_field("keywords", 0, 1),
-           no_tds = 1
+           no_tds = 1, possible_values = all_keywords
         %]
       </td>
     </tr>
   [% END %]
+
+  [% IF user.id %]
+    <tr>
+      [% INCLUDE bug/field.html.tmpl
+         bug = bug, field = bug_fields.tag, value = bug.tags.join(", "),
+         editable = 1, possible_values = user.tags.keys
+      %]
+    </tr>
+  [% END %]
 [% END %]
 
 [%############################################################################%]
index a74de2e321f3532f8d2f49b6173d2cbca96e3ab1..f76fa9639a38532247a222c4b33ff74aaaccdce3 100644 (file)
@@ -137,6 +137,13 @@ status_whiteboard =>
   "Each $terms.bug has a free-form single line text entry box for"
   _ " adding tags and status information.",
 
+tag =>
+  "Unlike ${vars.field_descs.keywords} which are global and visible by
+   all users, ${vars.field_descs.tag} are personal and can only be
+   viewed and edited by their author.
+   Editing them won't send any notification to other users. Use them
+   to tag and keep track of ${terms.bugs}.",
+
 target_milestone =>
    "The $vars.field_descs.target_milestone field is used to define when the"
    _ " engineer the $terms.bug is assigned to expects to fix it.",
index 0cc75c28884e66fe3148c480f07c0296b7cc19b6..e6660256f3d87975d0348bfbe35dd999f1276fda 100644 (file)
          </script>
        [% END %]
      [% CASE constants.FIELD_TYPE_KEYWORDS %]
-       <div id="keyword_container">
+       <div id="[% field.name FILTER html %]_container">
          <input type="text" id="[% field.name FILTER html %]" size="40"
                 class="text_input" name="[% field.name FILTER html %]"
                 value="[% value FILTER html %]">
-         <div id="keyword_autocomplete"></div>
+         <div id="[% field.name FILTER html %]_autocomplete"></div>
        </div>
        <script type="text/javascript" defer="defer">
-         YAHOO.bugzilla.keyword_array = [
-           [%- FOREACH keyword = all_keywords %]
-             [%-# %]"[% keyword.name FILTER js %]"
+         if (typeof YAHOO.bugzilla.field_array === "undefined")
+           YAHOO.bugzilla.field_array = [];
+         YAHOO.bugzilla.field_array["[% field.name FILTER js %]"] = [
+           [%- FOREACH val = possible_values %]
+             [%-# %]"[% val FILTER js %]"
              [%- "," IF NOT loop.last %][% END %]];
-         YAHOO.bugzilla.keywordAutocomplete.init('[% field.name FILTER js %]', 
-                                                 'keyword_autocomplete');
+         YAHOO.bugzilla.fieldAutocomplete.init('[% field.name FILTER js %]',
+                                               '[% field.name FILTER js %]_autocomplete');
        </script>
   [% END %]
 [% ELSE %]
index 31a686a00cda4c8c441ba7599f1e1bf48f228c7c..e3cfec8a2ebb0eed322cc7432f2f4b4086b5d57d 100644 (file)
   'series.frequency * 2',
 ],
 
-'global/per-bug-queries.html.tmpl' => [
-  '" value=\"$bugids\"" IF bugids',
-],
-
 'global/select-menu.html.tmpl' => [
   'options', 
   'size', 
index 27926c802ec63eef08ad076d23aab90949905fac..5f956c7144ecbf31643c6db3181eaa8e26901ffc 100644 (file)
      "settings"                => "Settings",
      "short_desc"              => "Summary",
      "status_whiteboard"       => "Whiteboard",
-     "tag.name"                => "Tags",
+     "tag"                     => "Tags",
      "target_milestone"        => "Target Milestone",
      "version"                 => "Version",
      "work_time"               => "Hours Worked",
index dcaf4b81a33557ce02f47ad8af44a6b9b9cf7a14..fe5029ebcf578cb0817901e211b8cb67690d8794 100644 (file)
       The cookie that was remembering your login is now gone.
     [% END %]
 
-  [% ELSIF message_tag == "tag_updated" %]
-    [% title = "Tag Updated" %]
-    The '<a href="buglist.cgi?tag=[% tag FILTER uri %]">[% tag FILTER html %]</a>'
-    tag has been
-    [% IF action == "add" %]
-      added to
-    [% ELSE %]
-      removed from
-    [% END %]
-    [%+ buglist.size > 1 ? terms.bugs : terms.bug %]
-    [%+ buglist.join(", ") FILTER html %].
-
   [% ELSIF message_tag == "term" %]
     [% terms.$term FILTER html %]
 
diff --git a/template/en/default/global/per-bug-queries.html.tmpl b/template/en/default/global/per-bug-queries.html.tmpl
deleted file mode 100644 (file)
index 766c713..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-[%# This Source Code Form is subject to the terms of the Mozilla Public
-  # License, v. 2.0. If a copy of the MPL was not distributed with this
-  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-  #
-  # This Source Code Form is "Incompatible With Secondary Licenses", as
-  # defined by the Mozilla Public License, v. 2.0.
-  #%]
-
-[% IF user.id && user.settings.per_bug_queries.value == "on" %]
-  <li id="links-special">
-    <script type="text/javascript">
-      <!--
-      function update_text() {
-        // 'lob' means list_of_bugs.
-        var lob_action = document.getElementById('lob_action');
-        var action = lob_action.options[lob_action.selectedIndex].value;
-        var text = document.getElementById('lob_direction');
-        var new_query_text = document.getElementById('lob_new_query_text');
-
-        if (action == "add") {
-          text.innerHTML = "to";
-          new_query_text.style.display = 'inline';
-        }
-        else {
-          text.innerHTML = "from";
-          new_query_text.style.display = 'none';
-        }
-      }
-
-      function manage_old_lists() {
-        var old_lists = document.getElementById('lob_oldqueryname');
-        // If there is no saved searches available, returns.
-        if (!old_lists) return;
-
-        var new_query = document.getElementById('lob_newqueryname').value;
-
-        if (new_query != "") {
-          old_lists.disabled = true;
-        }
-        else {
-          old_lists.disabled = false;
-        }
-      }
-      //-->
-    </script>
-
-    <div class="label"></div>
-    <ul class="links"><li class="form">
-      <form id="list_of_bugs" action="buglist.cgi" method="get">
-        <input type="hidden" name="cmdtype" value="doit">
-        <input type="hidden" name="remtype" value="asnamed">
-        <input type="hidden" name="list_of_bugs" value="1">
-        <input type="hidden" name="token" value="[% issue_hash_token(['savedsearch']) FILTER html %]">
-        <select id="lob_action" name="action" onchange="update_text();">
-          <option value="add">Add</option>
-          [% IF user.tags.size %]
-            <option value="remove">Remove</option>
-          [% END %]
-        </select>
-
-        [% IF Param('docs_urlbase') %]
-          <a href="[% docs_urlbase FILTER html %]query.html#individual-buglists">the named tag</a>
-        [% ELSE %]
-          the named tag
-        [% END %]
-
-        [% IF user.tags.size %]
-          <select id="lob_oldqueryname" name="oldqueryname">
-            [% FOREACH tag = user.tags.keys %]
-              <option value="[% tag FILTER html %]">[% tag FILTER html %]</option>
-            [% END %]
-          </select>
-        [% END %]
-        <span id="lob_new_query_text">
-          [% " or create and add the tag" IF user.tags.size %]
-          <input class="txt" type="text" id="lob_newqueryname"
-                 size="20" maxlength="64" name="newqueryname"
-                 onkeyup="manage_old_lists();">
-        </span>
-        <span id="lob_direction">to</span>
-        [%+ terms.bugs %]
-        <input type="text" name="bug_ids" size="12" maxlength="80"
-         [%- " value=\"$bugids\"" IF bugids %]>
-        <input type="submit" value="Commit" id="commit_list_of_bugs">
-      </form>
-    </li></ul>
-  </li>
-[% END %]
index 28ecad755a630da59d60423e968d239e9aebc6a9..f2dd43de5437e82008d0c071f61c1ac65e729bd2 100644 (file)
@@ -18,7 +18,6 @@
    "off"                              => "Off",
    "oldest_to_newest"                 => "Oldest to Newest",
    "on"                               => "On",
-   "per_bug_queries"                  => "Enable tags for $terms.bugs",
    "post_bug_submit_action"           => "After changing $terms.abug",
    "next_bug"                         => "Show next $terms.bug in my list",
    "same_bug"                         => "Show the updated $terms.bug",
index ea14be8fe583990638c1db658b460bf54d63b6ba..1b5ba9a30ff1f99df2f33df60bf1c87dccf6ba69 100644 (file)
@@ -58,8 +58,6 @@
 
   [%# Individual bugs addition %]
 
-  [% PROCESS "global/per-bug-queries.html.tmpl" %]
-
   [%# Sections of links to more things users can do on this installation. %]
   [% Hook.process("end") %]
 </ul>
index d3f71ae3f34ab0f196e5278af9f642f6e6ef9746..dd5e1fac7a2c5f2ef39c2b84942129d64abe238a 100644 (file)
        types = types, 
        selected = type_selected
     %]
-    <div id="keyword_container">
+    <div id="[% field.name FILTER html %]_container">
        <input name="[% field.name FILTER html %]" 
               id="[% field.name FILTER html %]" size="40"
               [% IF onchange %] onchange="[% onchange FILTER html %]"[% END %]
               value="[% value FILTER html %]">
-       <div id="keyword_autocomplete"></div>
+       <div id="[% field.name FILTER html %]_autocomplete"></div>
     </div>
     <script type="text/javascript" defer="defer">
-      YAHOO.bugzilla.keyword_array = [
-        [%- FOREACH keyword = all_keywords %]
-          [%-# %]"[% keyword.name FILTER js %]"
+      if (typeof YAHOO.bugzilla.field_array === "undefined")
+        YAHOO.bugzilla.field_array = [];
+      YAHOO.bugzilla.field_array["[% field.name FILTER js %]"] = [
+        [%- FOREACH val = possible_values %]
+          [%-# %]"[% val FILTER js %]"
           [%- "," IF NOT loop.last %][% END %]];
-      YAHOO.bugzilla.keywordAutocomplete.init('[% field.name FILTER js %]',
-                                              'keyword_autocomplete');
+      YAHOO.bugzilla.fieldAutocomplete.init('[% field.name FILTER js %]',
+                                            '[% field.name FILTER js %]_autocomplete');
     </script>
   [% CASE constants.FIELD_TYPE_DATETIME %]
     [% INCLUDE "bug/field-label.html.tmpl"
index 4b7ac4b079f339b60c8186d37be7344d29ad146c..fc6f597cfb815424c59c51a434c03af4fd7ccfb9 100644 (file)
@@ -142,6 +142,7 @@ TUI_hide_default('information_query');
     %]
     <div class="search_field_row">
       [% type = field_container.field.name _ "_type" %]
+      [% possible_values = field_container.field.name == 'keywords' ? all_keywords : [] %]
       [% INCLUDE "search/field.html.tmpl" 
           field => field_container.field
           types => field_container.qtypes || query_types