Add question box as special rendering

This commit is contained in:
Pieter Vander Vennet 2023-03-31 03:28:11 +02:00
parent 15664df63f
commit d47fd7e746
42 changed files with 956 additions and 311 deletions

View file

@ -23,6 +23,8 @@ import predifined_filters from "../../../assets/layers/filters/filters.json"
import { TagConfigJson } from "../Json/TagConfigJson"
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
import ValidationUtils from "./ValidationUtils"
import { RenderingSpecification } from "../../../UI/SpecialVisualization"
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
private static readonly predefinedFilters = ExpandFilter.load_filters()
@ -218,7 +220,7 @@ class ExpandTagRendering extends Conversion<
matchingTrs = layerTrs
} else if (id.startsWith("*")) {
const id_ = id.substring(1)
matchingTrs = layerTrs.filter((tr) => tr.group === id_ || tr.labels?.indexOf(id_) >= 0)
matchingTrs = layerTrs.filter((tr) => tr.labels?.indexOf(id_) >= 0)
} else {
matchingTrs = layerTrs.filter((tr) => tr.id === id || tr.labels?.indexOf(id) >= 0)
}
@ -255,13 +257,6 @@ class ExpandTagRendering extends Conversion<
ctx: string
): TagRenderingConfigJson[] {
const state = this._state
if (tr === "questions") {
return [
{
id: "questions",
},
]
}
if (typeof tr === "string") {
const lookup = this.lookup(tr)
@ -415,6 +410,111 @@ class ExpandTagRendering extends Conversion<
}
}
export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
constructor() {
super(
"Adds a 'questions'-object if no question element is added yet",
["tagRenderings"],
"AddQuestionBox"
)
}
convert(
json: LayerConfigJson,
context: string
): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
if (json.tagRenderings === undefined) {
return { result: json }
}
json = JSON.parse(JSON.stringify(json))
const allSpecials: Exclude<RenderingSpecification, string>[] = []
.concat(
...json.tagRenderings.map((tr) =>
ValidationUtils.getSpecialVisualsationsWithArgs(<TagRenderingConfigJson>tr)
)
)
.filter((spec) => typeof spec !== "string")
const questionSpecials = allSpecials.filter((sp) => sp.func.funcName === "questions")
const noLabels = questionSpecials.filter(
(sp) => sp.args.length === 0 || sp.args[0].trim() === ""
)
const errors: string[] = []
const warnings: string[] = []
if (noLabels.length > 1) {
console.log(json.tagRenderings)
errors.push(
"At " +
context +
": multiple 'questions'-visualisations found which would show _all_ questions. Don't do this"
)
}
// ALl labels that are used in this layer
const allLabels = new Set(
[].concat(...json.tagRenderings.map((tr) => (<TagRenderingConfigJson>tr).labels ?? []))
)
const seen = new Set()
for (const questionSpecial of questionSpecials) {
if (typeof questionSpecial === "string") {
continue
}
const used = questionSpecial.args[0]
?.split(";")
?.map((a) => a.trim())
?.filter((s) => s != "")
const blacklisted = questionSpecial.args[1]
?.split(";")
?.map((a) => a.trim())
?.filter((s) => s != "")
if (blacklisted?.length > 0 && used?.length > 0) {
errors.push(
"At " +
context +
": the {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." +
"\n Whitelisted: " +
used.join(", ") +
"\n Blacklisted: " +
blacklisted.join(", ")
)
}
for (const usedLabel of used) {
if (!allLabels.has(usedLabel)) {
errors.push(
"At " +
context +
": this layers specifies a special question element for label `" +
usedLabel +
"`, but this label doesn't exist.\n" +
" Available labels are " +
Array.from(allLabels).join(", ")
)
}
seen.add(usedLabel)
}
}
if (noLabels.length == 0) {
/* At this point, we know which question labels are not yet handled and which already are handled, and we
* know there is no previous catch-all questions
*/
const question: TagRenderingConfigJson = {
id: "leftover-questions",
render: {
"*": `{questions( ,${Array.from(seen).join(";")})}`,
},
}
json.tagRenderings.push(question)
}
return {
result: json,
errors,
warnings,
}
}
}
export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[]> {
constructor() {
super("Applies a rewrite", [], "ExpandRewrite")

View file

@ -10,7 +10,7 @@ import {
SetDefault,
} from "./Conversion"
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
import { PrepareLayer } from "./PrepareLayer"
import { AddQuestionBox, PrepareLayer } from "./PrepareLayer"
import { LayerConfigJson } from "../Json/LayerConfigJson"
import { Utils } from "../../../Utils"
import Constants from "../../Constants"
@ -336,7 +336,6 @@ export class AddMiniMap extends DesugaringStep<LayerConfigJson> {
if (!hasMinimap) {
layerConfig = { ...layerConfig }
layerConfig.tagRenderings = [...layerConfig.tagRenderings]
layerConfig.tagRenderings.push(state.tagRenderings.get("questions"))
layerConfig.tagRenderings.push(state.tagRenderings.get("minimap"))
}
@ -662,6 +661,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
: new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state),
new AddImportLayers(),
new On("layers", new Each(new AddQuestionBox())),
new On("layers", new Each(new AddMiniMap(state)))
)
}

View file

@ -619,12 +619,12 @@ class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
': detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`'
)
}
if (json.group) {
if (json["group"]) {
errors.push(
"At " +
context +
': groups are deprecated, use `"label": ["' +
json.group +
json["group"] +
'"]` instead'
)
}

View file

@ -1,7 +1,7 @@
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
import { Utils } from "../../../Utils"
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
import { SpecialVisualization } from "../../../UI/SpecialVisualization"
import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization"
export default class ValidationUtils {
/**
@ -11,11 +11,18 @@ export default class ValidationUtils {
public static getSpecialVisualisations(
renderingConfig: TagRenderingConfigJson
): SpecialVisualization[] {
return ValidationUtils.getSpecialVisualsationsWithArgs(renderingConfig).map(
(spec) => spec["func"]
)
}
public static getSpecialVisualsationsWithArgs(
renderingConfig: TagRenderingConfigJson
): RenderingSpecification[] {
const translations: any[] = Utils.NoNull([
renderingConfig.render,
...(renderingConfig.mappings ?? []).map((m) => m.then),
])
const all: SpecialVisualization[] = []
const all: RenderingSpecification[] = []
for (let translation of translations) {
if (typeof translation == "string") {
translation = { "*": translation }
@ -28,9 +35,7 @@ export default class ValidationUtils {
const template = translation[key]
const parts = SpecialVisualizations.constructSpecification(template)
const specials = parts
.filter((p) => typeof p !== "string")
.map((special) => special["func"])
const specials = parts.filter((p) => typeof p !== "string")
all.push(...specials)
}
}