forked from MapComplete/MapComplete
Reformat all files with prettier
This commit is contained in:
parent
e22d189376
commit
b541d3eab4
382 changed files with 50893 additions and 35566 deletions
|
@ -1,30 +1,29 @@
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import Toggle from "../Input/Toggle";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Svg from "../../Svg";
|
||||
import DeleteAction from "../../Logic/Osm/Actions/DeleteAction";
|
||||
import {Store, UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import Combine from "../Base/Combine";
|
||||
import {SubtleButton} from "../Base/SubtleButton";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import Constants from "../../Models/Constants";
|
||||
import DeleteConfig from "../../Models/ThemeConfig/DeleteConfig";
|
||||
import {OsmObject} from "../../Logic/Osm/OsmObject";
|
||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
||||
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction";
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
||||
import {InputElement} from "../Input/InputElement";
|
||||
import {RadioButton} from "../Input/RadioButton";
|
||||
import {FixedInputElement} from "../Input/FixedInputElement";
|
||||
import Title from "../Base/Title";
|
||||
import {SubstitutedTranslation} from "../SubstitutedTranslation";
|
||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState";
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion";
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Svg from "../../Svg"
|
||||
import DeleteAction from "../../Logic/Osm/Actions/DeleteAction"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
||||
import Combine from "../Base/Combine"
|
||||
import { SubtleButton } from "../Base/SubtleButton"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Constants from "../../Models/Constants"
|
||||
import DeleteConfig from "../../Models/ThemeConfig/DeleteConfig"
|
||||
import { OsmObject } from "../../Logic/Osm/OsmObject"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction"
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
||||
import { InputElement } from "../Input/InputElement"
|
||||
import { RadioButton } from "../Input/RadioButton"
|
||||
import { FixedInputElement } from "../Input/FixedInputElement"
|
||||
import Title from "../Base/Title"
|
||||
import { SubstitutedTranslation } from "../SubstitutedTranslation"
|
||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion"
|
||||
|
||||
export default class DeleteWizard extends Toggle {
|
||||
|
||||
/**
|
||||
* The UI-element which triggers 'deletion' (either soft or hard).
|
||||
*
|
||||
|
@ -44,11 +43,7 @@ export default class DeleteWizard extends Toggle {
|
|||
* @param state: the state of the application
|
||||
* @param options softDeletionTags: the tags to apply if the user doesn't have permission to delete, e.g. 'disused:amenity=public_bookcase', 'amenity='. After applying, the element should not be picked up on the map anymore. If undefined, the wizard will only show up if the point can be (hard) deleted
|
||||
*/
|
||||
constructor(id: string,
|
||||
state: FeaturePipelineState,
|
||||
options: DeleteConfig) {
|
||||
|
||||
|
||||
constructor(id: string, state: FeaturePipelineState, options: DeleteConfig) {
|
||||
const deleteAbility = new DeleteabilityChecker(id, state, options.neededChangesets)
|
||||
const tagsSource = state.allElements.getEventSourceById(id)
|
||||
|
||||
|
@ -57,239 +52,262 @@ export default class DeleteWizard extends Toggle {
|
|||
|
||||
const confirm = new UIEventSource<boolean>(false)
|
||||
|
||||
|
||||
/**
|
||||
* This function is the actual delete function
|
||||
*/
|
||||
function doDelete(selected: { deleteReason: string } | { retagTo: TagsFilter }) {
|
||||
let actionToTake: OsmChangeAction;
|
||||
let actionToTake: OsmChangeAction
|
||||
if (selected["retagTo"] !== undefined) {
|
||||
// no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping
|
||||
actionToTake = new ChangeTagAction(
|
||||
id,
|
||||
selected["retagTo"],
|
||||
tagsSource.data,
|
||||
{
|
||||
theme: state?.layoutToUse?.id ?? "unkown",
|
||||
changeType: "special-delete"
|
||||
}
|
||||
)
|
||||
actionToTake = new ChangeTagAction(id, selected["retagTo"], tagsSource.data, {
|
||||
theme: state?.layoutToUse?.id ?? "unkown",
|
||||
changeType: "special-delete",
|
||||
})
|
||||
} else {
|
||||
|
||||
actionToTake = new DeleteAction(id,
|
||||
actionToTake = new DeleteAction(
|
||||
id,
|
||||
options.softDeletionTags,
|
||||
{
|
||||
theme: state?.layoutToUse?.id ?? "unkown",
|
||||
specialMotivation: selected["deleteReason"]
|
||||
specialMotivation: selected["deleteReason"],
|
||||
},
|
||||
deleteAbility.canBeDeleted.data.canBeDeleted
|
||||
)
|
||||
}
|
||||
state.changes?.applyAction(actionToTake)
|
||||
isDeleted.setData(true)
|
||||
|
||||
}
|
||||
|
||||
|
||||
const t = Translations.t.delete
|
||||
const cancelButton = t.cancel.SetClass("block btn btn-secondary").onClick(() => confirm.setData(false));
|
||||
const cancelButton = t.cancel
|
||||
.SetClass("block btn btn-secondary")
|
||||
.onClick(() => confirm.setData(false))
|
||||
|
||||
/**
|
||||
* The button which is shown first. Opening it will trigger the check for deletions
|
||||
*/
|
||||
const deleteButton = new SubtleButton(
|
||||
Svg.delete_icon_svg().SetStyle("width: 1.5rem; height: 1.5rem;"), t.delete)
|
||||
.onClick(
|
||||
() => {
|
||||
deleteAbility.CheckDeleteability(true)
|
||||
confirm.setData(true);
|
||||
}
|
||||
)
|
||||
Svg.delete_icon_svg().SetStyle("width: 1.5rem; height: 1.5rem;"),
|
||||
t.delete
|
||||
).onClick(() => {
|
||||
deleteAbility.CheckDeleteability(true)
|
||||
confirm.setData(true)
|
||||
})
|
||||
|
||||
const isShown: Store<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 deleteOptionPicker = DeleteWizard.constructMultipleChoice(options, tagsSource, state)
|
||||
const deleteDialog = new Combine([
|
||||
|
||||
|
||||
new Title(new SubstitutedTranslation(t.whyDelete, tagsSource, state)
|
||||
.SetClass("question-text"), 3),
|
||||
new Title(
|
||||
new SubstitutedTranslation(t.whyDelete, tagsSource, state).SetClass(
|
||||
"question-text"
|
||||
),
|
||||
3
|
||||
),
|
||||
deleteOptionPicker,
|
||||
new Combine([
|
||||
DeleteWizard.constructExplanation(deleteOptionPicker.GetValue(), deleteAbility, tagsSource, state),
|
||||
DeleteWizard.constructExplanation(
|
||||
deleteOptionPicker.GetValue(),
|
||||
deleteAbility,
|
||||
tagsSource,
|
||||
state
|
||||
),
|
||||
new Combine([
|
||||
|
||||
cancelButton,
|
||||
DeleteWizard.constructConfirmButton(deleteOptionPicker.GetValue())
|
||||
.onClick(() => doDelete(deleteOptionPicker.GetValue().data))
|
||||
]).SetClass("flex justify-end flex-wrap-reverse")
|
||||
|
||||
]).SetClass("flex mt-2 justify-between")
|
||||
|
||||
|
||||
cancelButton,
|
||||
DeleteWizard.constructConfirmButton(deleteOptionPicker.GetValue()).onClick(() =>
|
||||
doDelete(deleteOptionPicker.GetValue().data)
|
||||
),
|
||||
]).SetClass("flex justify-end flex-wrap-reverse"),
|
||||
]).SetClass("flex mt-2 justify-between"),
|
||||
]).SetClass("question")
|
||||
|
||||
|
||||
super(
|
||||
new Toggle(
|
||||
new Combine([Svg.delete_icon_svg().SetClass("h-16 w-16 p-2 m-2 block bg-gray-300 rounded-full"),
|
||||
t.isDeleted]).SetClass("flex m-2 rounded-full"),
|
||||
new Combine([
|
||||
Svg.delete_icon_svg().SetClass(
|
||||
"h-16 w-16 p-2 m-2 block bg-gray-300 rounded-full"
|
||||
),
|
||||
t.isDeleted,
|
||||
]).SetClass("flex m-2 rounded-full"),
|
||||
new Toggle(
|
||||
new Toggle(
|
||||
new Toggle(
|
||||
new Toggle(
|
||||
deleteDialog,
|
||||
new SubtleButton(Svg.envelope_ui(), t.readMessages),
|
||||
state.osmConnection.userDetails.map(ud => ud.csCount > Constants.userJourney.addNewPointWithUnreadMessagesUnlock || ud.unreadMessages == 0)
|
||||
state.osmConnection.userDetails.map(
|
||||
(ud) =>
|
||||
ud.csCount >
|
||||
Constants.userJourney
|
||||
.addNewPointWithUnreadMessagesUnlock ||
|
||||
ud.unreadMessages == 0
|
||||
)
|
||||
),
|
||||
|
||||
deleteButton,
|
||||
confirm),
|
||||
new VariableUiElement(deleteAbility.canBeDeleted.map(cbd =>
|
||||
|
||||
new Combine([
|
||||
Svg.delete_not_allowed_svg().SetStyle("height: 2rem; width: auto").SetClass("mr-2"),
|
||||
confirm
|
||||
),
|
||||
new VariableUiElement(
|
||||
deleteAbility.canBeDeleted.map((cbd) =>
|
||||
new Combine([
|
||||
t.cannotBeDeleted,
|
||||
cbd.reason.SetClass("subtle"),
|
||||
t.useSomethingElse.SetClass("subtle")]).SetClass("flex flex-col")
|
||||
]).SetClass("flex m-2 p-2 rounded-lg bg-gray-200 bg-gray-200")))
|
||||
Svg.delete_not_allowed_svg()
|
||||
.SetStyle("height: 2rem; width: auto")
|
||||
.SetClass("mr-2"),
|
||||
new Combine([
|
||||
t.cannotBeDeleted,
|
||||
cbd.reason.SetClass("subtle"),
|
||||
t.useSomethingElse.SetClass("subtle"),
|
||||
]).SetClass("flex flex-col"),
|
||||
]).SetClass("flex m-2 p-2 rounded-lg bg-gray-200 bg-gray-200")
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
,
|
||||
deleteAbility.canBeDeleted.map(cbd => allowSoftDeletion || cbd.canBeDeleted !== false)),
|
||||
deleteAbility.canBeDeleted.map(
|
||||
(cbd) => allowSoftDeletion || cbd.canBeDeleted !== false
|
||||
)
|
||||
),
|
||||
|
||||
t.loginToDelete.onClick(state.osmConnection.AttemptLogin),
|
||||
state.osmConnection.isLoggedIn
|
||||
),
|
||||
isDeleted),
|
||||
isDeleted
|
||||
),
|
||||
undefined,
|
||||
isShown)
|
||||
|
||||
isShown
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private static constructConfirmButton(deleteReasons: UIEventSource<any | undefined>): BaseUIElement {
|
||||
const t = Translations.t.delete;
|
||||
private static constructConfirmButton(
|
||||
deleteReasons: UIEventSource<any | undefined>
|
||||
): BaseUIElement {
|
||||
const t = Translations.t.delete
|
||||
const btn = new Combine([
|
||||
Svg.delete_icon_ui().SetClass("w-6 h-6 mr-3 block"),
|
||||
t.delete
|
||||
t.delete,
|
||||
]).SetClass("flex btn bg-red-500")
|
||||
|
||||
|
||||
const btnNonActive = new Combine([
|
||||
Svg.delete_icon_ui().SetClass("w-6 h-6 mr-3 block"),
|
||||
t.delete
|
||||
t.delete,
|
||||
]).SetClass("flex btn btn-disabled bg-red-200")
|
||||
|
||||
return new Toggle(
|
||||
btn,
|
||||
btnNonActive,
|
||||
deleteReasons.map(reason => reason !== undefined)
|
||||
deleteReasons.map((reason) => reason !== undefined)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private static constructExplanation(
|
||||
selectedOption: UIEventSource<{ deleteReason: string } | { retagTo: TagsFilter }>,
|
||||
deleteAction: DeleteabilityChecker,
|
||||
currentTags: UIEventSource<object>,
|
||||
state?: { osmConnection?: OsmConnection }
|
||||
) {
|
||||
const t = Translations.t.delete
|
||||
return new VariableUiElement(
|
||||
selectedOption.map(
|
||||
(selectedOption) => {
|
||||
if (selectedOption === undefined) {
|
||||
return t.explanations.selectReason.SetClass("subtle")
|
||||
}
|
||||
|
||||
private static constructExplanation(selectedOption: UIEventSource<
|
||||
{deleteReason: string} | {retagTo: TagsFilter}>, deleteAction: DeleteabilityChecker,
|
||||
currentTags: UIEventSource<object>,
|
||||
state?: {osmConnection?: OsmConnection}) {
|
||||
const t = Translations.t.delete;
|
||||
return new VariableUiElement(selectedOption.map(
|
||||
selectedOption => {
|
||||
if (selectedOption === undefined) {
|
||||
return t.explanations.selectReason.SetClass("subtle");
|
||||
}
|
||||
const retag: TagsFilter | undefined = selectedOption["retagTo"]
|
||||
if (retag !== undefined) {
|
||||
// This is a retagging, not a deletion of any kind
|
||||
return new Combine([
|
||||
t.explanations.retagNoOtherThemes,
|
||||
TagRenderingQuestion.CreateTagExplanation(
|
||||
new UIEventSource<TagsFilter>(retag),
|
||||
currentTags,
|
||||
state
|
||||
).SetClass("subtle"),
|
||||
])
|
||||
}
|
||||
|
||||
const retag: TagsFilter | undefined = selectedOption["retagTo"]
|
||||
if(retag !== undefined) {
|
||||
// This is a retagging, not a deletion of any kind
|
||||
return new Combine([t.explanations.retagNoOtherThemes,
|
||||
TagRenderingQuestion.CreateTagExplanation(new UIEventSource<TagsFilter>(retag),
|
||||
currentTags, state
|
||||
).SetClass("subtle")
|
||||
])
|
||||
}
|
||||
|
||||
const deleteReason = selectedOption["deleteReason"];
|
||||
if(deleteReason !== undefined){
|
||||
return new VariableUiElement(deleteAction.canBeDeleted.map(({
|
||||
canBeDeleted, reason
|
||||
}) => {
|
||||
if(canBeDeleted){
|
||||
// This is a hard delete for which we give an explanation
|
||||
return t.explanations.hardDelete;
|
||||
}
|
||||
// This is a soft deletion: we explain _why_ the deletion is soft
|
||||
return t.explanations.softDelete.Subs({reason: reason})
|
||||
|
||||
}))
|
||||
|
||||
}
|
||||
}
|
||||
, [deleteAction.canBeDeleted]
|
||||
)).SetClass("block")
|
||||
const deleteReason = selectedOption["deleteReason"]
|
||||
if (deleteReason !== undefined) {
|
||||
return new VariableUiElement(
|
||||
deleteAction.canBeDeleted.map(({ canBeDeleted, reason }) => {
|
||||
if (canBeDeleted) {
|
||||
// This is a hard delete for which we give an explanation
|
||||
return t.explanations.hardDelete
|
||||
}
|
||||
// This is a soft deletion: we explain _why_ the deletion is soft
|
||||
return t.explanations.softDelete.Subs({ reason: reason })
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
[deleteAction.canBeDeleted]
|
||||
)
|
||||
).SetClass("block")
|
||||
}
|
||||
|
||||
private static constructMultipleChoice(config: DeleteConfig, tagsSource: UIEventSource<Record<string, string>>, state: FeaturePipelineState):
|
||||
InputElement<{ deleteReason: string } | { retagTo: TagsFilter }> {
|
||||
|
||||
const elements: InputElement<{ deleteReason: string } | { retagTo: TagsFilter }>[ ] = []
|
||||
private static constructMultipleChoice(
|
||||
config: DeleteConfig,
|
||||
tagsSource: UIEventSource<Record<string, string>>,
|
||||
state: FeaturePipelineState
|
||||
): InputElement<{ deleteReason: string } | { retagTo: TagsFilter }> {
|
||||
const elements: InputElement<{ deleteReason: string } | { retagTo: TagsFilter }>[] = []
|
||||
|
||||
for (const nonDeleteOption of config.nonDeleteMappings) {
|
||||
elements.push(new FixedInputElement(
|
||||
new SubstitutedTranslation(nonDeleteOption.then, tagsSource, state),
|
||||
{
|
||||
retagTo: nonDeleteOption.if
|
||||
}
|
||||
))
|
||||
elements.push(
|
||||
new FixedInputElement(
|
||||
new SubstitutedTranslation(nonDeleteOption.then, tagsSource, state),
|
||||
{
|
||||
retagTo: nonDeleteOption.if,
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
for (const extraDeleteReason of (config.extraDeleteReasons ?? [])) {
|
||||
elements.push(new FixedInputElement(
|
||||
new SubstitutedTranslation(extraDeleteReason.explanation, tagsSource, state),
|
||||
{
|
||||
deleteReason: extraDeleteReason.changesetMessage
|
||||
}
|
||||
))
|
||||
for (const extraDeleteReason of config.extraDeleteReasons ?? []) {
|
||||
elements.push(
|
||||
new FixedInputElement(
|
||||
new SubstitutedTranslation(extraDeleteReason.explanation, tagsSource, state),
|
||||
{
|
||||
deleteReason: extraDeleteReason.changesetMessage,
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
for (const extraDeleteReason of DeleteConfig.defaultDeleteReasons) {
|
||||
elements.push(new FixedInputElement(
|
||||
extraDeleteReason.explanation.Clone(/*Must clone here, as this explanation might be used on many locations*/),
|
||||
{
|
||||
deleteReason: extraDeleteReason.changesetMessage
|
||||
}
|
||||
))
|
||||
elements.push(
|
||||
new FixedInputElement(
|
||||
extraDeleteReason.explanation.Clone(/*Must clone here, as this explanation might be used on many locations*/),
|
||||
{
|
||||
deleteReason: extraDeleteReason.changesetMessage,
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return new RadioButton(elements, {selectFirstAsDefault: false});
|
||||
return new RadioButton(elements, { selectFirstAsDefault: false })
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class DeleteabilityChecker {
|
||||
|
||||
public readonly canBeDeleted: UIEventSource<{ canBeDeleted?: boolean, reason: Translation }>;
|
||||
private readonly _id: string;
|
||||
private readonly _allowDeletionAtChangesetCount: number;
|
||||
public readonly canBeDeleted: UIEventSource<{ canBeDeleted?: boolean; reason: Translation }>
|
||||
private readonly _id: string
|
||||
private readonly _allowDeletionAtChangesetCount: number
|
||||
private readonly _state: {
|
||||
osmConnection: OsmConnection
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
constructor(id: string,
|
||||
state: { osmConnection: OsmConnection },
|
||||
allowDeletionAtChangesetCount?: number) {
|
||||
this._id = id;
|
||||
this._state = state;
|
||||
this._allowDeletionAtChangesetCount = allowDeletionAtChangesetCount ?? Number.MAX_VALUE;
|
||||
constructor(
|
||||
id: string,
|
||||
state: { osmConnection: OsmConnection },
|
||||
allowDeletionAtChangesetCount?: number
|
||||
) {
|
||||
this._id = id
|
||||
this._state = state
|
||||
this._allowDeletionAtChangesetCount = allowDeletionAtChangesetCount ?? Number.MAX_VALUE
|
||||
|
||||
this.canBeDeleted = new UIEventSource<{ canBeDeleted?: boolean; reason: Translation }>({
|
||||
canBeDeleted: undefined,
|
||||
reason: Translations.t.delete.loading
|
||||
reason: Translations.t.delete.loading,
|
||||
})
|
||||
this.CheckDeleteability(false)
|
||||
}
|
||||
|
@ -301,145 +319,151 @@ class DeleteabilityChecker {
|
|||
* @private
|
||||
*/
|
||||
public CheckDeleteability(useTheInternet: boolean): void {
|
||||
const t = Translations.t.delete;
|
||||
const id = this._id;
|
||||
const t = Translations.t.delete
|
||||
const id = this._id
|
||||
const state = this.canBeDeleted
|
||||
const self = this;
|
||||
const self = this
|
||||
if (!id.startsWith("node")) {
|
||||
this.canBeDeleted.setData({
|
||||
canBeDeleted: false,
|
||||
reason: t.isntAPoint
|
||||
reason: t.isntAPoint,
|
||||
})
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// Does the currently logged in user have enough experience to delete this point?
|
||||
const deletingPointsOfOtherAllowed = this._state.osmConnection.userDetails.map(ud => {
|
||||
const deletingPointsOfOtherAllowed = this._state.osmConnection.userDetails.map((ud) => {
|
||||
if (ud === undefined) {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
if (!ud.loggedIn) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
return ud.csCount >= Math.min(Constants.userJourney.deletePointsOfOthersUnlock, this._allowDeletionAtChangesetCount);
|
||||
return (
|
||||
ud.csCount >=
|
||||
Math.min(
|
||||
Constants.userJourney.deletePointsOfOthersUnlock,
|
||||
this._allowDeletionAtChangesetCount
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
const previousEditors = new UIEventSource<number[]>(undefined)
|
||||
const allByMyself = previousEditors.map(previous => {
|
||||
if (previous === null || previous === undefined) {
|
||||
// Not yet downloaded
|
||||
return null;
|
||||
}
|
||||
const userId = self._state.osmConnection.userDetails.data.uid;
|
||||
return !previous.some(editor => editor !== userId)
|
||||
}, [self._state.osmConnection.userDetails])
|
||||
|
||||
const allByMyself = previousEditors.map(
|
||||
(previous) => {
|
||||
if (previous === null || previous === undefined) {
|
||||
// Not yet downloaded
|
||||
return null
|
||||
}
|
||||
const userId = self._state.osmConnection.userDetails.data.uid
|
||||
return !previous.some((editor) => editor !== userId)
|
||||
},
|
||||
[self._state.osmConnection.userDetails]
|
||||
)
|
||||
|
||||
// User allowed OR only edited by self?
|
||||
const deletetionAllowed = deletingPointsOfOtherAllowed.map(isAllowed => {
|
||||
if (isAllowed === undefined) {
|
||||
// No logged in user => definitively not allowed to delete!
|
||||
return false;
|
||||
}
|
||||
if (isAllowed === true) {
|
||||
return true;
|
||||
}
|
||||
const deletetionAllowed = deletingPointsOfOtherAllowed.map(
|
||||
(isAllowed) => {
|
||||
if (isAllowed === undefined) {
|
||||
// No logged in user => definitively not allowed to delete!
|
||||
return false
|
||||
}
|
||||
if (isAllowed === true) {
|
||||
return true
|
||||
}
|
||||
|
||||
// At this point, the logged in user is not allowed to delete points created/edited by _others_
|
||||
// however, we query OSM and if it turns out the current point has only be edited by the current user, deletion is allowed after all!
|
||||
// At this point, the logged in user is not allowed to delete points created/edited by _others_
|
||||
// however, we query OSM and if it turns out the current point has only be edited by the current user, deletion is allowed after all!
|
||||
|
||||
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
|
||||
const hist = OsmObject.DownloadHistory(id).map(versions => versions.map(version => Number(version.tags["_last_edit:contributor:uid"])))
|
||||
hist.addCallbackAndRunD(hist => previousEditors.setData(hist))
|
||||
}
|
||||
|
||||
if (allByMyself.data === true) {
|
||||
// Yay! We can download!
|
||||
return true;
|
||||
}
|
||||
if (allByMyself.data === false) {
|
||||
// Nope, downloading not allowed...
|
||||
return false;
|
||||
}
|
||||
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
|
||||
const hist = OsmObject.DownloadHistory(id).map((versions) =>
|
||||
versions.map((version) =>
|
||||
Number(version.tags["_last_edit:contributor:uid"])
|
||||
)
|
||||
)
|
||||
hist.addCallbackAndRunD((hist) => previousEditors.setData(hist))
|
||||
}
|
||||
|
||||
if (allByMyself.data === true) {
|
||||
// Yay! We can download!
|
||||
return true
|
||||
}
|
||||
if (allByMyself.data === false) {
|
||||
// Nope, downloading not allowed...
|
||||
return false
|
||||
}
|
||||
|
||||
// At this point, we don't have enough information yet to decide if the user is allowed to delete the current point...
|
||||
return undefined;
|
||||
}, [allByMyself])
|
||||
|
||||
// At this point, we don't have enough information yet to decide if the user is allowed to delete the current point...
|
||||
return undefined
|
||||
},
|
||||
[allByMyself]
|
||||
)
|
||||
|
||||
const hasRelations: UIEventSource<boolean> = new UIEventSource<boolean>(null)
|
||||
const hasWays: UIEventSource<boolean> = new UIEventSource<boolean>(null)
|
||||
deletetionAllowed.addCallbackAndRunD(deletetionAllowed => {
|
||||
|
||||
deletetionAllowed.addCallbackAndRunD((deletetionAllowed) => {
|
||||
if (deletetionAllowed === false) {
|
||||
// Nope, we are not allowed to delete
|
||||
state.setData({
|
||||
canBeDeleted: false,
|
||||
reason: t.notEnoughExperience
|
||||
reason: t.notEnoughExperience,
|
||||
})
|
||||
return true; // unregister this caller!
|
||||
return true // unregister this caller!
|
||||
}
|
||||
|
||||
if (!useTheInternet) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// All right! We have arrived at a point that we should query OSM again to check that the point isn't a part of ways or relations
|
||||
OsmObject.DownloadReferencingRelations(id).then(rels => {
|
||||
OsmObject.DownloadReferencingRelations(id).then((rels) => {
|
||||
hasRelations.setData(rels.length > 0)
|
||||
})
|
||||
|
||||
OsmObject.DownloadReferencingWays(id).then(ways => {
|
||||
OsmObject.DownloadReferencingWays(id).then((ways) => {
|
||||
hasWays.setData(ways.length > 0)
|
||||
})
|
||||
return true; // unregister to only run once
|
||||
return true // unregister to only run once
|
||||
})
|
||||
|
||||
|
||||
const hasWaysOrRelations = hasRelations.map(hasRelationsData => {
|
||||
if (hasRelationsData === true) {
|
||||
return true;
|
||||
}
|
||||
if (hasWays.data === true) {
|
||||
return true;
|
||||
}
|
||||
if (hasWays.data === null || hasRelationsData === null) {
|
||||
return null;
|
||||
}
|
||||
if (hasWays.data === false && hasRelationsData === false) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}, [hasWays])
|
||||
|
||||
hasWaysOrRelations.addCallbackAndRun(
|
||||
waysOrRelations => {
|
||||
if (waysOrRelations == null) {
|
||||
// Not yet loaded - we still wait a little bit
|
||||
return;
|
||||
const hasWaysOrRelations = hasRelations.map(
|
||||
(hasRelationsData) => {
|
||||
if (hasRelationsData === true) {
|
||||
return true
|
||||
}
|
||||
if (waysOrRelations) {
|
||||
// not deleteble by mapcomplete
|
||||
state.setData({
|
||||
canBeDeleted: false,
|
||||
reason: t.partOfOthers
|
||||
})
|
||||
} else {
|
||||
// alright, this point can be safely deleted!
|
||||
state.setData({
|
||||
canBeDeleted: true,
|
||||
reason: allByMyself.data === true ? t.onlyEditedByLoggedInUser : t.safeDelete
|
||||
})
|
||||
if (hasWays.data === true) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (hasWays.data === null || hasRelationsData === null) {
|
||||
return null
|
||||
}
|
||||
if (hasWays.data === false && hasRelationsData === false) {
|
||||
return false
|
||||
}
|
||||
return null
|
||||
},
|
||||
[hasWays]
|
||||
)
|
||||
|
||||
|
||||
hasWaysOrRelations.addCallbackAndRun((waysOrRelations) => {
|
||||
if (waysOrRelations == null) {
|
||||
// Not yet loaded - we still wait a little bit
|
||||
return
|
||||
}
|
||||
if (waysOrRelations) {
|
||||
// not deleteble by mapcomplete
|
||||
state.setData({
|
||||
canBeDeleted: false,
|
||||
reason: t.partOfOthers,
|
||||
})
|
||||
} else {
|
||||
// alright, this point can be safely deleted!
|
||||
state.setData({
|
||||
canBeDeleted: true,
|
||||
reason: allByMyself.data === true ? t.onlyEditedByLoggedInUser : t.safeDelete,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue