forked from MapComplete/MapComplete
Feature: add 'onsoftDelete'-option for tagrenderings which will clear when a soft-delete is performed, apply this on pharmacies
This commit is contained in:
parent
34672075d4
commit
e5f0846edd
6 changed files with 186 additions and 102 deletions
|
|
@ -321,7 +321,7 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
|||
editButtonAriaLabel?: Translatable
|
||||
|
||||
/**
|
||||
* What labels should be applied on this tagRendering?
|
||||
* question: What labels should be applied on this tagRendering?
|
||||
*
|
||||
* A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer
|
||||
*
|
||||
|
|
@ -330,4 +330,9 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
|||
* - "description": this label is a description used in the search
|
||||
*/
|
||||
labels?: string[]
|
||||
|
||||
/**
|
||||
* question: What tags should be applied when the object is soft-deleted?
|
||||
*/
|
||||
onSoftDelete?: string[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { Feature } from "geojson"
|
|||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
import { UploadableTag } from "../../Logic/Tags/TagTypes"
|
||||
import LayerConfig from "./LayerConfig"
|
||||
import ComparingTag from "../../Logic/Tags/ComparingTag"
|
||||
|
||||
export interface Mapping {
|
||||
readonly if: UploadableTag
|
||||
|
|
@ -80,12 +81,14 @@ export default class TagRenderingConfig {
|
|||
public readonly labels: string[]
|
||||
public readonly classes: string[] | undefined
|
||||
|
||||
public readonly onSoftDelete?: ReadonlyArray<UploadableTag>
|
||||
|
||||
constructor(
|
||||
config:
|
||||
| string
|
||||
| TagRenderingConfigJson
|
||||
| (QuestionableTagRenderingConfigJson & { questionHintIsMd?: boolean }),
|
||||
context?: string
|
||||
context?: string,
|
||||
) {
|
||||
let json = <string | QuestionableTagRenderingConfigJson>config
|
||||
if (json === undefined) {
|
||||
|
|
@ -142,9 +145,22 @@ export default class TagRenderingConfig {
|
|||
this.questionhint = Translations.T(json.questionHint, translationKey + ".questionHint")
|
||||
this.questionHintIsMd = json["questionHintIsMd"] ?? false
|
||||
this.description = Translations.T(json.description, translationKey + ".description")
|
||||
if(json.onSoftDelete && !Array.isArray(json.onSoftDelete)){
|
||||
throw context+".onSoftDelete Not an array: "+typeof json.onSoftDelete
|
||||
}
|
||||
this.onSoftDelete = json.onSoftDelete?.map(t => {
|
||||
const tag = TagUtils.Tag(t, context)
|
||||
if (tag instanceof RegexTag) {
|
||||
throw context+".onSoftDelete Invalid onSoftDelete: cannot upload tag " + t
|
||||
}
|
||||
if (tag instanceof ComparingTag) {
|
||||
throw context+".onSoftDelete Invalid onSoftDelete: cannot upload tag " + t
|
||||
}
|
||||
return tag
|
||||
})
|
||||
this.editButtonAriaLabel = Translations.T(
|
||||
json.editButtonAriaLabel,
|
||||
translationKey + ".editButtonAriaLabel"
|
||||
translationKey + ".editButtonAriaLabel",
|
||||
)
|
||||
|
||||
this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`)
|
||||
|
|
@ -160,7 +176,7 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
this.metacondition = TagUtils.Tag(
|
||||
json.metacondition ?? { and: [] },
|
||||
`${context}.metacondition`
|
||||
`${context}.metacondition`,
|
||||
)
|
||||
if (json.freeform) {
|
||||
if (
|
||||
|
|
@ -178,7 +194,7 @@ export default class TagRenderingConfig {
|
|||
}, perhaps you meant ${Utils.sortedByLevenshteinDistance(
|
||||
json.freeform.key,
|
||||
<any>Validators.availableTypes,
|
||||
(s) => <any>s
|
||||
(s) => <any>s,
|
||||
)}`
|
||||
}
|
||||
const type: ValidatorType = <any>json.freeform.type ?? "string"
|
||||
|
|
@ -200,7 +216,7 @@ export default class TagRenderingConfig {
|
|||
placeholder,
|
||||
addExtraTags:
|
||||
json.freeform.addExtraTags?.map((tg, i) =>
|
||||
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`)
|
||||
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`),
|
||||
) ?? [],
|
||||
inline: json.freeform.inline ?? false,
|
||||
default: json.freeform.default,
|
||||
|
|
@ -266,8 +282,8 @@ export default class TagRenderingConfig {
|
|||
context,
|
||||
this.multiAnswer,
|
||||
this.question !== undefined,
|
||||
commonIconSize
|
||||
)
|
||||
commonIconSize,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
this.mappings = []
|
||||
|
|
@ -293,7 +309,7 @@ export default class TagRenderingConfig {
|
|||
for (const expectedKey of keys) {
|
||||
if (usedKeys.indexOf(expectedKey) < 0) {
|
||||
const msg = `${context}.mappings[${i}]: This mapping only defines values for ${usedKeys.join(
|
||||
", "
|
||||
", ",
|
||||
)}, but it should also give a value for ${expectedKey}`
|
||||
this.configuration_warnings.push(msg)
|
||||
}
|
||||
|
|
@ -340,7 +356,7 @@ export default class TagRenderingConfig {
|
|||
context: string,
|
||||
multiAnswer?: boolean,
|
||||
isQuestionable?: boolean,
|
||||
commonSize: string = "small"
|
||||
commonSize: string = "small",
|
||||
): Mapping {
|
||||
const ctx = `${translationKey}.mappings.${i}`
|
||||
if (mapping.if === undefined) {
|
||||
|
|
@ -349,7 +365,7 @@ export default class TagRenderingConfig {
|
|||
if (mapping.then === undefined) {
|
||||
if (mapping["render"] !== undefined) {
|
||||
throw `${ctx}: Invalid mapping: no 'then'-clause found. You might have typed 'render' instead of 'then', change it in ${JSON.stringify(
|
||||
mapping
|
||||
mapping,
|
||||
)}`
|
||||
}
|
||||
throw `${ctx}: Invalid mapping: no 'then'-clause found in ${JSON.stringify(mapping)}`
|
||||
|
|
@ -360,7 +376,7 @@ export default class TagRenderingConfig {
|
|||
|
||||
if (mapping["render"] !== undefined) {
|
||||
throw `${ctx}: Invalid mapping: a 'render'-key is present, this is probably a bug: ${JSON.stringify(
|
||||
mapping
|
||||
mapping,
|
||||
)}`
|
||||
}
|
||||
if (typeof mapping.if !== "string" && mapping.if["length"] !== undefined) {
|
||||
|
|
@ -371,8 +387,8 @@ export default class TagRenderingConfig {
|
|||
throw `${ctx}.addExtraTags: expected a list, but got a ${typeof mapping.addExtraTags}`
|
||||
}
|
||||
if (mapping.addExtraTags !== undefined && multiAnswer) {
|
||||
const usedKeys = mapping.addExtraTags?.flatMap((et) => TagUtils.Tag(et).usedKeys())
|
||||
if (usedKeys.some((key) => TagUtils.Tag(mapping.if).usedKeys().indexOf(key) > 0)) {
|
||||
const usedKeys = mapping.addExtraTags?.flatMap((et) => TagUtils.Tag(et, context).usedKeys())
|
||||
if (usedKeys.some((key) => TagUtils.Tag(mapping.if, context).usedKeys().indexOf(key) > 0)) {
|
||||
throw `${ctx}: Invalid mapping: got a multi-Answer with addExtraTags which also modifies one of the keys; this is not allowed`
|
||||
}
|
||||
}
|
||||
|
|
@ -383,11 +399,11 @@ export default class TagRenderingConfig {
|
|||
} else if (mapping.hideInAnswer !== undefined) {
|
||||
hideInAnswer = TagUtils.Tag(
|
||||
mapping.hideInAnswer,
|
||||
`${context}.mapping[${i}].hideInAnswer`
|
||||
`${context}.mapping[${i}].hideInAnswer`,
|
||||
)
|
||||
}
|
||||
const addExtraTags = (mapping.addExtraTags ?? []).map((str, j) =>
|
||||
TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`)
|
||||
TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`),
|
||||
)
|
||||
if (hideInAnswer === true && addExtraTags.length > 0) {
|
||||
throw `${ctx}: Invalid mapping: 'hideInAnswer' is set to 'true', but 'addExtraTags' is enabled as well. This means that extra tags will be applied if this mapping is chosen as answer, but it cannot be chosen as answer. This either indicates a thought error or obsolete code that must be removed.`
|
||||
|
|
@ -483,7 +499,7 @@ export default class TagRenderingConfig {
|
|||
* @constructor
|
||||
*/
|
||||
public GetRenderValues(
|
||||
tags: Record<string, string>
|
||||
tags: Record<string, string>,
|
||||
): { then: Translation; icon?: string; iconClass?: string }[] {
|
||||
if (!this.multiAnswer) {
|
||||
return [this.GetRenderValueWithImage(tags)]
|
||||
|
|
@ -506,7 +522,7 @@ export default class TagRenderingConfig {
|
|||
return mapping
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
if (freeformKeyDefined && tags[this.freeform.key] !== undefined) {
|
||||
|
|
@ -514,7 +530,7 @@ export default class TagRenderingConfig {
|
|||
applicableMappings
|
||||
?.flatMap((m) => m.if?.usedTags() ?? [])
|
||||
?.filter((kv) => kv.key === this.freeform.key)
|
||||
?.map((kv) => kv.value)
|
||||
?.map((kv) => kv.value),
|
||||
)
|
||||
|
||||
const freeformValues = tags[this.freeform.key].split(";")
|
||||
|
|
@ -523,7 +539,7 @@ export default class TagRenderingConfig {
|
|||
applicableMappings.push({
|
||||
then: new TypedTranslation<object>(
|
||||
this.render.replace("{" + this.freeform.key + "}", leftover).translations,
|
||||
this.render.context
|
||||
this.render.context,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
|
@ -541,7 +557,7 @@ export default class TagRenderingConfig {
|
|||
* @constructor
|
||||
*/
|
||||
public GetRenderValueWithImage(
|
||||
tags: Record<string, string>
|
||||
tags: Record<string, string>,
|
||||
): { then: TypedTranslation<any>; icon?: string; iconClass?: string } | undefined {
|
||||
if (this.condition !== undefined) {
|
||||
if (!this.condition.matchesProperties(tags)) {
|
||||
|
|
@ -610,7 +626,7 @@ export default class TagRenderingConfig {
|
|||
const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true)
|
||||
if (key === undefined) {
|
||||
const values: { k: string; v: string }[][] = Utils.NoNull(
|
||||
answerMappings?.map((m) => m.if.asChange({})) ?? []
|
||||
answerMappings?.map((m) => m.if.asChange({})) ?? [],
|
||||
)
|
||||
if (values.length === 0) {
|
||||
return
|
||||
|
|
@ -628,15 +644,15 @@ export default class TagRenderingConfig {
|
|||
return {
|
||||
key: commonKey,
|
||||
values: Utils.NoNull(
|
||||
values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v)
|
||||
values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
let values = Utils.NoNull(
|
||||
answerMappings?.map(
|
||||
(m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v
|
||||
) ?? []
|
||||
(m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v,
|
||||
) ?? [],
|
||||
)
|
||||
if (values.length === undefined) {
|
||||
values = undefined
|
||||
|
|
@ -700,7 +716,7 @@ export default class TagRenderingConfig {
|
|||
freeformValue: string | undefined,
|
||||
singleSelectedMapping: number,
|
||||
multiSelectedMapping: boolean[] | undefined,
|
||||
currentProperties: Record<string, string>
|
||||
currentProperties: Record<string, string>,
|
||||
): UploadableTag {
|
||||
if (typeof freeformValue === "string") {
|
||||
freeformValue = freeformValue?.trim()
|
||||
|
|
@ -775,7 +791,7 @@ export default class TagRenderingConfig {
|
|||
new And([
|
||||
new Tag(this.freeform.key, freeformValue),
|
||||
...(this.freeform.addExtraTags ?? []),
|
||||
])
|
||||
]),
|
||||
)
|
||||
}
|
||||
const and = TagUtils.FlattenMultiAnswer([...selectedMappings, ...unselectedMappings])
|
||||
|
|
@ -845,11 +861,11 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
const msgs: string[] = [
|
||||
icon +
|
||||
" " +
|
||||
"*" +
|
||||
m.then.textFor(lang) +
|
||||
"* is shown if with " +
|
||||
m.if.asHumanString(true, false, {}),
|
||||
" " +
|
||||
"*" +
|
||||
m.then.textFor(lang) +
|
||||
"* is shown if with " +
|
||||
m.if.asHumanString(true, false, {}),
|
||||
]
|
||||
|
||||
if (m.hideInAnswer === true) {
|
||||
|
|
@ -858,11 +874,11 @@ export default class TagRenderingConfig {
|
|||
if (m.ifnot !== undefined) {
|
||||
msgs.push(
|
||||
"Unselecting this answer will add " +
|
||||
m.ifnot.asHumanString(true, false, {})
|
||||
m.ifnot.asHumanString(true, false, {}),
|
||||
)
|
||||
}
|
||||
return msgs.join(". ")
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -871,7 +887,7 @@ export default class TagRenderingConfig {
|
|||
const conditionAsLink = (<TagsFilter>this.condition.optimize()).asHumanString(
|
||||
true,
|
||||
false,
|
||||
{}
|
||||
{},
|
||||
)
|
||||
condition =
|
||||
"This tagrendering is only visible in the popup if the following condition is met: " +
|
||||
|
|
@ -905,7 +921,7 @@ export default class TagRenderingConfig {
|
|||
this.metacondition,
|
||||
this.condition,
|
||||
this.freeform?.key ? new RegexTag(this.freeform?.key, /.*/) : undefined,
|
||||
this.invalidValues
|
||||
this.invalidValues,
|
||||
)
|
||||
for (const m of this.mappings ?? []) {
|
||||
tags.push(m.if)
|
||||
|
|
@ -927,7 +943,7 @@ export default class TagRenderingConfig {
|
|||
*/
|
||||
public removeToSetUnknown(
|
||||
partOfLayer: LayerConfig,
|
||||
currentTags: Record<string, string>
|
||||
currentTags: Record<string, string>,
|
||||
): string[] | undefined {
|
||||
if (!partOfLayer?.source || !currentTags) {
|
||||
return
|
||||
|
|
@ -975,7 +991,7 @@ export class TagRenderingConfigUtils {
|
|||
public static withNameSuggestionIndex(
|
||||
config: TagRenderingConfig,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
feature?: Feature
|
||||
feature?: Feature,
|
||||
): Store<TagRenderingConfig> {
|
||||
const isNSI = NameSuggestionIndex.supportedTypes().indexOf(config.freeform?.key) >= 0
|
||||
if (!isNSI) {
|
||||
|
|
@ -993,8 +1009,8 @@ export class TagRenderingConfigUtils {
|
|||
tags,
|
||||
country.split(";"),
|
||||
center,
|
||||
{ sortByFrequency: true }
|
||||
)
|
||||
{ sortByFrequency: true },
|
||||
),
|
||||
)
|
||||
})
|
||||
return extraMappings.map((extraMappings) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue