Add ability to ignore warnings

Replace issue's array of entities with array of entity IDs
Improve issue ID hashing
This commit is contained in:
Quincy Morgan
2019-04-29 17:52:32 -07:00
parent 4215db39a2
commit 375779882d
34 changed files with 179 additions and 143 deletions
+11 -7
View File
@@ -7,10 +7,10 @@ export function validationIssue(attrs) {
this.severity = attrs.severity; // required - 'warning' or 'error'
this.message = attrs.message; // required - localized string
this.reference = attrs.reference; // optional - function(selection) to render reference information
this.entities = attrs.entities; // optional - array of entities involved in the issue
this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
this.data = attrs.data; // optional - object containing extra data for the fixes
this.fixes = attrs.fixes; // optional - array of validationIssueFix objects
this.fixes = attrs.fixes || []; // optional - array of validationIssueFix objects
this.hash = attrs.hash; // optional - string to further differentiate the issue
this.id = generateID.apply(this); // generated - see below
@@ -25,10 +25,14 @@ export function validationIssue(attrs) {
parts.push(this.hash);
}
if (this.subtype) {
parts.push(this.subtype);
}
// include entities this issue is for
// (sort them so the id is deterministic)
if (this.entities) {
var entityKeys = this.entities.map(osmEntity.key).sort();
if (this.entityIds) {
var entityKeys = this.entityIds.slice().sort();
parts.push.apply(parts, entityKeys);
}
@@ -48,9 +52,9 @@ export function validationIssue(attrs) {
if (this.loc) {
return _extent = geoExtent(this.loc);
}
if (this.entities && this.entities.length) {
return _extent = this.entities.reduce(function(extent, entity) {
return extent.extend(entity.extent(resolver));
if (this.entityIds && this.entityIds.length) {
return _extent = this.entityIds.reduce(function(extent, entityId) {
return extent.extend(resolver.entity(entityId).extent(resolver));
}, geoExtent());
}
return null;
+43 -19
View File
@@ -2,6 +2,8 @@ import { dispatch as d3_dispatch } from 'd3-dispatch';
import { coreDifference } from './difference';
import { utilArrayGroupBy, utilCallWhenIdle, utilRebind } from '../util';
import { t } from '../util/locale';
import { validationIssueFix } from './validation/models';
import * as Validations from '../validations/index';
@@ -12,6 +14,7 @@ export function coreValidator(context) {
var _rules = {};
var _disabledRules = {};
var _ignoredIssueIDs = {}; // issue.id -> true
var _issuesByIssueID = {}; // issue.id -> issue
var _issuesByEntityID = {}; // entity.id -> set(issue.id)
var _validatedGraph = null;
@@ -57,9 +60,10 @@ export function coreValidator(context) {
// options = {
// what: 'edited', // 'all' or 'edited'
// where: 'visible', // 'all' or 'visible'
// includeIgnored: false // true or false
// };
validator.getIssues = function(options) {
var opts = Object.assign({ what: 'all', where: 'all' }, options);
var opts = Object.assign({ what: 'all', where: 'all', includeIgnored: false }, options);
var issues = Object.values(_issuesByIssueID);
var changes = context.history().difference().changes();
var view = context.map().extent();
@@ -69,19 +73,21 @@ export function coreValidator(context) {
// Sanity check: This issue may be for an entity that not longer exists.
// If we detect this, uncache and return false so it is not incluced..
var entities = issue.entities || [];
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (!context.hasEntity(entity.id)) {
delete _issuesByEntityID[entity.id];
delete _issuesByIssueID[issue.id];
var entityIds = issue.entityIds || [];
for (var i = 0; i < entityIds.length; i++) {
var entityId = entityIds[i];
if (!context.hasEntity(entityId)) {
delete _issuesByEntityID[entityId];
delete _issuesByIssueID[entityId];
return false;
}
}
if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false;
if (opts.what === 'edited') {
var isEdited = entities.some(function(entity) { return changes[entity.id]; });
if (entities.length && !isEdited) return false;
var isEdited = entityIds.some(function(entityId) { return changes[entityId]; });
if (entityIds.length && !isEdited) return false;
}
if (opts.where === 'visible') {
@@ -108,7 +114,7 @@ export function coreValidator(context) {
return Array.from(issueIDs)
.map(function(id) { return _issuesByIssueID[id]; })
.filter(function(issue) { return !_disabledRules[issue.type]; });
.filter(function(issue) { return !_disabledRules[issue.type] && !_ignoredIssueIDs[issue.id]; });
};
@@ -158,10 +164,10 @@ export function coreValidator(context) {
if (issue) {
// When multiple entities are involved (e.g. crossing_ways),
// remove this issue from the other entity caches too..
var entities = issue.entities || [];
entities.forEach(function(other) {
if (other.id !== entityID) {
var otherIssueIDs = _issuesByEntityID[other.id];
var entityIds = issue.entityIds || [];
entityIds.forEach(function(other) {
if (other !== entityID) {
var otherIssueIDs = _issuesByEntityID[other];
if (otherIssueIDs) {
otherIssueIDs.delete(issueID);
}
@@ -176,6 +182,11 @@ export function coreValidator(context) {
}
function ignoreIssue(id) {
_ignoredIssueIDs[id] = true;
}
//
// Run validation on a single entity
//
@@ -196,6 +207,19 @@ export function coreValidator(context) {
}
var detected = fn(entity, context);
detected.forEach(function(issue) {
if (issue.severity === 'warning') {
var ignoreFix = new validationIssueFix({
title: t('issues.fix.ignore_issue.title'),
icon: 'iD-icon-close',
onClick: function() {
ignoreIssue(this.issue.id);
}
});
ignoreFix.issue = issue;
issue.fixes.push(ignoreFix);
}
});
entityIssues = entityIssues.concat(detected);
ran[key] = true;
return !detected.length;
@@ -278,12 +302,12 @@ export function coreValidator(context) {
var issues = validateEntity(entity);
issues.forEach(function(issue) {
var entities = issue.entities || [];
entities.forEach(function(entity) {
if (!_issuesByEntityID[entity.id]) {
_issuesByEntityID[entity.id] = new Set();
var entityIds = issue.entityIds || [];
entityIds.forEach(function(entityId) {
if (!_issuesByEntityID[entityId]) {
_issuesByEntityID[entityId] = new Set();
}
_issuesByEntityID[entity.id].add(issue.id);
_issuesByEntityID[entityId].add(issue.id);
});
_issuesByIssueID[issue.id] = issue;
});