diff options
author | myk%mozilla.org <> | 2002-11-05 10:53:59 +0100 |
---|---|---|
committer | myk%mozilla.org <> | 2002-11-05 10:53:59 +0100 |
commit | 6a64cd597b36411fa01d681c693786750b68c92c (patch) | |
tree | d24789dab5efebdaa47c0f1c8936428f15be9935 | |
parent | 952d1ad687cb0ad29188c71fab2ad40e5ec984ba (diff) | |
download | bugzilla-6a64cd597b36411fa01d681c693786750b68c92c.tar.gz bugzilla-6a64cd597b36411fa01d681c693786750b68c92c.tar.xz |
Fix for bug 156548: XUL implementation of duplicates report.
-rw-r--r-- | CGI.pl | 2 | ||||
-rwxr-xr-x | checksetup.pl | 6 | ||||
-rwxr-xr-x | collectstats.pl | 17 | ||||
-rw-r--r-- | css/duplicates.css | 27 | ||||
-rwxr-xr-x | duplicates.cgi | 12 | ||||
-rw-r--r-- | duplicates.xul | 133 | ||||
-rw-r--r-- | js/duplicates.js | 153 | ||||
-rw-r--r-- | skins/standard/duplicates.css | 27 | ||||
-rw-r--r-- | template/en/default/reports/duplicates.rdf.tmpl | 51 |
9 files changed, 426 insertions, 2 deletions
@@ -206,7 +206,7 @@ sub get_netaddr { my ($ipaddr) = @_; # Check for a valid IPv4 addr which we know how to parse - if ($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { + if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { return undef; } diff --git a/checksetup.pl b/checksetup.pl index 3a60a3937..aa91c3a34 100755 --- a/checksetup.pl +++ b/checksetup.pl @@ -837,8 +837,12 @@ END open HTACCESS, ">data/.htaccess"; print HTACCESS <<'END'; # nothing in this directory is retrievable unless overriden by an .htaccess -# in a subdirectory +# in a subdirectory; the only exception is duplicates.rdf, which is used by +# duplicates.xul and must be loadable over the web deny from all +<Files duplicates.rdf> + allow from all +</Files> END close HTACCESS; chmod $fileperm, "data/.htaccess"; diff --git a/collectstats.pl b/collectstats.pl index 8caf92d77..61e7cf204 100755 --- a/collectstats.pl +++ b/collectstats.pl @@ -53,6 +53,23 @@ foreach (@myproducts) { &calculate_dupes(); +# Generate a static RDF file containing the default view of the duplicates data. +open(CGI, "REQUEST_METHOD=GET QUERY_STRING=ctype=rdf ./duplicates.cgi |") + || die "can't fork duplicates.cgi: $!"; +open(RDF, ">data/duplicates.tmp") + || die "can't write to data/duplicates.tmp: $!"; +my $headers_done = 0; +while (<CGI>) { + print RDF if $headers_done; + $headers_done = 1 if $_ eq "\n"; +} +close CGI; +close RDF; +if (-s "data/duplicates.tmp") { + rename("data/duplicates.rdf", "data/duplicates-old.rdf"); + rename("data/duplicates.tmp", "data/duplicates.rdf"); +} + sub check_data_dir { my $dir = shift; diff --git a/css/duplicates.css b/css/duplicates.css new file mode 100644 index 000000000..aab36fb2a --- /dev/null +++ b/css/duplicates.css @@ -0,0 +1,27 @@ +/* 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> + */ + +treechildren:-moz-tree-cell-text(resolution-FIXED) { + text-decoration: line-through; +} + +treecol#id_column { width: 6em; } +treecol#duplicate_count_column { width: 5em; } +treecol#duplicate_delta_column { width: 5em; } diff --git a/duplicates.cgi b/duplicates.cgi index 643a54423..e95d4b02c 100755 --- a/duplicates.cgi +++ b/duplicates.cgi @@ -32,6 +32,18 @@ use lib qw(.); require "globals.pl"; require "CGI.pl"; +use vars qw($buffer); + +# Go directly to the XUL version of the duplicates report (duplicates.xul) +# if the user specified ctype=xul. Adds params if they exist, and directs +# the user to a signed copy of the script in duplicates.jar if it exists. +if ($::FORM{'ctype'} eq "xul") { + my $params = CanonicaliseParams($::buffer, ["format", "ctype"]); + print "Location: " . (-e "duplicates.jar" ? "duplicates.jar!/" : "") . + "duplicates.xul" . ($params ? "?$params" : "") . "\n\n"; + exit; +} + # Use global templatisation variables. use vars qw($template $vars); diff --git a/duplicates.xul b/duplicates.xul new file mode 100644 index 000000000..be647c188 --- /dev/null +++ b/duplicates.xul @@ -0,0 +1,133 @@ +<?xml version="1.0"?> +<!-- + - + - 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> + - + --> + +<!DOCTYPE window [ + <!ENTITY idColumn.label "ID"> + <!ENTITY duplicateCountColumn.label "Count"> + <!ENTITY duplicateDeltaColumn.label "Delta"> + <!ENTITY componentColumn.label "Component"> + <!ENTITY severityColumn.label "Severity"> + <!ENTITY osColumn.label "OS"> + <!ENTITY targetMilestoneColumn.label "Milestone"> + <!ENTITY summaryColumn.label "Summary"> +]> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="css/duplicates.css" type="text/css"?> + +<window id="duplicates_report" + xmlns:html="http://www.w3.org/1999/xhtml" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="Duplicates Report"> + + // Code for populating the tree from the RDF data source + // and loading bug reports when the user selects rows in the tree. + <script type="application/x-javascript" src="js/duplicates.js" /> + + <tree id="results-tree" flex="1" + flags="dont-build-content" + enableColumnDrag="true" + datasources="rdf:null" + ref="" + onselect="loadBugInPane();" + ondblclick="loadBugInWindow();"> + <treecols> + <treecol id="id_column" label="&idColumn.label;" primary="true" sort="?id" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="duplicate_count_column" label="&duplicateCountColumn.label;" sort="?duplicate_count" + sortActive="true" sortDirection="descending" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter" /> + + <treecol id="duplicate_delta_column" label="&duplicateDeltaColumn.label;" sort="?duplicate_delta" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="component_column" label="&componentColumn.label;" flex="3" sort="?component" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="severity_column" label="&severityColumn.label;" flex="1" sort="?severity" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="os_column" label="&osColumn.label;" flex="2" sort="?os" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="target_milestone_column" label="&targetMilestoneColumn.label;" flex="1" sort="?target_milestone" + persist="width hidden sortActive sortDirection ordinal" /> + <splitter class="tree-splitter"/> + + <treecol id="summary_column" label="&summaryColumn.label;" flex="12" sort="?summary" + persist="width hidden sortActive sortDirection ordinal" /> + </treecols> + <template> + <rule> + <conditions> + <treeitem uri="?uri" /> + <triple subject="?uri" predicate="http://www.bugzilla.org/rdf#bugs" object="?bugs" /> + <member container="?bugs" child="?bug" /> + <triple subject="?bug" predicate="http://www.bugzilla.org/rdf#id" object="?id" /> + </conditions> + <bindings> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#duplicate_count" object="?duplicate_count" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#duplicate_delta" object="?duplicate_delta" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#component" object="?component" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#severity" object="?severity" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#priority" object="?priority" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#os" object="?os" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#target_milestone" object="?target_milestone" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#summary" object="?summary" /> + <binding subject="?bug" predicate="http://www.bugzilla.org/rdf#resolution" object="?resolution" /> + </bindings> + <action> + <treechildren> + <treeitem uri="?bug"> + <treerow properties="resolution-?resolution"> + <treecell ref="id_column" label="?id" properties="resolution-?resolution" /> + <treecell ref="duplicate_count_column" label="?duplicate_count" properties="resolution-?resolution" /> + <treecell ref="duplicate_delta_column" label="?duplicate_delta" properties="resolution-?resolution" /> + <treecell ref="component_column" label="?component" properties="resolution-?resolution" /> + <treecell ref="severity_column" label="?severity" properties="resolution-?resolution" /> + <treecell ref="os_column" label="?os" properties="resolution-?resolution" /> + <treecell ref="target_milestone_column" label="?target_milestone" properties="resolution-?resolution" /> + <treecell ref="summary_column" label="?summary" properties="resolution-?resolution" /> + </treerow> + </treeitem> + </treechildren> + </action> + </rule> + </template> + </tree> + + <splitter id="report-content-splitter" collapse="after" state="open" persist="state"> + <grippy/> + </splitter> + + <iframe id="content-browser" src="about:blank" flex="2" persist="height" /> + +</window> diff --git a/js/duplicates.js b/js/duplicates.js new file mode 100644 index 000000000..b1e94a8a6 --- /dev/null +++ b/js/duplicates.js @@ -0,0 +1,153 @@ +/* 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> + */ + +// When the XUL window finishes loading, load the RDF data into it. +window.addEventListener('load', loadData, false); + +// The base URL of this Bugzilla installation; derived from the page's URL. +var gBaseURL = window.location.href.replace(/duplicates\.(jar!|xul).*/, ""); + +function loadData() +{ + // Loads the duplicates data as an RDF data source, attaches it to the tree, + // and rebuilds the tree to display the data. + + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + // Get the RDF service so we can use it to load the data source. + var rdfService = + Components + .classes["@mozilla.org/rdf/rdf-service;1"] + .getService(Components.interfaces.nsIRDFService); + + // When a bug report loads in the content iframe, a 'load' event bubbles up + // to the browser window, which calls this load handler again, which reloads + // the RDF data, which causes the tree to lose the selection. To prevent + // this, we have to remove this handler. + window.removeEventListener('load', loadData, false); + + // The URL of the RDF file; by default for performance a static file + // generated by collectstats.pl, but a call to duplicates.cgi if the page's + // URL contains parameters (so we can dynamically generate the RDF data + // based on those parameters). + var dataURL = gBaseURL + "data/duplicates.rdf"; + if (window.location.href.search(/duplicates\.xul\?.+/) != -1) + dataURL = window.location.href.replace(/(duplicates\.jar!\/)?duplicates\.xul\?/, "duplicates.cgi?ctype=rdf&"); + + // Get the data source and add it to the XUL tree's database to populate + // the tree with the data. + var dataSource = rdfService.GetDataSource(dataURL); + + // If we're using the static file, add an observer that detects failed loads + // (in case this installation isn't generating the file nightly) and redirects + // to the CGI version when loading of the static version fails. + if (window.location.href.search(/duplicates\.xul\?.+/) == -1) + { + var sink = dataSource.QueryInterface(Components.interfaces.nsIRDFXMLSink); + sink.addXMLSinkObserver(StaticDataSourceObserver); + } + + // Add the data source to the tree, set the tree's "ref" attribute + // to the base URL of the data source, and rebuild the tree. + var resultsTree = document.getElementById('results-tree'); + resultsTree.database.AddDataSource(dataSource); + resultsTree.setAttribute('ref', gBaseURL + "data/duplicates.rdf"); + resultsTree.builder.rebuild(); +} + +function getBugURI() +{ + var tree = document.getElementById('results-tree'); + var index = tree.currentIndex; + + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var builder = tree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder); + var resource = builder.getResourceAtIndex(index); + + return resource.Value; +} + +function loadBugInWindow() +{ + // Loads the selected bug in the browser window, replacing the duplicates report + // with the bug report. + + var bugURI = getBugURI(); + window.location = bugURI; +} + +function loadBugInPane() +{ + // Loads the selected bug in the iframe-based content pane that is part of + // this XUL document. + + var splitter = document.getElementById('report-content-splitter'); + var state = splitter.getAttribute('state'); + if (state != "collapsed") + { + var bugURI = getBugURI(); + var browser = document.getElementById('content-browser'); + browser.setAttribute('src', bugURI); + } +} + +var StaticDataSourceObserver = { + onBeginLoad: function(aSink) { } , + onInterrupt: function(aSink) { } , + onResume: function(aSink) { } , + onEndLoad: function(aSink) + { + // Removes the observer from the data source so it doesn't stay around + // when duplicates.xul is reloaded from scratch. + + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + aSink.removeXMLSinkObserver(StaticDataSourceObserver); + } , + onError: function(aSink, aStatus, aErrorMsg) + { + // Tries the dynamic data source since the static one failed to load. + + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + // Get the RDF service so we can use it to load the data source. + var rdfService = + Components + .classes["@mozilla.org/rdf/rdf-service;1"] + .getService(Components.interfaces.nsIRDFService); + + // Remove the observer from the data source so it doesn't stay around + // when duplicates.xul is reloaded from scratch. + aSink.removeXMLSinkObserver(StaticDataSourceObserver); + + // Remove the static data source from the tree. + var oldDataSource = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource); + var resultsTree = document.getElementById('results-tree'); + resultsTree.database.RemoveDataSource(oldDataSource); + + // Munge the URL to point to the CGI and load the data source. + var dataURL = gBaseURL + "duplicates.cgi?ctype=rdf"; + newDataSource = rdfService.GetDataSource(dataURL); + + // Add the data source to the tree and rebuild the tree with the new data. + resultsTree.database.AddDataSource(newDataSource); + resultsTree.builder.rebuild(); + } +}; diff --git a/skins/standard/duplicates.css b/skins/standard/duplicates.css new file mode 100644 index 000000000..aab36fb2a --- /dev/null +++ b/skins/standard/duplicates.css @@ -0,0 +1,27 @@ +/* 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> + */ + +treechildren:-moz-tree-cell-text(resolution-FIXED) { + text-decoration: line-through; +} + +treecol#id_column { width: 6em; } +treecol#duplicate_count_column { width: 5em; } +treecol#duplicate_delta_column { width: 5em; } diff --git a/template/en/default/reports/duplicates.rdf.tmpl b/template/en/default/reports/duplicates.rdf.tmpl new file mode 100644 index 000000000..941f9f70f --- /dev/null +++ b/template/en/default/reports/duplicates.rdf.tmpl @@ -0,0 +1,51 @@ +[% template_version = "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. + # + # 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> + #%] + +<?xml version="1.0"?> +<!-- [% template_version %] --> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:bz="http://www.bugzilla.org/rdf#" + xmlns:nc="http://home.netscape.com/NC-rdf#"> + +<bz:duplicates_report rdf:about="[% Param('urlbase') %]data/duplicates.rdf"> + <bz:bugs> + <Seq> + [% FOREACH bug = bugs %] + <li> + <bz:bug rdf:about="[% Param('urlbase') %]show_bug.cgi?id=[% bug.id %]"> + <bz:id nc:parseType="Integer">[% bug.id %]</bz:id> + <bz:resolution>[% bug.resolution FILTER html %]</bz:resolution> + <bz:duplicate_count nc:parseType="Integer">[% bug.count %]</bz:duplicate_count> + <bz:duplicate_delta nc:parseType="Integer">[% bug.delta %]</bz:duplicate_delta> + <bz:component>[% bug.component FILTER html %]</bz:component> + <bz:severity>[% bug.bug_severity FILTER html %]</bz:severity> + <bz:os>[% bug.op_sys FILTER html %]</bz:os> + <bz:target_milestone>[% bug.target_milestone FILTER html %]</bz:target_milestone> + <bz:summary>[% bug.short_desc FILTER html %]</bz:summary> + </bz:bug> + </li> + [% END %] + </Seq> + </bz:bugs> +</bz:duplicates_report> + +</RDF> |