diff --git a/modules/core/validation/models.js b/modules/core/validation/models.js index 74224ce5a..1b5ac4e71 100644 --- a/modules/core/validation/models.js +++ b/modules/core/validation/models.js @@ -3,6 +3,7 @@ import { osmEntity } from '../../osm/entity'; export function validationIssue(attrs) { this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag') + this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag') 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 diff --git a/modules/ui/commit.js b/modules/ui/commit.js index 94b6e3b00..a8602635f 100644 --- a/modules/ui/commit.js +++ b/modules/ui/commit.js @@ -132,7 +132,15 @@ export function uiCommit(context) { var warningsByType = utilArrayGroupBy(warnings, 'type'); for (var warningType in warningsByType) { - tags['warnings:' + warningType] = warningsByType[warningType].length.toString(); + var warningsOfType = warningsByType[warningType]; + tags['warnings:' + warningType] = warningsOfType.length.toString(); + if (warningsOfType[0].subtype) { + var warningsBySubtype = utilArrayGroupBy(warningsOfType, 'subtype'); + for (var warningSubtype in warningsBySubtype) { + var warningsOfSubtype = warningsBySubtype[warningSubtype]; + tags['warnings:' + warningType + ':' + warningSubtype] = warningsOfSubtype.length.toString(); + } + } } diff --git a/modules/validations/missing_tag.js b/modules/validations/missing_tag.js index 8a953aee5..a498f7ec6 100644 --- a/modules/validations/missing_tag.js +++ b/modules/validations/missing_tag.js @@ -45,16 +45,21 @@ export function validationMissingTag() { var messageObj = {}; var missingTagType; + var subtype; if (Object.keys(entity.tags).length === 0) { missingTagType = 'any'; + subtype = 'any'; } else if (!hasDescriptiveTags(entity)) { missingTagType = 'descriptive'; + subtype = 'descriptive'; } else if (isUntypedRelation(entity)) { missingTagType = 'specific'; messageObj.tag = 'type'; + subtype = 'relation_type'; } else if (isUnknownRoad(entity)) { missingTagType = 'unknown_road'; + subtype = 'highway_classification'; } if (!missingTagType) return []; @@ -101,9 +106,10 @@ export function validationMissingTag() { var referenceID = missingTagType === 'unknown_road' ? 'unknown_road' : 'missing_tag'; var severity = (canDelete && missingTagType !== 'unknown_road') ? 'error' : 'warning'; - + return [new validationIssue({ type: type, + subtype: subtype, severity: severity, message: t('issues.' + messageID + '.message', messageObj), reference: showReference, diff --git a/modules/validations/outdated_tags.js b/modules/validations/outdated_tags.js index 4ceaecf88..a17156a79 100644 --- a/modules/validations/outdated_tags.js +++ b/modules/validations/outdated_tags.js @@ -14,6 +14,8 @@ export function validationOutdatedTags() { var graph = context.graph(); var oldTags = Object.assign({}, entity.tags); // shallow copy var preset = context.presets().match(entity, graph); + var explicitPresetUpgrade = preset.replacement; + var subtype = 'deprecated_tags'; // upgrade preset.. if (preset.replacement) { @@ -38,6 +40,9 @@ export function validationOutdatedTags() { Object.keys(preset.addTags).forEach(function(k) { if (!newTags[k]) { newTags[k] = preset.addTags[k]; + if (!explicitPresetUpgrade) { + subtype = 'incomplete_tags'; + } } }); } @@ -61,6 +66,7 @@ export function validationOutdatedTags() { return [new validationIssue({ type: type, + subtype: subtype, severity: 'warning', message: t('issues.outdated_tags.message', { feature: utilDisplayLabel(entity, context) }), reference: showReference, @@ -133,6 +139,7 @@ export function validationOutdatedTags() { var multipolygonLabel = utilDisplayLabel(multipolygon, context); return [new validationIssue({ type: type, + subtype: 'old_multipolygon', severity: 'warning', message: t('issues.old_multipolygon.message', { multipolygon: multipolygonLabel }), reference: showReference, diff --git a/test/spec/validations/missing_tag.js b/test/spec/validations/missing_tag.js index cad1fa01a..42dbb63a2 100644 --- a/test/spec/validations/missing_tag.js +++ b/test/spec/validations/missing_tag.js @@ -67,6 +67,7 @@ describe('iD.validations.missing_tag', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('missing_tag'); + expect(issue.subtype).to.eql('any'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('w-1'); }); @@ -77,6 +78,7 @@ describe('iD.validations.missing_tag', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('missing_tag'); + expect(issue.subtype).to.eql('descriptive'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('w-1'); }); @@ -87,6 +89,7 @@ describe('iD.validations.missing_tag', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('missing_tag'); + expect(issue.subtype).to.eql('descriptive'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('r-1'); }); @@ -97,6 +100,7 @@ describe('iD.validations.missing_tag', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('missing_tag'); + expect(issue.subtype).to.eql('relation_type'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('r-1'); }); @@ -113,6 +117,7 @@ describe('iD.validations.missing_tag', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('missing_tag'); + expect(issue.subtype).to.eql('highway_classification'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('w-1'); }); diff --git a/test/spec/validations/outdated_tags.js b/test/spec/validations/outdated_tags.js index 69414b050..ef387f683 100644 --- a/test/spec/validations/outdated_tags.js +++ b/test/spec/validations/outdated_tags.js @@ -61,6 +61,7 @@ describe('iD.validations.outdated_tags', function () { expect(issues).to.have.lengthOf(1); var issue = issues[0]; expect(issue.type).to.eql('outdated_tags'); + expect(issue.subtype).to.eql('deprecated_tags'); expect(issue.severity).to.eql('warning'); expect(issue.entities).to.have.lengthOf(1); expect(issue.entities[0].id).to.eql('w-1'); @@ -85,6 +86,7 @@ describe('iD.validations.outdated_tags', function () { expect(issues).to.not.have.lengthOf(0); var issue = issues[0]; expect(issue.type).to.eql('outdated_tags'); + expect(issue.subtype).to.eql('old_multipolygon'); expect(issue.entities).to.have.lengthOf(2); expect(issue.entities[0].id).to.eql('w-1'); expect(issue.entities[1].id).to.eql('r-1');