Huge refactoring: split readonly and writable stores

This commit is contained in:
Pieter Vander Vennet 2022-06-05 02:24:14 +02:00
parent 0946d8ac9c
commit 4283b76f36
95 changed files with 819 additions and 625 deletions

View file

@ -1,7 +1,7 @@
import {SpecialVisualization} from "../SpecialVisualizations";
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState";
import BaseUIElement from "../BaseUIElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Stores, UIEventSource} from "../../Logic/UIEventSource";
import {DefaultGuiState} from "../DefaultGuiState";
import {SubtleButton} from "../Base/SubtleButton";
import Img from "../Base/Img";
@ -97,7 +97,7 @@ class ApplyButton extends UIElement {
new ShowDataLayer({
leafletMap: previewMap.leafletMap,
zoomToFeatures: true,
features: new StaticFeatureSource(features, false),
features: StaticFeatureSource.fromGeojson(features),
state: this.state,
layerToShow: this.layer.layerDef,
})
@ -218,7 +218,7 @@ export default class AutoApplyButton implements SpecialVisualization {
return new Lazy(() => {
const to_parse = new UIEventSource(undefined)
// Very ugly hack: read the value every 500ms
UIEventSource.Chronic(500, () => to_parse.data === undefined).addCallback(() => {
Stores.Chronic(500, () => to_parse.data === undefined).addCallback(() => {
const applicable = tagSource.data[argument[1]]
to_parse.setData(applicable)
})

View file

@ -3,7 +3,7 @@ import Toggle from "../Input/Toggle";
import Translations from "../i18n/Translations";
import Svg from "../../Svg";
import DeleteAction from "../../Logic/Osm/Actions/DeleteAction";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, UIEventSource} from "../../Logic/UIEventSource";
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import Combine from "../Base/Combine";
import {SubtleButton} from "../Base/SubtleButton";
@ -106,7 +106,7 @@ export default class DeleteWizard extends Toggle {
}
)
const isShown: UIEventSource<boolean> = tagsSource.map(tgs => tgs.id.indexOf("-") < 0)
const isShown: Store<boolean> = tagsSource.map(tgs => tgs.id.indexOf("-") < 0)
const deleteOptionPicker = DeleteWizard.constructMultipleChoice(options, tagsSource, state);
const deleteDialog = new Combine([
@ -350,8 +350,10 @@ class DeleteabilityChecker {
if (allByMyself.data === null && useTheInternet) {
// We kickoff the download here as it hasn't yet been downloaded. Note that this is mapped onto 'all by myself' above
OsmObject.DownloadHistory(id).map(versions => versions.map(version => version.tags["_last_edit:contributor:uid"])).syncWith(previousEditors)
const hist = OsmObject.DownloadHistory(id).map(versions => versions.map(version => version.tags["_last_edit:contributor:uid"]))
hist.addCallbackAndRunD(hist => previousEditors.setData(hist))
}
if (allByMyself.data === true) {
// Yay! We can download!
return true;

View file

@ -241,7 +241,7 @@ ${Utils.special_visualizations_importRequirementDocs}
new ShowDataMultiLayer({
leafletMap: confirmationMap.leafletMap,
zoomToFeatures: true,
features: new StaticFeatureSource([feature], false),
features: StaticFeatureSource.fromGeojson([feature]),
state: state,
layers: state.filteredLayers
})

View file

@ -1,4 +1,4 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store} from "../../Logic/UIEventSource";
import BaseUIElement from "../BaseUIElement";
import Combine from "../Base/Combine";
import {SubtleButton} from "../Base/SubtleButton";
@ -16,12 +16,12 @@ import {OsmConnection} from "../../Logic/Osm/OsmConnection";
export interface MultiApplyParams {
featureIds: UIEventSource<string[]>,
featureIds: Store<string[]>,
keysToApply: string[],
text: string,
autoapply: boolean,
overwrite: boolean,
tagsSource: UIEventSource<any>,
tagsSource: Store<any>,
state: {
changes: Changes,
allElements: ElementStorage,
@ -145,7 +145,7 @@ export default class MultiApply extends Toggle {
}
const isShown: UIEventSource<boolean> = p.state.osmConnection.isLoggedIn.map(loggedIn => {
const isShown: Store<boolean> = p.state.osmConnection.isLoggedIn.map(loggedIn => {
return loggedIn && p.featureIds.data.length > 0
}, [p.featureIds])
super(new Combine(elems), undefined, isShown);

View file

@ -1,7 +1,7 @@
import Combine from "../Base/Combine";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, Stores, UIEventSource} from "../../Logic/UIEventSource";
import {SlideShow} from "../Image/SlideShow";
import Toggle from "../Input/Toggle";
import {ClickableToggle} from "../Input/Toggle";
import Loading from "../Base/Loading";
import {AttributedImage} from "../Image/AttributedImage";
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders";
@ -15,8 +15,6 @@ import {SubtleButton} from "../Base/SubtleButton";
import {GeoOperations} from "../../Logic/GeoOperations";
import {ElementStorage} from "../../Logic/ElementStorage";
import Lazy from "../Base/Lazy";
import {Utils} from "../../Utils";
import beginningOfLine = Mocha.reporters.Base.cursor.beginningOfLine;
export interface P4CPicture {
pictureUrl: string,
@ -42,7 +40,7 @@ export interface NearbyImageOptions {
// Radius of the upstream search
searchRadius?: 500 | number,
maxDaysOld?: 1095 | number,
blacklist: UIEventSource<{ url: string }[]>,
blacklist: Store<{ url: string }[]>,
shownImagesCount?: UIEventSource<number>,
towardscenter?: UIEventSource<boolean>;
allowSpherical?: UIEventSource<boolean>
@ -173,7 +171,7 @@ export default class NearbyImages extends Lazy {
const nearbyImages = state !== undefined ? new ImagesInLoadedDataFetcher(state).fetchAround(options) : []
return UIEventSource.FromPromise<P4CPicture[]>(
return Stores.FromPromise<P4CPicture[]>(
picManager.startPicsRetrievalAround(new P4C.LatLng(options.lat, options.lon), options.searchRadius ?? 500, {
mindate: new Date().getTime() - (options.maxDaysOld ?? (3 * 365)) * 24 * 60 * 60 * 1000,
towardscenter: false
@ -234,7 +232,7 @@ export default class NearbyImages extends Lazy {
return new AttributedImage({url: info.thumbUrl, provider, date: new Date(info.date)})
}
protected asToggle(info: P4CPicture): Toggle {
protected asToggle(info: P4CPicture): ClickableToggle {
const imgNonSelected = NearbyImages.asAttributedImage(info);
const imageSelected = NearbyImages.asAttributedImage(info);
@ -246,7 +244,7 @@ export default class NearbyImages extends Lazy {
hoveringCheckmark,
]).SetClass("relative block")
return new Toggle(selected, nonSelected).SetClass("").ToggleOnClick();
return new ClickableToggle(selected, nonSelected).SetClass("").ToggleOnClick();
}

View file

@ -7,9 +7,8 @@ import Translations from "../i18n/Translations";
import {Utils} from "../../Utils";
import Img from "../Base/Img";
import {SlideShow} from "../Image/SlideShow";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Stores, UIEventSource} from "../../Logic/UIEventSource";
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
import {UIElement} from "../UIElement";
import {VariableUiElement} from "../Base/VariableUIElement";
export default class NoteCommentElement extends Combine {
@ -25,7 +24,7 @@ export default class NoteCommentElement extends Combine {
}) {
const t = Translations.t.notes;
let actionIcon: BaseUIElement = undefined;
let actionIcon: BaseUIElement;
if (comment.action === "opened" || comment.action === "reopened") {
actionIcon = Svg.note_svg()
} else if (comment.action === "closed") {
@ -41,7 +40,7 @@ export default class NoteCommentElement extends Combine {
user = new Link(comment.user, comment.user_url ?? "", true)
}
let userinfo = UIEventSource.FromPromise( Utils.downloadJsonCached("https://www.openstreetmap.org/api/0.6/user/"+comment.uid, 24*60*60*1000))
let userinfo = Stores.FromPromise( Utils.downloadJsonCached("https://www.openstreetmap.org/api/0.6/user/"+comment.uid, 24*60*60*1000))
let userImg = new VariableUiElement( userinfo.map(userinfo => {
const href = userinfo?.user?.img?.href;
if(href !== undefined){

View file

@ -1,4 +1,4 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, UIEventSource} from "../../Logic/UIEventSource";
import TagRenderingQuestion from "./TagRenderingQuestion";
import Translations from "../i18n/Translations";
import Combine from "../Base/Combine";
@ -14,7 +14,7 @@ import Lazy from "../Base/Lazy";
*/
export default class QuestionBox extends VariableUiElement {
public readonly skippedQuestions: UIEventSource<number[]>;
public readonly restingQuestions: UIEventSource<BaseUIElement[]>;
public readonly restingQuestions: Store<BaseUIElement[]>;
constructor(state, options: {
tagsSource: UIEventSource<any>,
@ -81,7 +81,7 @@ export default class QuestionBox extends VariableUiElement {
return undefined; // The questions are depleted
}, [skippedQuestions]);
const questionsToAsk: UIEventSource<BaseUIElement[]> = tagsSource.map(tags => {
const questionsToAsk: Store<BaseUIElement[]> = tagsSource.map(tags => {
if (tags === undefined) {
return [];
}

View file

@ -1,4 +1,4 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, UIEventSource} from "../../Logic/UIEventSource";
import Translations from "../i18n/Translations";
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
import Toggle from "../Input/Toggle";
@ -6,7 +6,7 @@ import BaseUIElement from "../BaseUIElement";
export class SaveButton extends Toggle {
constructor(value: UIEventSource<any>, osmConnection: OsmConnection, textEnabled ?: BaseUIElement, textDisabled ?: BaseUIElement) {
constructor(value: Store<any>, osmConnection: OsmConnection, textEnabled ?: BaseUIElement, textDisabled ?: BaseUIElement) {
if (value === undefined) {
throw "No event source for savebutton, something is wrong"
}

View file

@ -78,7 +78,7 @@ export default class SplitRoadWizard extends Toggle {
// Datalayer displaying the road and the cut points (if any)
new ShowDataMultiLayer({
features: new StaticFeatureSource([roadElement], false),
features: StaticFeatureSource.fromGeojson([roadElement]),
layers: state.filteredLayers,
leafletMap: miniMap.leafletMap,
zoomToFeatures: true,
@ -86,7 +86,7 @@ export default class SplitRoadWizard extends Toggle {
})
new ShowDataLayer({
features: new StaticFeatureSource(splitPoints, true),
features: new StaticFeatureSource(splitPoints),
leafletMap: miniMap.leafletMap,
zoomToFeatures: false,
layerToShow: SplitRoadWizard.splitLayerStyling,

View file

@ -3,7 +3,7 @@ import Translations from "../i18n/Translations";
import {VariableUiElement} from "../Base/VariableUIElement";
import BaseUIElement from "../BaseUIElement";
import {FixedUiElement} from "../Base/FixedUiElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, UIEventSource} from "../../Logic/UIEventSource";
import {SubtleButton} from "../Base/SubtleButton";
import Combine from "../Base/Combine";
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
@ -40,7 +40,7 @@ export default class TagApplyButton implements AutoAction {
];
public readonly example = "`{tag_apply(survey_date=$_now:date, Surveyed today!)}`, `{tag_apply(addr:street=$addr:street, Apply the address, apply_icon.svg, _closest_osm_id)";
public static generateTagsToApply(spec: string, tagSource: UIEventSource<any>): UIEventSource<Tag[]> {
public static generateTagsToApply(spec: string, tagSource: Store<any>): Store<Tag[]> {
const tgsSpec = spec.split(";").map(spec => {
const kv = spec.split("=").map(s => s.trim());

View file

@ -2,7 +2,6 @@ import {UIEventSource} from "../../Logic/UIEventSource";
import {Utils} from "../../Utils";
import BaseUIElement from "../BaseUIElement";
import {VariableUiElement} from "../Base/VariableUIElement";
import List from "../Base/List";
import {SubstitutedTranslation} from "../SubstitutedTranslation";
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
import Combine from "../Base/Combine";

View file

@ -1,6 +1,6 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {Store, Stores, UIEventSource} from "../../Logic/UIEventSource";
import Combine from "../Base/Combine";
import {InputElement} from "../Input/InputElement";
import {InputElement, ReadonlyInputElement} from "../Input/InputElement";
import ValidatedTextField from "../Input/ValidatedTextField";
import {FixedInputElement} from "../Input/FixedInputElement";
import {RadioButton} from "../Input/RadioButton";
@ -45,14 +45,14 @@ export default class TagRenderingQuestion extends Combine {
units?: Unit[],
afterSave?: () => void,
cancelButton?: BaseUIElement,
saveButtonConstr?: (src: UIEventSource<TagsFilter>) => BaseUIElement,
bottomText?: (src: UIEventSource<TagsFilter>) => BaseUIElement
saveButtonConstr?: (src: Store<TagsFilter>) => BaseUIElement,
bottomText?: (src: Store<TagsFilter>) => BaseUIElement
}
) {
const applicableMappingsSrc =
UIEventSource.ListStabilized(tags.map(tags => {
Stores.ListStabilized(tags.map(tags => {
const applicableMappings: { if: TagsFilter, icon?: string, then: TypedTranslation<object>, ifnot?: TagsFilter, addExtraTags: Tag[] }[] = []
for (const mapping of configuration.mappings ?? []) {
if (mapping.hideInAnswer === true) {
@ -81,7 +81,7 @@ export default class TagRenderingQuestion extends Combine {
const feedback = new UIEventSource<Translation>(undefined)
const inputElement: InputElement<TagsFilter> =
const inputElement: ReadonlyInputElement<TagsFilter> =
new VariableInputElement(applicableMappingsSrc.map(applicableMappings =>
TagRenderingQuestion.GenerateInputElement(state, configuration, applicableMappings, applicableUnit, tags, feedback)
))
@ -452,8 +452,8 @@ export default class TagRenderingQuestion extends Combine {
}
public static CreateTagExplanation(selectedValue: UIEventSource<TagsFilter>,
tags: UIEventSource<object>,
public static CreateTagExplanation(selectedValue: Store<TagsFilter>,
tags: Store<object>,
state?: {osmConnection?: OsmConnection}){
return new VariableUiElement(
selectedValue.map(