chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2025-03-06 16:21:55 +01:00
parent 8109c13b38
commit 297bb1c498
185 changed files with 2826 additions and 5874 deletions

View file

@ -14,7 +14,6 @@ import {
} from "geojson"
import { Tiles } from "../Models/TileRange"
import { Utils } from "../Utils"
;("use strict")
export class GeoOperations {

View file

@ -9,13 +9,15 @@ import Constants from "../../Models/Constants"
import Locale from "../../UI/i18n/Locale"
import { Utils } from "../../Utils"
export class ThemeSearchIndex {
private readonly themeIndex: Fuse<MinimalThemeInformation>
private readonly layerIndex: Fuse<{ id: string, description }>
private readonly layerIndex: Fuse<{ id: string; description }>
constructor(language: string, themesToSearch?: MinimalThemeInformation[], layersToIgnore: string[] = []) {
constructor(
language: string,
themesToSearch?: MinimalThemeInformation[],
layersToIgnore: string[] = []
) {
const themes = Utils.NoNull(themesToSearch ?? ThemeSearch.officialThemes?.themes)
if (!themes) {
throw "No themes loaded. Did generate:layeroverview fail?"
@ -27,14 +29,17 @@ export class ThemeSearchIndex {
{ name: "id", weight: 2 },
"title." + language,
"keywords." + language,
"shortDescription." + language
]
"shortDescription." + language,
],
}
this.themeIndex = new Fuse(themes.filter(th => th?.id !== "personal"), fuseOptions)
this.themeIndex = new Fuse(
themes.filter((th) => th?.id !== "personal"),
fuseOptions
)
const toIgnore = new Set(layersToIgnore)
const layersAsList: { id: string, description: Record<string, string[]> }[] = []
const layersAsList: { id: string; description: Record<string, string[]> }[] = []
for (const id in ThemeSearch.officialThemes.layers) {
if (Constants.isPriviliged(id)) {
continue
@ -50,7 +55,7 @@ export class ThemeSearchIndex {
minMatchCharLength: 3,
ignoreLocation: true,
threshold: 0.02,
keys: ["id", "description." + language]
keys: ["id", "description." + language],
})
}
@ -61,7 +66,7 @@ export class ThemeSearchIndex {
if (limit) {
result = result.slice(0, limit)
}
return result.map(e => ThemeSearch.officialThemesById.get(e[0]))
return result.map((e) => ThemeSearch.officialThemesById.get(e[0]))
}
public searchWithScores(text: string): Map<string, number> {
@ -76,20 +81,22 @@ export class ThemeSearchIndex {
for (const layer of layerResults) {
const matchingThemes = ThemeSearch.layersToThemes.get(layer.item.id)
const score = layer.score
matchingThemes?.forEach(th => {
matchingThemes?.forEach((th) => {
const previous = result.get(th.id) ?? 10000
result.set(th.id, Math.min(previous, score * 5))
})
}
return result
}
/**
* Builds a search index containing all public and visited themes, but ignoring the layers loaded by the current theme
*/
public static fromState(state: { osmConnection: OsmConnection; theme: ThemeConfig }): Store<ThemeSearchIndex> {
public static fromState(state: {
osmConnection: OsmConnection
theme: ThemeConfig
}): Store<ThemeSearchIndex> {
const layersToIgnore = state.theme.layers.filter((l) => l.isNormal()).map((l) => l.id)
const knownHidden: Store<string[]> = UserRelatedState.initDiscoveredHiddenThemes(
state.osmConnection
@ -97,8 +104,11 @@ export class ThemeSearchIndex {
const otherThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(
(th) => th.id !== state.theme.id
)
return Locale.language.map(language => {
const themes = otherThemes.concat(...knownHidden.data.map(id => ThemeSearch.officialThemesById.get(id)))
return Locale.language.map(
(language) => {
const themes = otherThemes.concat(
...knownHidden.data.map((id) => ThemeSearch.officialThemesById.get(id))
)
return new ThemeSearchIndex(language, themes, layersToIgnore)
},
[knownHidden]
@ -116,9 +126,8 @@ export default class ThemeSearch {
MinimalThemeInformation
>()
/*
* For every layer id, states which themes use the layer
* For every layer id, states which themes use the layer
*/
public static readonly layersToThemes: Map<string, MinimalThemeInformation[]> = new Map()
static {
@ -170,6 +179,4 @@ export default class ThemeSearch {
return `${linkPrefix}`
}
}

View file

@ -68,7 +68,10 @@ export default class SearchState {
)
const themeSearch = ThemeSearchIndex.fromState(state)
this.themeSuggestions = this.searchTerm.mapD((query) => themeSearch.data.search(query, 3), [themeSearch])
this.themeSuggestions = this.searchTerm.mapD(
(query) => themeSearch.data.search(query, 3),
[themeSearch]
)
const layerSearch = new LayerSearch(state.theme)
this.layerSuggestions = this.searchTerm.mapD((query) => layerSearch.search(query, 5))

View file

@ -1,14 +1,42 @@
import { Utils } from "../../Utils"
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
export class ThemeMetaTagging {
public static readonly themeName = "usersettings"
public static readonly themeName = "usersettings"
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/&lt;/g,'<')?.replace(/&gt;/g,'>') ?? '' )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
feat.properties['__current_backgroun'] = 'initial_value'
}
}
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
feat.properties._description
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
?.at(1)
)
Utils.AddLazyProperty(
feat.properties,
"_d",
() => feat.properties._description?.replace(/&lt;/g, "<")?.replace(/&gt;/g, ">") ?? ""
)
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.href.match(/mastodon|en.osm.town/) !== null
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(
feat.properties,
"_mastodon_candidate",
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
)
feat.properties["__current_backgroun"] = "initial_value"
}
}

View file

@ -103,7 +103,10 @@ export default class SubstitutingTag extends TagsFilter {
asChange(properties: Readonly<Record<string, string>>): { k: string; v: string }[] {
if (this._invert) {
throw "An inverted substituting tag can not be used to create a change. The offending tag is " + this.asHumanString()
throw (
"An inverted substituting tag can not be used to create a change. The offending tag is " +
this.asHumanString()
)
}
const v = SubstitutingTag.substituteString(this._value, properties)
if (v.match(/{.*}/) !== null) {

View file

@ -70,7 +70,7 @@ export class AndroidPolyfill {
AndroidPolyfill.backfillGeolocation(AndroidPolyfill.databridgePlugin)
}
public static async openLoginPage(){
public static async openLoginPage() {
await DatabridgePluginSingleton.request<{ oauth_token: string }>({ key: "open:login" })
}
public static async requestLoginCodes() {

View file

@ -117,12 +117,12 @@ export class MangroveIdentity {
return []
}
const allReviews = await MangroveReviews.getReviews({
kid: pem
kid: pem,
})
this.allReviewsById.setData(
allReviews.reviews.map((r) => ({
...r,
...r.payload
...r.payload,
}))
)
})
@ -283,7 +283,9 @@ export default class FeatureReviews {
return cached
}
const themeIsSensitive = state.theme?.enableMorePrivacy
const settings = state.osmConnection.getPreference<"always" | "yes" | "ask" | "hidden">("reviews-allowed")
const settings = state.osmConnection.getPreference<"always" | "yes" | "ask" | "hidden">(
"reviews-allowed"
)
const loadingAllowed = new UIEventSource(false)
settings.addCallbackAndRun((s) => {
console.log("Reviews allowed is", s)
@ -329,7 +331,7 @@ export default class FeatureReviews {
}
const r: Review = {
sub: this.subjectUri.data,
...review
...review,
}
const keypair: CryptoKeyPair = await this._identity.getKeypair()
const jwt = await MangroveReviews.signReview(keypair, r)
@ -344,7 +346,7 @@ export default class FeatureReviews {
...r,
kid,
signature: jwt,
madeByLoggedInUser: new ImmutableStore(true)
madeByLoggedInUser: new ImmutableStore(true),
}
this._reviews.data.push(reviewWithKid)
this._reviews.ping()
@ -402,7 +404,7 @@ export default class FeatureReviews {
signature: reviewData.signature,
madeByLoggedInUser: this._identity.getKeyId().map((user_key_id) => {
return reviewData.kid === user_key_id
})
}),
})
hasNew = true
}
@ -428,8 +430,8 @@ export default class FeatureReviews {
} else if (this._uncertainty > 1000) {
console.error(
"Not fetching reviews. Only got a point and a very big uncertainty range (" +
this._uncertainty +
"), so you'd probably only get garbage. Specify a name"
this._uncertainty +
"), so you'd probably only get garbage. Specify a name"
)
return undefined
}

View file

@ -5,7 +5,10 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
import { And } from "../../Logic/Tags/And"
import { Utils } from "../../Utils"
import { Tag } from "../../Logic/Tags/Tag"
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
import {
MappingConfigJson,
QuestionableTagRenderingConfigJson,
} from "./Json/QuestionableTagRenderingConfigJson"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import { RegexTag } from "../../Logic/Tags/RegexTag"
@ -812,8 +815,14 @@ export default class TagRenderingConfig {
if (and.and.length === 0) {
return undefined
}
console.log(">>> New properties", TagUtils.asProperties(and, currentProperties), this.invalidValues)
if (this.invalidValues?.matchesProperties(TagUtils.asProperties(and, currentProperties))) {
console.log(
">>> New properties",
TagUtils.asProperties(and, currentProperties),
this.invalidValues
)
if (
this.invalidValues?.matchesProperties(TagUtils.asProperties(and, currentProperties))
) {
return undefined
}
return and

View file

@ -225,13 +225,17 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
this.geolocationControl.handleClick()
})
Hotkeys.RegisterHotkey({ nomod: "H" }, Translations.t.hotkeyDocumentation.homeLocation, () => {
const home = this.userRelatedState.osmConnection.userDetails.data?.home
if (!home) {
console.log("No home location set")
Hotkeys.RegisterHotkey(
{ nomod: "H" },
Translations.t.hotkeyDocumentation.homeLocation,
() => {
const home = this.userRelatedState.osmConnection.userDetails.data?.home
if (!home) {
console.log("No home location set")
}
this.mapProperties.location.set(home)
}
this.mapProperties.location.set(home)
})
)
Hotkeys.RegisterHotkey(
{

View file

@ -41,21 +41,24 @@
"oauth_token",
undefined,
"Used to complete the login"
)
),
})
const state = new UserRelatedState(osmConnection)
const guistate = new MenuState(undefined)
const menuDrawerState = {
guistate, osmConnection,
guistate,
osmConnection,
userRelatedState: state,
featureSwitches: { featureSwitchEnableLogin: new UIEventSource(true) }
featureSwitches: { featureSwitchEnableLogin: new UIEventSource(true) },
}
const t = Translations.t.index
const tu = Translations.t.general
const tr = Translations.t.general.morescreen
const recentThemes = state.recentlyVisitedThemes.value.mapD(themes => themes.map(thId => ThemeSearch.officialThemesById.get(thId)))
const recentThemes = state.recentlyVisitedThemes.value.mapD((themes) =>
themes.map((thId) => ThemeSearch.officialThemesById.get(thId))
)
let userLanguages = osmConnection.userDetails.map((ud) => ud?.languages ?? [])
let search: UIEventSource<string | undefined> = new UIEventSource<string>("")
@ -81,10 +84,12 @@
).mapD((stableIds) => Utils.NoNullInplace(stableIds.map((id) => state.getUnofficialTheme(id))))
function filtered(themes: Store<MinimalThemeInformation[]>): Store<MinimalThemeInformation[]> {
const searchIndex = Locale.language.map(language => {
return new ThemeSearchIndex(language, themes.data)
}, [themes])
const searchIndex = Locale.language.map(
(language) => {
return new ThemeSearchIndex(language, themes.data)
},
[themes]
)
return searchStable.map(
(searchTerm) => {
@ -98,7 +103,6 @@
const index = searchIndex.data
return index.search(searchTerm)
},
[searchIndex]
)
@ -113,7 +117,7 @@
let customSearched: Store<MinimalThemeInformation[]> = filtered(customThemes)
let searchIsFocussed = new UIEventSource(false)
document.addEventListener("keydown", function(event) {
document.addEventListener("keydown", function (event) {
if (event.ctrlKey && event.code === "KeyF") {
searchIsFocussed.set(true)
event.preventDefault()
@ -150,7 +154,7 @@
</script>
<main>
<div class="absolute h-screen w-screen bg-white top-0 left-0" style="z-index: -1;"></div>
<div class="absolute left-0 top-0 h-screen w-screen bg-white" style="z-index: -1;" />
<div class="h-full overflow-hidden">
<DrawerLeft shown={guistate.pageStates.menu}>
@ -162,7 +166,7 @@
<div class="m-4 flex flex-col">
<div class="w-ful flex justify-between">
<button on:click={() => guistate.pageStates.menu.set(true)} class="rounded-full m-0 p-2">
<button on:click={() => guistate.pageStates.menu.set(true)} class="m-0 rounded-full p-2">
<MenuIcon class="h-6 w-6 cursor-pointer" />
</button>
@ -179,7 +183,7 @@
<Logo alt="MapComplete Logo" class="h-12 w-12 sm:h-24 sm:w-24" />
</div>
<div class="link-underline flex flex-col w-full">
<div class="link-underline flex w-full flex-col">
<h1 class="m-0 font-extrabold tracking-tight md:text-6xl">
<Tr t={t.title} />
</h1>
@ -259,15 +263,12 @@
{/if}
</LoginToggle>
<div class="subtle mb-16 self-end">
v{Constants.vNumber}
</div>
</div>
<div class="absolute top-0 w-0 h-0" style="margin-left: -10em">
<div class="absolute top-0 h-0 w-0" style="margin-left: -10em">
<MenuDrawer onlyLink={false} state={menuDrawerState} />
</div>
</main>

View file

@ -21,7 +21,8 @@
if (fullscreen) {
defaultClass = shared
}
let dialogClass = "fixed top-0 start-0 end-0 h-modal inset-0 w-full p-4 flex class-marker-dialog " + zIndex
let dialogClass =
"fixed top-0 start-0 end-0 h-modal inset-0 w-full p-4 flex class-marker-dialog " + zIndex
if (fullscreen) {
dialogClass += " h-full-child"
}

View file

@ -13,8 +13,7 @@
}
</script>
<button on:click={() => clear()}>
<Trash class="w-6 h-6" />
<Trash class="h-6 w-6" />
<Tr t={Translations.t.general.removeLocationHistory} />
</button>

View file

@ -17,7 +17,7 @@
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
import { ImmutableStore } from "../../Logic/UIEventSource"
export let state: { theme?: ThemeConfig, mapProperties?: MapProperties }
export let state: { theme?: ThemeConfig; mapProperties?: MapProperties }
const t = Translations.t.general.attribution
const layoutToUse = state.theme
@ -27,27 +27,28 @@
maintainer = t.themeBy.Subs({ author: layoutToUse.credits })
}
const bgMapAttribution = state.mapProperties?.rasterLayer?.mapD((layer) => {
const props = layer.properties
const attrUrl = props.attribution?.url
const attrText = props.attribution?.text
const bgMapAttribution =
state.mapProperties?.rasterLayer?.mapD((layer) => {
const props = layer.properties
const attrUrl = props.attribution?.url
const attrText = props.attribution?.text
let bgAttr: BaseUIElement | string = undefined
if (attrText && attrUrl) {
bgAttr = "<a href='" + attrUrl + "' target='_blank' rel='noopener'>" + attrText + "</a>"
} else if (attrUrl) {
bgAttr = attrUrl
} else {
bgAttr = attrText
}
if (bgAttr) {
return Translations.t.general.attribution.attributionBackgroundLayerWithCopyright.Subs({
name: props.name,
copyright: bgAttr,
})
}
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props)
}) ?? new ImmutableStore(undefined)
let bgAttr: BaseUIElement | string = undefined
if (attrText && attrUrl) {
bgAttr = "<a href='" + attrUrl + "' target='_blank' rel='noopener'>" + attrText + "</a>"
} else if (attrUrl) {
bgAttr = attrUrl
} else {
bgAttr = attrText
}
if (bgAttr) {
return Translations.t.general.attribution.attributionBackgroundLayerWithCopyright.Subs({
name: props.name,
copyright: bgAttr,
})
}
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props)
}) ?? new ImmutableStore(undefined)
function calculateDataContributions(contributions: Map<string, number>): Translation {
if (contributions === undefined) {
@ -83,9 +84,9 @@
}
}
const datacontributions = (state.mapProperties ? new ContributorCount(<any>state).Contributors : new ImmutableStore([])).map((counts) =>
calculateDataContributions(counts)
)
const datacontributions = (
state.mapProperties ? new ContributorCount(<any>state).Contributors : new ImmutableStore([])
).map((counts) => calculateDataContributions(counts))
function codeContributors(
contributors,

View file

@ -64,11 +64,11 @@
export let state: {
favourites: FavouritesFeatureSource
guistate: MenuState,
osmConnection: OsmConnection,
theme?: ThemeConfig,
featureSwitches: Partial<FeatureSwitchState>,
mapProperties?: MapProperties,
guistate: MenuState
osmConnection: OsmConnection
theme?: ThemeConfig
featureSwitches: Partial<FeatureSwitchState>
mapProperties?: MapProperties
userRelatedState?: UserRelatedState
}
let hotkeys = Hotkeys._docs
@ -240,15 +240,15 @@
<a
class="flex"
href={"https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes/" +
theme.id +
".md"}
theme.id +
".md"}
target="_blank"
>
<DocumentMagnifyingGlass class="h-6 w-6" />
<Tr
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
name: theme.title,
})}
name: theme.title,
})}
/>
</a>
@ -256,10 +256,13 @@
<QueueList class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: theme.title })} />
</a>
<a class="flex" href={`./statistics.html?filter-mapcomplete-changes-theme-search={"search"%3A"${theme.id}"}`}
target="_blank">
<a
class="flex"
href={`./statistics.html?filter-mapcomplete-changes-theme-search={"search"%3A"${theme.id}"}`}
target="_blank"
>
<ChartBar class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openStatistics.Subs({theme: theme.title})} />
<Tr t={Translations.t.general.attribution.openStatistics.Subs({ theme: theme.title })} />
</a>
{/if}
</SidebarUnit>
@ -305,7 +308,6 @@
<Tr t={Translations.t.general.morescreen.createYourOwnTheme} />
</a>
<a class="flex" href="mailto:info@mapcomplete.org">
<EnvelopeOpen class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.emailCreators} />
@ -321,7 +323,6 @@
<Tr t={Translations.t.general.attribution.donate} />
</a>
<a
class="flex"
href="https://source.mapcomplete.org/MapComplete/MapComplete/issues"
@ -340,7 +341,6 @@
<Tr t={Translations.t.translations.activateButton} />
</a>
<a
class="flex"
href={window.location.protocol + "//" + window.location.host + "/inspector.html"}
@ -350,10 +350,9 @@
</a>
{#if !state.theme}
<a class="flex" href={`./statistics.html`}
target="_blank">
<a class="flex" href={`./statistics.html`} target="_blank">
<ChartBar class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openStatistics.Subs({theme: "MapComplete"})} />
<Tr t={Translations.t.general.attribution.openStatistics.Subs({ theme: "MapComplete" })} />
</a>
{/if}
@ -389,11 +388,10 @@
<Tr t={Translations.t.privacy.title} />
</svelte:fragment>
<PrivacyPolicy {state} />
<a href="./privacy.html" class="button w-fit float-right" target="_blank">
<ArrowTopRightOnSquare class="w-8 h-8" />
<a href="./privacy.html" class="button float-right w-fit" target="_blank">
<ArrowTopRightOnSquare class="h-8 w-8" />
</a>
</Page>
</SidebarUnit>
<div class="subtle self-end">

View file

@ -15,6 +15,7 @@
const errors = changes?.errors
const pending = changes?.pendingChanges
</script>
{#if changes}
<div
class="pointer-events-auto flex flex-col"

View file

@ -13,12 +13,14 @@
const editThemeHistory = usersettings.tagRenderings.find((tr) => tr.id === "sync-visited-themes")
const editReviews = usersettings.tagRenderings.find((tr) => tr.id === "mangrove-reviews-allowed")
const editLocationHistory = usersettings.tagRenderings.find((tr) => tr.id === "sync-visited-locations")
const editLocationHistory = usersettings.tagRenderings.find(
(tr) => tr.id === "sync-visited-locations"
)
const selectedElement: Feature = {
type: "Feature",
properties: { id: "settings" },
geometry: { type: "Point", coordinates: [0, 0] }
geometry: { type: "Point", coordinates: [0, 0] },
}
const isLoggedIn = state.osmConnection.isLoggedIn
</script>
@ -93,7 +95,6 @@
/>
</li>
<li>
<TagRenderingEditable
config={editThemeHistory}
{selectedElement}
@ -102,8 +103,7 @@
/>
</li>
</ul>
{:else }
{:else}
<button class="as-link" on:click={() => state.osmConnection.AttemptLogin()}>
<Tr t={t.browsingHistoryNotLoggedIn} />
</button>
@ -120,7 +120,6 @@
tags={state.userRelatedState.preferencesAsTags}
/>
<h3>
<Tr t={t.whileYoureHere} />
</h3>

View file

@ -12,7 +12,6 @@ export default class StatisticsForLayerPanel extends VariableUiElement {
super(
elementsInview.features.stabilized(1000).map(
(features) => {
const els: BaseUIElement[] = []
const featuresForLayer = features
if (featuresForLayer.length === 0) {

View file

@ -276,13 +276,8 @@ export default class TagRenderingChart extends Combine {
}
super([
new Title(
options?.includeTitle ? tagRendering.question ?? tagRendering.id : undefined
),
new Combine([
chart
]).SetClass("flex flex-col justify-center h-full")
new Title(options?.includeTitle ? tagRendering.question ?? tagRendering.id : undefined),
new Combine([chart]).SetClass("flex flex-col justify-center h-full"),
])
this.SetClass("block")

View file

@ -19,7 +19,10 @@
<section class="w-full">
<slot name="title" />
<div
class={onlyIcons ? "flex gap-x-2 flex-wrap items-center justify-center" : ("theme-list my-2 gap-4 md:grid md:grid-flow-row md:grid-cols-2 lg:grid-cols-3")}>
class={onlyIcons
? "flex flex-wrap items-center justify-center gap-x-2"
: "theme-list my-2 gap-4 md:grid md:grid-flow-row md:grid-cols-2 lg:grid-cols-3"}
>
{#each Utils.NoNull(themes) as theme (theme.id)}
<ThemeButton {theme} {state} iconOnly={onlyIcons}>
{#if $search && hasSelection && themes?.[0] === theme}

View file

@ -4,7 +4,10 @@ import Translations from "../../i18n/Translations"
export default class RegexValidator extends StringValidator {
constructor() {
super("regex", "Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme.")
super(
"regex",
"Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
)
}
getFeedback(s: string): Translation | undefined {

File diff suppressed because it is too large Load diff

View file

@ -101,7 +101,11 @@ class SingleBackgroundHandler {
private async enable() {
let ttl = 15
await this.awaitStyleIsLoaded()
while (this._background.data.properties.id === this._targetLayer.properties.id && !this.tryEnable() && ttl > 0) {
while (
this._background.data.properties.id === this._targetLayer.properties.id &&
!this.tryEnable() &&
ttl > 0
) {
ttl--
await Utils.waitFor(250)
}
@ -147,7 +151,6 @@ class SingleBackgroundHandler {
console.log("UPDATING")
this._languageSupport.update()
})
} else {
map.addLayer(
{
@ -155,8 +158,8 @@ class SingleBackgroundHandler {
type: "raster",
source: background.id,
paint: {
"raster-opacity": 0
}
"raster-opacity": 0,
},
},
addLayerBeforeId
)
@ -213,7 +216,12 @@ export default class RasterLayerHandler {
background.addCallbackAndRunD((l) => {
const key = l.properties.id
if (!this._singleLayerHandlers[key]) {
this._singleLayerHandlers[key] = new SingleBackgroundHandler(map, l, background, this._languageSupport)
this._singleLayerHandlers[key] = new SingleBackgroundHandler(
map,
l,
background,
this._languageSupport
)
}
})
this._languageSupport = new ProtomapsLanguageSupport(map)
@ -225,7 +233,7 @@ export default class RasterLayerHandler {
if (layer.type === "vector") {
return {
type: "vector",
url: layer.url
url: layer.url,
}
}
return {
@ -237,7 +245,7 @@ export default class RasterLayerHandler {
minzoom: layer["min_zoom"] ?? 1,
maxzoom: layer["max_zoom"] ?? 25,
// Bit of a hack, but seems to work
scheme: layer.url.includes("{-y}") ? "tms" : "xyz"
scheme: layer.url.includes("{-y}") ? "tms" : "xyz",
}
}
@ -251,7 +259,7 @@ export default class RasterLayerHandler {
"{width}": "" + size,
"{height}": "" + size,
"{zoom}": "{z}",
"{-y}": "{y}"
"{-y}": "{y}",
}
for (const key in toReplace) {

View file

@ -172,12 +172,12 @@
<Tr t={Translations.t.general.add.zoomInFurther} />
</div>
{:else if $isLoading}
<div class="w-full h-full p-2 flex items-center justify-center">
<div class="alert">
<Loading>
<Tr t={Translations.t.general.add.stillLoading} />
</Loading>
</div>
<div class="flex h-full w-full items-center justify-center p-2">
<div class="alert">
<Loading>
<Tr t={Translations.t.general.add.stillLoading} />
</Loading>
</div>
</div>
{:else if selectedPreset === undefined}
<!-- First, select the correct preset -->

View file

@ -60,7 +60,7 @@
const review: Omit<Review, "sub"> = {
rating: confirmedScore,
opinion: opinion.data,
metadata: { nickname, is_affiliated: isAffiliated.data }
metadata: { nickname, is_affiliated: isAffiliated.data },
}
try {
await reviews.createReview(review)
@ -73,7 +73,6 @@
</script>
<ReviewPrivacyShield hiddenIfNotAllowed {reviews} guistate={state.guistate}>
{#if uploadFailed}
<div class="alert flex">
<ExclamationTriangle class="h-6 w-6" />
@ -92,21 +91,27 @@
{#if question}
{question}
{:else}
<SpecialTranslation {feature} {layer} {state} t={Translations.t.reviews.question} {tags} />
<SpecialTranslation
{feature}
{layer}
{state}
t={Translations.t.reviews.question}
{tags}
/>
{/if}
</div>
<StarsBar
on:click={(e) => {
confirmedScore = e.detail.score
score = confirmedScore
console.log("Confirmed score is:", confirmedScore)
}}
confirmedScore = e.detail.score
score = confirmedScore
console.log("Confirmed score is:", confirmedScore)
}}
on:hover={(e) => {
score = e.detail.score
}}
score = e.detail.score
}}
on:mouseout={() => {
score = null
}}
score = null
}}
score={score ?? confirmedScore ?? 0}
starSize="w-8 h-8"
/>
@ -127,9 +132,9 @@
<ExclamationTriangle class="h-12 w-12" />
<Tr
t={t.too_long.Subs({
max: FeatureReviews.REVIEW_OPINION_MAX_LENGTH,
amount: $opinion?.length ?? 0,
})}
max: FeatureReviews.REVIEW_OPINION_MAX_LENGTH,
amount: $opinion?.length ?? 0,
})}
/>
</div>
{/if}

View file

@ -1,27 +1,29 @@
<script lang="ts">/**
* Due to privacy, we cannot load reviews unless allowed in the privacy policy
*/
import FeatureReviews from "../../Logic/Web/MangroveReviews"
import { MenuState } from "../../Models/MenuState"
<script lang="ts">
/**
* Due to privacy, we cannot load reviews unless allowed in the privacy policy
*/
import FeatureReviews from "../../Logic/Web/MangroveReviews"
import { MenuState } from "../../Models/MenuState"
export let guistate: MenuState
export let reviews: FeatureReviews
export let hiddenIfNotAllowed: boolean = false
let allowed = reviews.loadingAllowed
export let guistate: MenuState
export let reviews: FeatureReviews
export let hiddenIfNotAllowed: boolean = false
let allowed = reviews.loadingAllowed
</script>
{#if $allowed}
<slot />
{:else if !hiddenIfNotAllowed && $allowed !== null }
<div class="low-interaction flex flex-col rounded mx-1">
{:else if !hiddenIfNotAllowed && $allowed !== null}
<div class="low-interaction mx-1 flex flex-col rounded">
Reviews are disabled due to your privacy settings.
<button on:click={() => reviews.loadingAllowed.set(true)} class="primary">
Load reviews once
</button>
<button class="as-link self-end" on:click={() => guistate.openUsersettings("mangrove-reviews-allowed")}>
<button
class="as-link self-end"
on:click={() => guistate.openUsersettings("mangrove-reviews-allowed")}
>
Edit your privacy settings
</button>
</div>
{/if}

View file

@ -24,7 +24,9 @@ export class SettingsVisualisations {
docs: "A component to set the language of the user interface",
constr(state: SpecialVisualizationState): SvelteUIElement {
const availableLanguages = Locale.showLinkToWeblate.map((showTranslations) =>
showTranslations ? LanguageUtils.usedLanguagesSorted : (state?.theme?.language ?? LanguageUtils.usedLanguagesSorted)
showTranslations
? LanguageUtils.usedLanguagesSorted
: state?.theme?.language ?? LanguageUtils.usedLanguagesSorted
)
return new SvelteUIElement(LanguagePicker, {
assignTo: state.userRelatedState.language,

View file

@ -29,7 +29,7 @@ class QuestionViz implements SpecialVisualizationSvelte {
},
{
name: "blacklisted-labels",
doc: "One or more ';'-separated labels of questions which should _not_ be included. Default: 'hidden'"
doc: "One or more ';'-separated labels of questions which should _not_ be included. Default: 'hidden'",
},
]
svelteBased = true
@ -46,7 +46,7 @@ class QuestionViz implements SpecialVisualizationSvelte {
?.split(";")
?.map((s) => s.trim())
?.filter((s) => s !== "")
const blacklist = (args[1])
const blacklist = args[1]
?.split(";")
?.map((s) => s.trim())
?.filter((s) => s !== "")

View file

@ -1,7 +1,11 @@
import { FixedUiElement } from "./Base/FixedUiElement"
import BaseUIElement from "./BaseUIElement"
import { default as FeatureTitle } from "./Popup/Title.svelte"
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
import {
RenderingSpecification,
SpecialVisualization,
SpecialVisualizationState,
} from "./SpecialVisualization"
import { HistogramViz } from "./Popup/HistogramViz"
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
import { MultiApplyViz } from "./Popup/MultiApplyViz"
@ -36,11 +40,8 @@ import { UISpecialVisualisations } from "./SpecialVisualisations/UISpecialVisual
import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations"
import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations"
import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations"
import TagrenderingManipulationSpecialVisualisations
from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
import {
WebAndCommunicationSpecialVisualisations
} from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
import TagrenderingManipulationSpecialVisualisations from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
import { WebAndCommunicationSpecialVisualisations } from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
import ClearGPSHistory from "./BigComponents/ClearGPSHistory.svelte"
import AllFeaturesStatistics from "./Statistics/AllFeaturesStatistics.svelte"
@ -405,7 +406,7 @@ export default class SpecialVisualizations {
docs: "Show general statistics about the elements currently in view. Intended to use on the `current_view`-layer",
args: [],
constr: (state) => new SvelteUIElement(AllFeaturesStatistics, { state })
constr: (state) => new SvelteUIElement(AllFeaturesStatistics, { state }),
},
{

View file

@ -7,12 +7,10 @@
* An element showing s
*/
export let state: ThemeViewState
let layers = state.theme.layers.filter(l => l.isNormal())
let layers = state.theme.layers.filter((l) => l.isNormal())
</script>
<Accordion>
{#each layers as layer (layer.id)}
<LayerStatistics {state} {layer} />
{/each}

View file

@ -18,12 +18,16 @@
let elements: Feature[] = state.perLayer.get(layer.id).GetFeaturesWithin($bbox)
$: elements = state.perLayer.get(layer.id).GetFeaturesWithin($bbox)
let trs = layer.tagRenderings.filter(tr => tr.question)
let trs = layer.tagRenderings.filter((tr) => tr.question)
</script>
<AccordionItem paddingDefault="p-2" inactiveClass="text-black" defaultClass="w-full flex-grow justify-start">
<AccordionItem
paddingDefault="p-2"
inactiveClass="text-black"
defaultClass="w-full flex-grow justify-start"
>
<div slot="header" class="flex items-center gap-x-2">
<div class="w-8 h-8 inline-block">
<div class="inline-block h-8 w-8">
<DefaultIcon {layer} />
</div>
<Tr t={layer.name} />
@ -35,12 +39,15 @@
{:else if elements.length === 0}
No features in view
{:else}
<div class="flex flex-wrap w-full gap-y-4 gap-x-4">
<div class="flex w-full flex-wrap gap-x-4 gap-y-4">
{#each trs as tr}
<ToSvelte construct={() => new TagRenderingChart(elements, tr, {
chartclasses: "w-full self-center",includeTitle: true
}).SetClass(tr.multiAnswer ? "w-128": "w-96") } />
<ToSvelte
construct={() =>
new TagRenderingChart(elements, tr, {
chartclasses: "w-full self-center",
includeTitle: true,
}).SetClass(tr.multiAnswer ? "w-128" : "w-96")}
/>
{/each}
</div>
{/if}

View file

@ -10,9 +10,7 @@
import QuestionPreview from "./QuestionPreview.svelte"
import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte"
import { EditJsonState } from "./EditLayerState"
import type {
QuestionableTagRenderingConfigJson
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import type { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import { AccordionItem } from "flowbite-svelte"
import { ExclamationTriangle } from "@babeard/svelte-heroicons/solid/ExclamationTriangle"
@ -29,7 +27,7 @@
export let expanded = new UIEventSource(false)
let errors = state.messagesFor(path).mapD(msgs => msgs.filter(msg => msg.level === "error"))
let errors = state.messagesFor(path).mapD((msgs) => msgs.filter((msg) => msg.level === "error"))
const subparts: ConfigMeta[] = state
.getSchemaStartingWith(schema.path)
@ -92,10 +90,10 @@
} catch (e) {
console.log(
"Warning: could not translate a title for " +
`${singular} ${i} with function ` +
schema.hints.title +
" and value " +
JSON.stringify(value)
`${singular} ${i} with function ` +
schema.hints.title +
" and value " +
JSON.stringify(value)
)
}
return Translations.T(`${singular} ${i}`)
@ -152,8 +150,8 @@
{:else}
<Tr cls="font-bold" t={Translations.T(value?.question ?? value?.render)} />
{#if $errors.length > 0}
<div class="alert w-fit inline">
<ExclamationTriangle class="w-6 h-6 inline" />{$errors.length}
<div class="alert inline w-fit">
<ExclamationTriangle class="inline h-6 w-6" />{$errors.length}
</div>
{/if}
{/if}

View file

@ -76,7 +76,8 @@
let selfLayers = layers.mapD(
(ls) =>
ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
(l) =>
l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
),
[uid, layerFilterTerm]
)
@ -93,7 +94,8 @@
let officialLayers = layers.mapD(
(ls) =>
ls.filter(
(l) => l.owner === undefined && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
(l) =>
l.owner === undefined && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
),
[uid, layerFilterTerm]
)
@ -106,7 +108,8 @@
let selfThemes = themes.mapD(
(ls) =>
ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
(l) =>
l.owner === uid.data && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
),
[uid, themeFilterTerm]
)
@ -123,7 +126,8 @@
let officialThemes = themes.mapD(
(ls) =>
ls.filter(
(l) => l.owner === undefined && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
(l) =>
l.owner === undefined && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
),
[uid, themeFilterTerm]
)
@ -340,11 +344,7 @@
Selecting a layer will create a copy in your account. You will not change the version that
is in MapComplete
</div>
<ChooseLayerToEdit
{osmConnection}
layerIds={officialLayers}
on:layerSelected={editLayer}
/>
<ChooseLayerToEdit {osmConnection} layerIds={officialLayers} on:layerSelected={editLayer} />
</div>
{:else if state === "edit_theme"}
<div class="m-4 flex flex-col">
@ -374,11 +374,7 @@
<h3>Themes by other contributors</h3>
<ChooseLayerToEdit {osmConnection} layerIds={otherThemes} on:layerSelected={editTheme} />
<h3>Official themes by MapComplete</h3>
<ChooseLayerToEdit
{osmConnection}
layerIds={officialThemes}
on:layerSelected={editTheme}
/>
<ChooseLayerToEdit {osmConnection} layerIds={officialThemes} on:layerSelected={editTheme} />
</div>
{:else if state === "loading"}
<div class="h-8 w-8">

View file

@ -1,11 +1,11 @@
{
"contributors": [
{
"commits": 9176,
"commits": 9299,
"contributor": "Pieter Vander Vennet"
},
{
"commits": 515,
"commits": 520,
"contributor": "Robin van der Linde"
},
{
@ -28,6 +28,10 @@
"commits": 33,
"contributor": "Christian Neumann"
},
{
"commits": 32,
"contributor": "Midgard"
},
{
"commits": 31,
"contributor": "Andrews Leruth"
@ -44,10 +48,6 @@
"commits": 29,
"contributor": "riQQ"
},
{
"commits": 26,
"contributor": "Midgard"
},
{
"commits": 26,
"contributor": "Joost"
@ -60,6 +60,10 @@
"commits": 24,
"contributor": "Ward"
},
{
"commits": 21,
"contributor": "Osmwithspace"
},
{
"commits": 21,
"contributor": "wjtje"
@ -97,7 +101,7 @@
"contributor": "ToastHawaii"
},
{
"commits": 13,
"commits": 14,
"contributor": "danieldegroot2"
},
{
@ -112,10 +116,6 @@
"commits": 12,
"contributor": "Bavo Vanderghote"
},
{
"commits": 11,
"contributor": "Osmwithspace"
},
{
"commits": 11,
"contributor": "Flo Edelmann"
@ -152,6 +152,10 @@
"commits": 7,
"contributor": "OliNau"
},
{
"commits": 6,
"contributor": "Languages add-on"
},
{
"commits": 6,
"contributor": "David Haberthür"
@ -160,10 +164,6 @@
"commits": 5,
"contributor": "tiptoptom"
},
{
"commits": 4,
"contributor": "Languages add-on"
},
{
"commits": 4,
"contributor": "Daniele Santini"
@ -280,6 +280,10 @@
"commits": 2,
"contributor": "Stanislas Gueniffey"
},
{
"commits": 1,
"contributor": "Weblate Admin"
},
{
"commits": 1,
"contributor": "Malte"

View file

@ -236,9 +236,9 @@
"fr"
],
"GQ": [
"pt",
"fr",
"es"
"es",
"pt"
],
"GR": [
"el"

View file

@ -12468,7 +12468,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -13805,7 +13805,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -15190,7 +15190,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -16579,7 +16579,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -17970,7 +17970,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -19359,7 +19359,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},

View file

@ -15115,7 +15115,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -16489,7 +16489,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -17912,7 +17912,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -19337,7 +19337,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -20763,7 +20763,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -22188,7 +22188,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -36926,7 +36926,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -38351,7 +38351,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -39827,7 +39827,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -41303,7 +41303,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -42780,7 +42780,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},
@ -44256,7 +44256,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},

View file

@ -675,7 +675,7 @@
},
{
"if": "value=regex",
"then": "<b>regex</b> Validates a regex"
"then": "<b>regex</b> Only used when your input should be a valid regex. This validator is only used as helper for Studio and should not be used in a mapcomplete-theme."
}
]
},

View file

@ -17,7 +17,7 @@
"contributor": "Anonymous"
},
{
"commits": 122,
"commits": 128,
"contributor": "mcliquid"
},
{
@ -25,7 +25,7 @@
"contributor": "Allan Nordhøy"
},
{
"commits": 89,
"commits": 92,
"contributor": "mike140"
},
{
@ -45,7 +45,7 @@
"contributor": "Jiří Podhorecký"
},
{
"commits": 53,
"commits": 57,
"contributor": "Supaplex"
},
{
@ -108,6 +108,10 @@
"commits": 16,
"contributor": "macpac"
},
{
"commits": 15,
"contributor": "Pau Nofuentes"
},
{
"commits": 15,
"contributor": "Ettore Atalan"
@ -148,6 +152,10 @@
"commits": 12,
"contributor": "Piotr Strebski"
},
{
"commits": 11,
"contributor": "Weblate Admin"
},
{
"commits": 11,
"contributor": "Manuel Tassi"
@ -188,10 +196,6 @@
"commits": 10,
"contributor": "Irina"
},
{
"commits": 9,
"contributor": "Weblate Admin"
},
{
"commits": 9,
"contributor": "Krzysztof Chorzempa"
@ -368,6 +372,10 @@
"commits": 4,
"contributor": "Jan Zabel"
},
{
"commits": 3,
"contributor": "ceirios"
},
{
"commits": 3,
"contributor": "Gábor"

View file

@ -5,7 +5,7 @@ import { LocalStorageSource } from "./Logic/Web/LocalStorageSource"
console.log("Authorizing...")
if (QueryParameters.wasInitialized("error")) {
// error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.
// error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.
alert("Access was denied")
const previousLocation = LocalStorageSource.get("location_before_login")
window.location.href = previousLocation.data ?? "./"