[% FOR duplicate IN problem.duplicates %]
[% INCLUDE 'report/_item.html' problem = duplicate %]
[% END %]
diff --git a/templates/web/base/report/display.html b/templates/web/base/report/display.html
index 1ee5c4636..7c26c4938 100644
--- a/templates/web/base/report/display.html
+++ b/templates/web/base/report/display.html
@@ -40,12 +40,19 @@
[% INCLUDE 'report/banner.html' %]
[% INCLUDE 'report/_main.html' %]
+
+[% IF problem.duplicate_of %]
+ [% INCLUDE 'report/duplicate-no-updates.html' hide_header = 1 %]
+[% END %]
+
[% TRY %][% INCLUDE 'report/_message_manager.html' %][% CATCH file %][% END %]
[% INCLUDE 'report/display_tools.html' %]
[% TRY %][% INCLUDE 'report/sharing.html' %][% CATCH file %][% END %]
[% INCLUDE 'report/updates.html' %]
-[% IF NOT shown_form %]
+[% IF problem.duplicate_of %]
+ [% INCLUDE 'report/duplicate-no-updates.html' %]
+[% ELSIF NOT shown_form %]
[% INCLUDE 'report/update-form.html' %]
[% END %]
diff --git a/templates/web/base/report/duplicate-no-updates.html b/templates/web/base/report/duplicate-no-updates.html
new file mode 100644
index 000000000..eb9ded728
--- /dev/null
+++ b/templates/web/base/report/duplicate-no-updates.html
@@ -0,0 +1,7 @@
+
+ [% UNLESS hide_header %]
[% loc( 'Provide an update') %]
[% END %]
+
[% loc("This report is a duplicate. Please leave updates on the original report:") %]
+
+ [% INCLUDE 'report/_item.html' item_extra_class = 'item-list__item--with-pin item-list--reports__item--selected' problem = problem.duplicate_of %]
+
+
diff --git a/templates/web/bromley/report/display.html b/templates/web/bromley/report/display.html
index 9f2089d28..4c1a69bca 100644
--- a/templates/web/bromley/report/display.html
+++ b/templates/web/bromley/report/display.html
@@ -21,147 +21,19 @@
[% INCLUDE 'report/banner.html' %]
[% INCLUDE 'report/_main.html' %]
-[% INCLUDE 'report/display_tools.html' %]
-[% INCLUDE 'report/updates.html' %]
-
-
-
[% loc( 'Provide an update') %]
-
- [% INCLUDE 'errors.html' %]
-
-
-
+[% INCLUDE 'report/display_tools.html' %]
+[% INCLUDE 'report/updates.html' %]
+[% IF problem.duplicate_of %]
+ [% INCLUDE 'report/duplicate-no-updates.html' %]
+[% ELSE %]
+ [% INCLUDE 'report/update-form.html' %]
+[% END %]
[% INCLUDE 'footer.html' %]
diff --git a/templates/web/bromley/report/update-form.html b/templates/web/bromley/report/update-form.html
new file mode 100644
index 000000000..112cb2960
--- /dev/null
+++ b/templates/web/bromley/report/update-form.html
@@ -0,0 +1,137 @@
+
+
[% loc( 'Provide an update') %]
+
+ [% INCLUDE 'errors.html' %]
+
+
+
--
cgit v1.2.3
From 05ba5147de9dc7b68f3c9048771fcabf80f20eca Mon Sep 17 00:00:00 2001
From: Dave Arter
Date: Thu, 24 Nov 2016 13:56:00 +0000
Subject: Display nearby candidate reports when marking as duplicate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Use Problem->pin_data for single report page
- Promote markers_highlight to fixmystreet.maps API
We want to highlight map pins on the duplicate report selection UI, so let's use
what's already there instead of writing something new.
- Make sure duplicate report pins aren’t draggable
---
perllib/FixMyStreet/App/Controller/Report.pm | 20 ++++---
perllib/FixMyStreet/DB/Result/Problem.pm | 1 +
web/cobrands/fixmystreet/fixmystreet.js | 30 +++++++++-
web/js/map-OpenLayers.js | 86 ++++++++++++++++------------
web/js/map-google.js | 3 +
5 files changed, 94 insertions(+), 46 deletions(-)
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index f9eaf583c..154f0ac94 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -231,13 +231,8 @@ sub generate_map_tags : Private {
latitude => $problem->latitude,
longitude => $problem->longitude,
pins => $problem->used_map
- ? [ {
- latitude => $problem->latitude,
- longitude => $problem->longitude,
- colour => $c->cobrand->pin_colour($problem, 'report'),
- type => 'big',
- } ]
- : [],
+ ? [ $problem->pin_data($c, 'report', type => 'big') ]
+ : [],
);
return 1;
@@ -431,14 +426,21 @@ sub nearby_json : Private {
my $nearby = $c->model('DB::Nearby')->nearby(
$c, $dist, [ $p->id ], 5, $p->latitude, $p->longitude, undef, [ $p->category ], undef
);
- # my @reports = map { $_->problem : $_; } @$nearby;
+ my @pins = map {
+ my $p = $_->problem;
+ my $colour = $c->cobrand->pin_colour( $p, 'around' );
+ [ $p->latitude, $p->longitude,
+ $colour,
+ $p->id, $p->title_safe, 'small', JSON->false
+ ]
+ } @$nearby;
my $on_map_list_html = $c->render_fragment(
'around/on_map_list_items.html',
{ on_map => [], around_map => $nearby }
);
- my $json = {};
+ my $json = { pins => \@pins };
$json->{current} = $on_map_list_html if $on_map_list_html;
my $body = encode_json($json);
$c->res->content_type('application/json; charset=utf-8');
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index b7573d994..ec1534fe9 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -942,6 +942,7 @@ sub pin_data {
id => $self->id,
title => $opts{private} ? $self->title : $self->title_safe,
problem => $self,
+ type => $opts{type},
}
};
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index b314bc991..2a5c85872 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -402,7 +402,8 @@ $.extend(fixmystreet.set_up, {
longitude: $('input[name="longitude"]').val()
};
$("#js-duplicate-reports ul").html("
Loading...
");
- $.getJSON('/report/'+report_id+'/nearby', args, function(data) {
+ var nearby_url = '/report/'+report_id+'/nearby.json';
+ $.getJSON(nearby_url, args, function(data) {
var duplicate_of = $("#report_inspect_form [name=duplicate_of]").val();
var $reports = $(data.current)
.filter("li")
@@ -410,6 +411,16 @@ $.extend(fixmystreet.set_up, {
.slice(0, 5);
$reports.filter("[data-report-id="+duplicate_of+"]").addClass("item-list--reports__item--selected");
+ (function() {
+ var timeout;
+ $reports.on('mouseenter', function(){
+ clearTimeout(timeout);
+ fixmystreet.maps.markers_highlight(parseInt($(this).data('reportId'), 10));
+ }).on('mouseleave', function(){
+ timeout = setTimeout(fixmystreet.maps.markers_highlight, 50);
+ });
+ })();
+
$("#js-duplicate-reports ul").empty().prepend($reports);
$reports.find("a").click(function() {
@@ -419,9 +430,26 @@ $.extend(fixmystreet.set_up, {
$(this).closest("li").addClass("item-list--reports__item--selected");
return false;
});
+
+ show_nearby_pins(data, report_id);
});
}
+ function show_nearby_pins(data, report_id) {
+ var markers = fixmystreet.maps.markers_list( data.pins, true );
+ // We're replacing all the features in the markers layer with the
+ // possible duplicates, but the list of pins from the server doesn't
+ // include the current report. So we need to extract the feature for
+ // the current report and include it in the list of features we're
+ // showing on the layer.
+ var report_marker = fixmystreet.maps.get_marker_by_id(parseInt(report_id, 10));
+ if (report_marker) {
+ markers.unshift(report_marker);
+ }
+ fixmystreet.markers.removeAllFeatures();
+ fixmystreet.markers.addFeatures( markers );
+ }
+
function state_change() {
// The duplicate report list only makes sense when state is 'duplicate'
if ($(this).val() !== "duplicate") {
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index a3cefa7da..49801911b 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -90,7 +90,8 @@ var fixmystreet = fixmystreet || {};
size: pin[5] || marker_size,
faded: 0,
id: pin[3],
- title: pin[4] || ''
+ title: pin[4] || '',
+ draggable: pin[6] === false ? false : true
});
markers.push( marker );
}
@@ -144,7 +145,7 @@ var fixmystreet = fixmystreet || {};
admin_drag: function(pin_moved_callback, confirm_change) {
confirm_change = confirm_change || false;
var original_lonlat;
- var drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, {
+ var drag = new OpenLayers.Control.DragFeatureFMS( fixmystreet.markers, {
onStart: function(feature, e) {
// Keep track of where the feature started, so we can put it
// back if the user cancels the operation.
@@ -167,12 +168,41 @@ var fixmystreet = fixmystreet || {};
} );
fixmystreet.map.addControl( drag );
drag.activate();
+ },
+
+ // `markers.redraw()` in markers_highlight will trigger an
+ // `overFeature` event if the mouse cursor is still over the same
+ // marker on the map, which would then run markers_highlight
+ // again, causing an infinite flicker while the cursor remains over
+ // the same marker. We really only want to redraw the markers when
+ // the cursor moves from one marker to another (ie: when there is an
+ // overFeature followed by an outFeature followed by an overFeature).
+ // Therefore, we keep track of the previous event in
+ // fixmystreet.latest_map_hover_event and only call markers_highlight
+ // if we know the previous event was different to the current one.
+ // (See the `overFeature` and `outFeature` callbacks inside of
+ // fixmystreet.select_feature).
+
+ markers_highlight: function(problem_id) {
+ for (var i = 0; i < fixmystreet.markers.features.length; i++) {
+ if (typeof problem_id == 'undefined') {
+ // There is no highlighted marker, so unfade this marker
+ fixmystreet.markers.features[i].attributes.faded = 0;
+ } else if (problem_id == fixmystreet.markers.features[i].attributes.id) {
+ // This is the highlighted marker, unfade it
+ fixmystreet.markers.features[i].attributes.faded = 0;
+ } else {
+ // This is not the hightlighted marker, fade it
+ fixmystreet.markers.features[i].attributes.faded = 1;
+ }
+ }
+ fixmystreet.markers.redraw();
}
};
var drag = {
activate: function() {
- this._drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, {
+ this._drag = new OpenLayers.Control.DragFeatureFMS( fixmystreet.markers, {
onComplete: function(feature, e) {
fixmystreet.update_pin( feature.geometry );
}
@@ -195,35 +225,6 @@ var fixmystreet = fixmystreet || {};
fixmystreet.map.setCenter(center, z);
}
- // `markers.redraw()` in markers_highlight will trigger an
- // `overFeature` event if the mouse cursor is still over the same
- // marker on the map, which would then run markers_highlight
- // again, causing an infinite flicker while the cursor remains over
- // the same marker. We really only want to redraw the markers when
- // the cursor moves from one marker to another (ie: when there is an
- // overFeature followed by an outFeature followed by an overFeature).
- // Therefore, we keep track of the previous event in
- // fixmystreet.latest_map_hover_event and only call markers_highlight
- // if we know the previous event was different to the current one.
- // (See the `overFeature` and `outFeature` callbacks inside of
- // fixmystreet.select_feature).
-
- function markers_highlight(problem_id) {
- for (var i = 0; i < fixmystreet.markers.features.length; i++) {
- if (typeof problem_id == 'undefined') {
- // There is no highlighted marker, so unfade this marker
- fixmystreet.markers.features[i].attributes.faded = 0;
- } else if (problem_id == fixmystreet.markers.features[i].attributes.id) {
- // This is the highlighted marker, unfade it
- fixmystreet.markers.features[i].attributes.faded = 0;
- } else {
- // This is not the hightlighted marker, fade it
- fixmystreet.markers.features[i].attributes.faded = 1;
- }
- }
- fixmystreet.markers.redraw();
- }
-
function sidebar_highlight(problem_id) {
if (typeof problem_id !== 'undefined') {
var $a = $('.item-list--reports a[href$="/' + problem_id + '"]');
@@ -505,7 +506,7 @@ var fixmystreet = fixmystreet || {};
overFeature: function (feature) {
if (fixmystreet.latest_map_hover_event != 'overFeature') {
document.getElementById('map').style.cursor = 'pointer';
- markers_highlight(feature.attributes.id);
+ fixmystreet.maps.markers_highlight(feature.attributes.id);
sidebar_highlight(feature.attributes.id);
fixmystreet.latest_map_hover_event = 'overFeature';
}
@@ -513,7 +514,7 @@ var fixmystreet = fixmystreet || {};
outFeature: function (feature) {
if (fixmystreet.latest_map_hover_event != 'outFeature') {
document.getElementById('map').style.cursor = '';
- markers_highlight();
+ fixmystreet.maps.markers_highlight();
sidebar_highlight();
fixmystreet.latest_map_hover_event = 'outFeature';
}
@@ -666,9 +667,9 @@ var fixmystreet = fixmystreet || {};
var href = $('a', this).attr('href');
var id = parseInt(href.replace(/^.*[/]([0-9]+)$/, '$1'));
clearTimeout(timeout);
- markers_highlight(id);
+ fixmystreet.maps.markers_highlight(id);
}).on('mouseleave', '.item-list--reports__item', function(){
- timeout = setTimeout(markers_highlight, 50);
+ timeout = setTimeout(fixmystreet.maps.markers_highlight, 50);
});
})();
});
@@ -888,6 +889,19 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
}
});
+/* Drag handler that allows individual features to disable dragging */
+OpenLayers.Control.DragFeatureFMS = OpenLayers.Class(OpenLayers.Control.DragFeature, {
+ CLASS_NAME: "OpenLayers.Control.DragFeatureFMS",
+
+ overFeature: function(feature) {
+ if (feature.attributes.draggable) {
+ return OpenLayers.Control.DragFeature.prototype.overFeature.call(this, feature);
+ } else {
+ return false;
+ }
+ }
+})
+
OpenLayers.Renderer.SVGBig = OpenLayers.Class(OpenLayers.Renderer.SVG, {
MAX_PIXEL: 15E7,
CLASS_NAME: "OpenLayers.Renderer.SVGBig"
diff --git a/web/js/map-google.js b/web/js/map-google.js
index 4c3f6188e..be2df8502 100644
--- a/web/js/map-google.js
+++ b/web/js/map-google.js
@@ -56,6 +56,9 @@ fixmystreet.maps = {};
google.maps.event.trigger(fixmystreet.map, 'idle');
};
+ // This is a noop on Google Maps right now.
+ fixmystreet.maps.markers_highlight = function() {};
+
function PaddingControl(div) {
div.style.padding = '40px';
}
--
cgit v1.2.3
From ec6389940afce877a0bc7771d11a27ee7183f96a Mon Sep 17 00:00:00 2001
From: Dave Arter
Date: Tue, 22 Nov 2016 13:04:25 +0000
Subject: Make it clearer that report is closed when marked as duplicate
- Record state change when leaving update and marking as duplicate
- Change save button wording to match problem state when inspecting
- Make it clearer that updates marking a report as duplicate actually close the report
---
perllib/FixMyStreet/App/Controller/Report.pm | 7 +++++
t/app/controller/report_display.t | 2 +-
t/app/controller/report_inspect.t | 46 +++++++++++++++++++++++-----
t/app/controller/report_updates.t | 2 ++
templates/web/base/report/_inspect.html | 2 +-
templates/web/base/report/updates.html | 2 +-
web/cobrands/fixmystreet/fixmystreet.js | 13 +++++++-
7 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 154f0ac94..f7ccddc70 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -314,6 +314,7 @@ sub inspect : Private {
my $valid = 1;
my $update_text;
my $reputation_change = 0;
+ my %update_params = ();
if ($permissions->{report_inspect}) {
foreach (qw/detailed_information traffic_information duplicate_of/) {
@@ -341,6 +342,11 @@ sub inspect : Private {
if ( $problem->state eq 'hidden' ) {
$problem->get_photoset->delete_cached;
}
+ if ( $problem->state eq 'duplicate' && $old_state ne 'duplicate' ) {
+ # If the report is being closed as duplicate, make sure the
+ # update records this.
+ $update_params{problem_state} = "duplicate";
+ }
if ( $problem->state ne 'duplicate' ) {
$problem->unset_extra_metadata('duplicate_of');
}
@@ -388,6 +394,7 @@ sub inspect : Private {
state => 'confirmed',
mark_fixed => 0,
anonymous => 0,
+ %update_params,
} );
}
# This problem might no longer be visible on the current cobrand,
diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t
index 9817a640d..fad8b2bbb 100644
--- a/t/app/controller/report_display.t
+++ b/t/app/controller/report_display.t
@@ -117,7 +117,7 @@ subtest "duplicate reports are signposted correctly" => sub {
my $report2_id = $report2->id;
ok $mech->get("/report/$report2_id"), "get '/report/$report2_id'";
- $mech->content_contains('This report is a duplicate.');
+ $mech->content_contains('This report is a duplicate');
$mech->content_contains($report->title);
$mech->log_out_ok;
diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t
index b4d6636b9..56e6e957f 100644
--- a/t/app/controller/report_inspect.t
+++ b/t/app/controller/report_inspect.t
@@ -21,12 +21,14 @@ my $wodc = $mech->create_body_ok(2420, 'West Oxfordshire District Council', id =
$mech->create_contact_ok( body_id => $wodc->id, category => 'Horses', email => 'horses@example.net' );
-my ($report) = $mech->create_problems_for_body(1, $oxon->id, 'Test', {
+my ($report, $report2) = $mech->create_problems_for_body(2, $oxon->id, 'Test', {
category => 'Cows', cobrand => 'fixmystreet', areas => ',2237,2420',
whensent => \'current_timestamp',
latitude => 51.847693, longitude => -1.355908,
});
my $report_id = $report->id;
+my $report2_id = $report2->id;
+
my $user = $mech->log_in_ok('test@example.com');
$user->update( { from_body => $oxon } );
@@ -94,11 +96,6 @@ FixMyStreet::override_config {
};
subtest "test duplicate reports are shown" => sub {
- my ($report2) = $mech->create_problems_for_body(1, $oxon->id, 'The other report is a duplicate of this one', {
- category => $report->category, cobrand => 'fixmystreet', areas => ',2237,2420',
- whensent => \'current_timestamp',
- latitude => 51.847694, longitude => -1.355909,
- });
my $old_state = $report->state;
$report->set_extra_metadata('duplicate_of' => $report2->id);
$report->state('duplicate');
@@ -107,7 +104,6 @@ FixMyStreet::override_config {
$mech->get_ok("/report/$report_id");
$mech->content_contains($report2->title);
- my $report2_id = $report2->id;
$mech->get_ok("/report/$report2_id");
$mech->content_contains($report->title);
@@ -116,6 +112,42 @@ FixMyStreet::override_config {
$report->update;
};
+ subtest "marking a report as a duplicate with update correctly sets update status" => sub {
+ my $old_state = $report->state;
+ $report->comments->delete_all;
+
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form_ok({ button => 'save', with_fields => { state => 'Duplicate', duplicate_of => $report2->id, public_update => "This is a duplicate.", save_inspected => "1" } });
+ $report->discard_changes;
+
+ is $report->state, 'duplicate', 'report marked as duplicate';
+ is $report->comments->search({ problem_state => 'duplicate' })->count, 1, 'update marking report as duplicate was left';
+
+ $report->update({ state => $old_state });
+ };
+
+ subtest "marking a report as a duplicate doesn't clobber user-provided update" => sub {
+ my $old_state = $report->state;
+ $report->comments->delete_all;
+
+ $mech->get_ok("/report/$report_id");
+ my $update_text = "This text was entered as an update by the user.";
+ $mech->submit_form_ok({ button => 'save', with_fields => {
+ state => 'Duplicate',
+ duplicate_of => $report2->id,
+ public_update => $update_text,
+ save_inspected => "1",
+ }});
+ $report->discard_changes;
+
+ is $report->state, 'duplicate', 'report marked as duplicate';
+ is $report->comments->search({ problem_state => 'duplicate' })->count, 1, 'update marked report as duplicate';
+ $mech->content_contains($update_text);
+ $mech->content_lacks("Thank you for your report. This problem has already been reported.");
+
+ $report->update({ state => $old_state });
+ };
+
foreach my $test (
{ type => 'report_edit_priority', priority => 1 },
{ type => 'report_edit_category', category => 1 },
diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t
index e1cd0da71..5a88097fa 100644
--- a/t/app/controller/report_updates.t
+++ b/t/app/controller/report_updates.t
@@ -685,6 +685,8 @@ for my $test (
my $meta_state = $test->{meta} || $test->{fields}->{state};
if ( $test->{reopened} ) {
like $update_meta->[0], qr/reopened$/, 'update meta says reopened';
+ } elsif ( $test->{state} eq 'duplicate' ) {
+ like $update_meta->[0], qr/closed as $meta_state$/, 'update meta includes state change';
} else {
like $update_meta->[0], qr/marked as $meta_state$/, 'update meta includes state change';
}
diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html
index 6f49f3ecb..ccaa756c5 100644
--- a/templates/web/base/report/_inspect.html
+++ b/templates/web/base/report/_inspect.html
@@ -158,7 +158,7 @@