diff --git a/Models/ThemeConfig/Conversion/PrepareTheme.ts b/Models/ThemeConfig/Conversion/PrepareTheme.ts index 3caf387afa..a1b3379717 100644 --- a/Models/ThemeConfig/Conversion/PrepareTheme.ts +++ b/Models/ThemeConfig/Conversion/PrepareTheme.ts @@ -20,9 +20,9 @@ class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfig this._state = state; } - convert(json: string | LayerConfigJson, context: string): { result: LayerConfigJson[]; errors: string[] } { + convert(json: string | LayerConfigJson, context: string): { result: LayerConfigJson[]; errors: string[], warnings?: string[] } { const errors = [] - const state= this._state + const state= this._state function reportNotFound(name: string){ const knownLayers = Array.from(state.sharedLayers.keys()) const withDistance = knownLayers.map(lname => [lname, Utils.levenshteinDistance(name, lname)]) @@ -55,6 +55,8 @@ class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfig names = [names] } const layers = [] + const warnings = [] + for (const name of names) { const found = Utils.Clone(state.sharedLayers.get(name)) if (found === undefined) { @@ -70,10 +72,48 @@ class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfig } catch (e) { errors.push(`At ${context}: could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(json["override"],)}`) } + + if(json["hideTagRenderingsWithLabels"]){ + const hideLabels: Set = new Set(json["hideTagRenderingsWithLabels"]) + // These labels caused at least one deletion + const usedLabels : Set = new Set(); + const filtered = [] + for (const tr of found.tagRenderings) { + const labels = tr["labels"] + if(labels !== undefined){ + const forbiddenLabel = labels.findIndex(l => hideLabels.has(l)) + if(forbiddenLabel >= 0){ + usedLabels.add(labels[forbiddenLabel]) + warnings.push(context+": Dropping tagRendering "+tr["id"]+" as it has a forbidden label: "+labels[forbiddenLabel]) + continue + } + } + + if(hideLabels.has(tr["id"])){ + usedLabels.add(tr["id"]) + warnings.push(context+": Dropping tagRendering "+tr["id"]+" as its id is a forbidden label") + continue + } + + if(hideLabels.has(tr["group"])){ + usedLabels.add(tr["group"]) + warnings.push(context+": Dropping tagRendering "+tr["id"]+" as its group `"+tr["group"]+"` is a forbidden label") + continue + } + + filtered.push(tr) + } + const unused = Array.from(hideLabels).filter(l => !usedLabels.has(l)) + if(unused.length > 0){ + errors.push("This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: "+unused.join(", ")+"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore") + } + found.tagRenderings = filtered + } } return { result: layers, - errors + errors, + warnings } } diff --git a/Models/ThemeConfig/Json/LayoutConfigJson.ts b/Models/ThemeConfig/Json/LayoutConfigJson.ts index b49fe272fe..11dbbde538 100644 --- a/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/Models/ThemeConfig/Json/LayoutConfigJson.ts @@ -202,7 +202,14 @@ export interface LayoutConfigJson { * } *``` */ - layers: (LayerConfigJson | string | { builtin: string | string[], override: any })[], + layers: (LayerConfigJson | string | + { builtin: string | string[], + override: any, + /** + * TagRenderings with any of these labels will be removed from the layer. + * Note that the 'id' and 'group' are considered labels too + */ + hideTagRenderingsWithLabels?: string[]})[], /** * If defined, data will be clustered. diff --git a/Models/ThemeConfig/Json/TagRenderingConfigJson.ts b/Models/ThemeConfig/Json/TagRenderingConfigJson.ts index c9b3733a38..879fe929b2 100644 --- a/Models/ThemeConfig/Json/TagRenderingConfigJson.ts +++ b/Models/ThemeConfig/Json/TagRenderingConfigJson.ts @@ -20,6 +20,11 @@ export interface TagRenderingConfigJson { */ group?: string + /** + * A list of labels. These are strings that are used for various purposes, e.g. to filter them away + */ + labels?: string[] + /** * Renders this value. Note that "{key}"-parts are substituted by the corresponding values of the element. * If neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value. @@ -27,7 +32,7 @@ export interface TagRenderingConfigJson { * Note that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
` */ render?: string | any, - + /** * If it turns out that this tagRendering doesn't match _any_ value, then we show this question. * If undefined, the question is never asked and this tagrendering is read-only diff --git a/Models/ThemeConfig/TagRenderingConfig.ts b/Models/ThemeConfig/TagRenderingConfig.ts index 833b4ac8ed..5674a24f58 100644 --- a/Models/ThemeConfig/TagRenderingConfig.ts +++ b/Models/ThemeConfig/TagRenderingConfig.ts @@ -19,15 +19,15 @@ import List from "../../UI/Base/List"; */ export default class TagRenderingConfig { - readonly id: string; - readonly group: string; - readonly render?: Translation; - readonly question?: Translation; - readonly condition?: TagsFilter; + public readonly id: string; + public readonly group: string; + public readonly render?: Translation; + public readonly question?: Translation; + public readonly condition?: TagsFilter; - readonly configuration_warnings: string[] = [] + public readonly configuration_warnings: string[] = [] - readonly freeform?: { + public readonly freeform?: { readonly key: string, readonly type: string, readonly placeholder: Translation, @@ -37,9 +37,9 @@ export default class TagRenderingConfig { readonly helperArgs?: (string | number | boolean)[] }; - readonly multiAnswer: boolean; + public readonly multiAnswer: boolean; - readonly mappings?: { + public readonly mappings?: { readonly if: TagsFilter, readonly ifnot?: TagsFilter, readonly then: Translation, @@ -47,6 +47,7 @@ export default class TagRenderingConfig { readonly hideInAnswer: boolean | TagsFilter readonly addExtraTags: Tag[] }[] + public readonly labels: string[] constructor(json: string | TagRenderingConfigJson, context?: string) { if (json === undefined) { @@ -83,6 +84,7 @@ export default class TagRenderingConfig { this.group = json.group ?? ""; + this.labels = json.labels ?? [] this.render = Translations.T(json.render, context + ".render"); this.question = Translations.T(json.question, context + ".question"); this.condition = TagUtils.Tag(json.condition ?? {"and": []}, `${context}.condition`);