Merge pull request #8628 from openstreetmap/tag_as_not

Add a validator fix option to tag as `not:` a matched item
This commit is contained in:
Milos Brzakovic
2021-09-27 19:12:10 +02:00
committed by GitHub
3 changed files with 65 additions and 11 deletions
+3
View File
@@ -1943,6 +1943,9 @@ en:
tag_as_disconnected:
title: Tag as disconnected
annotation: Tagged very close features as disconnected.
tag_as_not:
title: "Tag as not the same \"{name}\""
annotation: "Added not: tag"
tag_as_unsquare:
title: Tag as physically unsquare
annotation: Tagged a way as having unsquare corners.
+19 -6
View File
@@ -399,7 +399,11 @@ function gatherTuples(tryKVs, tryNames) {
// `tags`: `Object` containing the feature's OSM tags
// `loc`: Location where this feature exists, as a [lon, lat]
// Returns
// `Object`: The tags the the feature should have, or `null` if no changes needed
// `Object` containing the result, or `null` if no changes needed:
// {
// 'newTags': `Object` - The tags the the feature should have
// 'matched': `Object` - The matched item
// }
//
function _upgradeTags(tags, loc) {
let newTags = Object.assign({}, tags); // shallow copy
@@ -438,7 +442,9 @@ function _upgradeTags(tags, loc) {
// Gather key/value tag pairs to try to match
const tryKVs = gatherKVs(tags);
if (!tryKVs.primary.size && !tryKVs.alternate.size) return changed ? newTags : null;
if (!tryKVs.primary.size && !tryKVs.alternate.size) {
return changed ? { newTags: newTags, matched: null } : null;
}
// Gather namelike tag values to try to match
const tryNames = gatherNames(tags);
@@ -448,7 +454,9 @@ function _upgradeTags(tags, loc) {
const foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
if (foundQID) tryNames.primary.add(foundQID); // matcher will recognize the Wikidata QID as name too
if (!tryNames.primary.size && !tryNames.alternate.size) return changed ? newTags : null;
if (!tryNames.primary.size && !tryNames.alternate.size) {
return changed ? { newTags: newTags, matched: null } : null;
}
// Order the [key,value,name] tuples - test primary before alternate
const tuples = gatherTuples(tryKVs, tryNames);
@@ -489,6 +497,7 @@ function _upgradeTags(tags, loc) {
if (!item) continue;
// At this point we have matched a canonical item and can suggest tag upgrades..
item = JSON.parse(JSON.stringify(item)); // deep copy
const tkv = item.tkv;
const parts = tkv.split('/', 3); // tkv = "tree/key/value"
const k = parts[1];
@@ -579,10 +588,10 @@ function _upgradeTags(tags, loc) {
}
}
return newTags;
return { newTags: newTags, matched: item };
}
return changed ? newTags : null;
return changed ? { newTags: newTags, matched: null } : null;
}
@@ -682,7 +691,11 @@ export default {
// `tags`: `Object` containing the feature's OSM tags
// `loc`: Location where this feature exists, as a [lon, lat]
// Returns
// `Object`: The tags the the feature should have, or `null` if no change
// `Object` containing the result, or `null` if no changes needed:
// {
// 'newTags': `Object` - The tags the the feature should have
// 'matched': `Object` - The matched item
// }
//
upgradeTags: (tags, loc) => _upgradeTags(tags, loc),
+43 -5
View File
@@ -66,13 +66,14 @@ export function validationOutdatedTags() {
// Attempt to match a canonical record in the name-suggestion-index.
const nsi = services.nsi;
let waitingForNsi = false;
let nsiResult;
if (nsi) {
waitingForNsi = (nsi.status() === 'loading');
if (!waitingForNsi) {
const loc = entity.extent(graph).center();
const result = nsi.upgradeTags(newTags, loc);
if (result) {
newTags = result;
nsiResult = nsi.upgradeTags(newTags, loc);
if (nsiResult) {
newTags = nsiResult.newTags;
subtype = 'noncanonical_brand';
}
}
@@ -88,7 +89,7 @@ export function validationOutdatedTags() {
const isOnlyAddingTags = tagDiff.every(d => d.type === '+');
let prefix = '';
if (subtype === 'noncanonical_brand') {
if (nsiResult) {
prefix = 'noncanonical_brand.';
} else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
subtype = 'incomplete_tags';
@@ -107,7 +108,7 @@ export function validationOutdatedTags() {
entityIds: [entity.id],
hash: utilHashcode(JSON.stringify(tagDiff)),
dynamicFixes: () => {
return [
let fixes = [
new validationIssueFix({
autoArgs: autoArgs,
title: t.html('issues.fix.upgrade_tags.title'),
@@ -116,6 +117,20 @@ export function validationOutdatedTags() {
}
})
];
const item = nsiResult && nsiResult.matched;
if (item) {
fixes.push(
new validationIssueFix({
title: t.html('issues.fix.tag_as_not.title', { name: item.displayName }),
onClick: (context) => {
context.perform(addNotTag, t('issues.fix.tag_as_not.annotation'));
}
})
);
}
return fixes;
}
}));
return issues;
@@ -138,6 +153,29 @@ export function validationOutdatedTags() {
}
function addNotTag(graph) {
const currEntity = graph.hasEntity(entity.id);
if (!currEntity) return graph;
const item = nsiResult && nsiResult.matched;
if (!item) return graph;
let newTags = Object.assign({}, currEntity.tags); // shallow copy
const wd = item.mainTag; // e.g. `brand:wikidata`
const notwd = `not:${wd}`; // e.g. `not:brand:wikidata`
const qid = item.tags[wd];
newTags[notwd] = qid;
if (newTags[wd] === qid) { // if `brand:wikidata` was set to that qid
const wp = item.mainTag.replace('wikidata', 'wikipedia');
delete newTags[wd]; // remove `brand:wikidata`
delete newTags[wp]; // remove `brand:wikipedia`
}
return actionChangeTags(currEntity.id, newTags)(graph);
}
function showMessage(context) {
const currEntity = context.hasEntity(entity.id);
if (!currEntity) return '';