forked from MapComplete/MapComplete
Remove unmaintained preferences page, re-add earlier visited installed themes (only remove themes)
This commit is contained in:
parent
4b6769d601
commit
7fe79600fb
6 changed files with 78 additions and 282 deletions
|
@ -1,65 +0,0 @@
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import {OsmConnection} from "../Osm/OsmConnection";
|
||||
import {Utils} from "../../Utils";
|
||||
import LZString from "lz-string";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
/**
|
||||
* Gives an overview of themes that are installed in the user preferences
|
||||
*/
|
||||
export default class InstalledThemes {
|
||||
public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>;
|
||||
|
||||
|
||||
constructor(osmConnection: OsmConnection) {
|
||||
this.installedThemes = osmConnection.preferencesHandler.preferences.map<{ layout: LayoutConfig, definition: string }[]>(allPreferences => {
|
||||
const installedThemes: { layout: LayoutConfig, definition: string }[] = [];
|
||||
if (allPreferences === undefined) {
|
||||
console.log("All prefs is undefined");
|
||||
return installedThemes;
|
||||
}
|
||||
const invalidThemes = []
|
||||
for (const allPreferencesKey in allPreferences) {
|
||||
const themename = allPreferencesKey.match(/^mapcomplete-installed-theme-(.*)-combined-length$/);
|
||||
if (themename && themename[1] !== "") {
|
||||
const customLayout = osmConnection.GetLongPreference("installed-theme-" + themename[1]);
|
||||
if (customLayout.data === undefined) {
|
||||
console.log("No data defined for ", themename[1]);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
let layoutJson;
|
||||
try {
|
||||
layoutJson = JSON.parse(atob(customLayout.data))
|
||||
} catch (e) {
|
||||
layoutJson = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(customLayout.data)))
|
||||
}
|
||||
const layout = new LayoutConfig(layoutJson, false);
|
||||
installedThemes.push({
|
||||
layout: layout,
|
||||
definition: customLayout.data
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn("Could not parse custom layout from preferences - deleting: ", allPreferencesKey, e, customLayout.data);
|
||||
invalidThemes.push(themename[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstalledThemes.DeleteInvalid(osmConnection, invalidThemes);
|
||||
|
||||
return installedThemes;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private static DeleteInvalid(osmConnection: OsmConnection, invalidThemes: any[]) {
|
||||
for (const invalid of invalidThemes) {
|
||||
console.error("Attempting to remove ", invalid)
|
||||
osmConnection.GetLongPreference(
|
||||
"installed-theme-" + invalid
|
||||
).setData(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ import {FixLegacyTheme, PrepareTheme} from "../Models/ThemeConfig/LegacyJsonConv
|
|||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import SharedTagRenderings from "../Customizations/SharedTagRenderings";
|
||||
import * as known_layers from "../assets/generated/known_layers.json"
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
|
||||
export default class DetermineLayout {
|
||||
|
||||
|
@ -62,6 +63,22 @@ export default class DetermineLayout {
|
|||
return layoutToUse
|
||||
}
|
||||
|
||||
private static prepCustomTheme(json: any): LayoutConfigJson{
|
||||
const knownLayersDict = new Map<string, LayerConfigJson>()
|
||||
for (const key in known_layers["default"]) {
|
||||
const layer = known_layers["default"][key]
|
||||
knownLayersDict.set(layer.id, layer)
|
||||
}
|
||||
const converState = {
|
||||
tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
|
||||
sharedLayers: knownLayersDict
|
||||
}
|
||||
json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme")
|
||||
json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme")
|
||||
console.log("The layoutconfig is ", json)
|
||||
return json
|
||||
}
|
||||
|
||||
public static LoadLayoutFromHash(
|
||||
userLayoutParam: UIEventSource<string>
|
||||
): LayoutConfig | null {
|
||||
|
@ -102,25 +119,9 @@ export default class DetermineLayout {
|
|||
}
|
||||
}
|
||||
|
||||
const knownLayersDict = new Map<string, LayerConfigJson>()
|
||||
for (const key in known_layers["default"]) {
|
||||
const layer = known_layers["default"][key]
|
||||
console.log("Found shared layer "+layer.id)
|
||||
knownLayersDict.set(layer.id, layer)
|
||||
}
|
||||
|
||||
const converState = {
|
||||
tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
|
||||
sharedLayers: knownLayersDict
|
||||
}
|
||||
|
||||
json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme")
|
||||
|
||||
json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme")
|
||||
|
||||
const layoutToUse = new LayoutConfig(json, false);
|
||||
const layoutToUse = DetermineLayout.prepCustomTheme(json)
|
||||
userLayoutParam.setData(layoutToUse.id);
|
||||
return layoutToUse;
|
||||
return new LayoutConfig(layoutToUse, false);
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
if (hash === undefined || hash.length < 10) {
|
||||
|
@ -160,9 +161,14 @@ export default class DetermineLayout {
|
|||
tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
|
||||
sharedLayers: new Map<string, LayerConfigJson>() // FIXME: actually add the layers
|
||||
}, parsed, "While loading a dynamic theme")
|
||||
try {
|
||||
|
||||
|
||||
parsed.id = link;
|
||||
return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed));
|
||||
|
||||
|
||||
try {
|
||||
const layoutToUse = DetermineLayout.prepCustomTheme(parsed)
|
||||
return new LayoutConfig(layoutToUse,false).patchImages(link, JSON.stringify(layoutToUse));
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
DetermineLayout.ShowErrorOnCustomTheme(
|
||||
|
|
|
@ -3,12 +3,12 @@ import {OsmConnection} from "../Osm/OsmConnection";
|
|||
import {MangroveIdentity} from "../Web/MangroveReviews";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {QueryParameters} from "../Web/QueryParameters";
|
||||
import InstalledThemes from "../Actors/InstalledThemes";
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
|
||||
import {Utils} from "../../Utils";
|
||||
import Locale from "../../UI/i18n/Locale";
|
||||
import ElementsState from "./ElementsState";
|
||||
import SelectedElementTagsUpdater from "../Actors/SelectedElementTagsUpdater";
|
||||
import {log} from "util";
|
||||
|
||||
/**
|
||||
* The part of the state which keeps track of user-related stuff, e.g. the OSM-connection,
|
||||
|
@ -33,7 +33,10 @@ export default class UserRelatedState extends ElementsState {
|
|||
/**
|
||||
* WHich other themes the user previously visited
|
||||
*/
|
||||
public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>;
|
||||
public installedThemes: UIEventSource<{ id: string, // The id doubles as the URL
|
||||
icon: string,
|
||||
title: any,
|
||||
shortDescription: any}[]>;
|
||||
|
||||
|
||||
constructor(layoutToUse: LayoutConfig, options?:{attemptLogin : true | boolean}) {
|
||||
|
@ -69,9 +72,47 @@ export default class UserRelatedState extends ElementsState {
|
|||
})
|
||||
}
|
||||
|
||||
this.installedThemes = new InstalledThemes(
|
||||
this.osmConnection
|
||||
).installedThemes;
|
||||
this.installedThemes = this.osmConnection.GetLongPreference("installed-themes").map(
|
||||
str => {
|
||||
if(str === undefined || str === ""){
|
||||
return []
|
||||
}
|
||||
try{
|
||||
return JSON.parse(str)
|
||||
}catch(e){
|
||||
console.warn("Could not parse preference with installed themes due to ", e,"\nThe offending string is",str)
|
||||
return []
|
||||
}
|
||||
}, [],(installed => JSON.stringify(installed))
|
||||
)
|
||||
|
||||
|
||||
const self = this;
|
||||
this.osmConnection.isLoggedIn.addCallbackAndRunD(loggedIn => {
|
||||
if(!loggedIn){
|
||||
return
|
||||
}
|
||||
|
||||
if(this.layoutToUse.id.startsWith("http")){
|
||||
if(!this.installedThemes.data.some(installed => installed.id === this.layoutToUse.id)){
|
||||
|
||||
this.installedThemes.data.push({
|
||||
id: this.layoutToUse.id,
|
||||
icon: this.layoutToUse.icon,
|
||||
title: this.layoutToUse.title.translations,
|
||||
shortDescription: this.layoutToUse.shortDescription.translations
|
||||
})
|
||||
}
|
||||
this.installedThemes.ping()
|
||||
console.log("Registered "+this.layoutToUse.id+" as installed themes")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
|
||||
// Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme
|
||||
this.favouriteLayers = LocalStorageSource.Get("favouriteLayers")
|
||||
|
@ -81,8 +122,7 @@ export default class UserRelatedState extends ElementsState {
|
|||
[],
|
||||
(layers) => Utils.Dedup(layers)?.join(";")
|
||||
);
|
||||
|
||||
|
||||
|
||||
this.InitializeLanguage();
|
||||
new SelectedElementTagsUpdater(this)
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export default class MoreScreen extends Combine {
|
|||
icon: string,
|
||||
title: any,
|
||||
shortDescription: any
|
||||
}, customThemeDefinition: string = undefined
|
||||
}, isCustom: boolean = false
|
||||
):
|
||||
BaseUIElement {
|
||||
if (layout === undefined) {
|
||||
|
@ -79,14 +79,12 @@ export default class MoreScreen extends Combine {
|
|||
}
|
||||
|
||||
let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
|
||||
let linkSuffix = ""
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
|
||||
linkPrefix = `${path}/theme.html?layout=${layout.id}&`
|
||||
}
|
||||
|
||||
if (customThemeDefinition) {
|
||||
if (isCustom) {
|
||||
linkPrefix = `${path}/theme.html?userlayout=${layout.id}&`
|
||||
linkSuffix = `#${customThemeDefinition}`
|
||||
}
|
||||
|
||||
const linkText = currentLocation?.map(currentLocation => {
|
||||
|
@ -97,8 +95,8 @@ export default class MoreScreen extends Combine {
|
|||
].filter(part => part[1] !== undefined)
|
||||
.map(part => part[0] + "=" + part[1])
|
||||
.join("&")
|
||||
return `${linkPrefix}${params}${linkSuffix}`;
|
||||
}) ?? new UIEventSource<string>(`${linkPrefix}${linkSuffix}`)
|
||||
return `${linkPrefix}${params}`;
|
||||
}) ?? new UIEventSource<string>(`${linkPrefix}`)
|
||||
|
||||
|
||||
return new SubtleButton(layout.icon,
|
||||
|
@ -117,7 +115,7 @@ export default class MoreScreen extends Combine {
|
|||
if (customThemes.length <= 0) {
|
||||
return undefined;
|
||||
}
|
||||
const customThemeButtons = customThemes.map(theme => MoreScreen.createLinkButton(state, theme.layout, theme.definition)?.SetClass(buttonClass))
|
||||
const customThemeButtons = customThemes.map(theme => MoreScreen.createLinkButton(state, theme, true)?.SetClass(buttonClass))
|
||||
return new Combine([
|
||||
Translations.t.general.customThemeIntro.Clone(),
|
||||
new Combine(customThemeButtons).SetClass(themeListClasses)
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="index.css" rel="stylesheet"/>
|
||||
<title>Preferences editor</title>
|
||||
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Preferences editor - developers only</h1>
|
||||
Only use if you know what you're doing. To prevent newbies to make mistakes here, editing a mapcomplete-preference is
|
||||
only available if over 500 changes<br/>
|
||||
Editing any preference -including non-mapcomplete ones- is available when you have more then 2500 changesets. Until that
|
||||
point, only editing mapcomplete-preferences is possible.
|
||||
<div id="maindiv">'maindiv' not attached</div>
|
||||
<script src="./preferences.ts"></script>
|
||||
</body>
|
||||
</html>
|
154
preferences.ts
154
preferences.ts
|
@ -1,154 +0,0 @@
|
|||
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
||||
import Combine from "./UI/Base/Combine";
|
||||
import {Button} from "./UI/Base/Button";
|
||||
import {TextField} from "./UI/Input/TextField";
|
||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
||||
import {Utils} from "./Utils";
|
||||
import {SubtleButton} from "./UI/Base/SubtleButton";
|
||||
import LZString from "lz-string";
|
||||
import BaseUIElement from "./UI/BaseUIElement";
|
||||
import Table from "./UI/Base/Table";
|
||||
import {LayoutConfigJson} from "./Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import {Changes} from "./Logic/Osm/Changes";
|
||||
import {ElementStorage} from "./Logic/ElementStorage";
|
||||
|
||||
|
||||
const connection = new OsmConnection({
|
||||
osmConfiguration: 'osm',
|
||||
changes: new Changes(),
|
||||
layoutName: '',
|
||||
allElements: new ElementStorage()
|
||||
});
|
||||
|
||||
|
||||
let rendered = false;
|
||||
|
||||
function salvageThemes(preferences: any) {
|
||||
const knownThemeNames = new Set<string>();
|
||||
const correctThemeNames = []
|
||||
for (const key in preferences) {
|
||||
try {
|
||||
if (!(typeof key === "string")) {
|
||||
continue;
|
||||
}
|
||||
const prefix = "mapcomplete-installed-theme-";
|
||||
// mapcomplete-installed-theme-arbres_llefia-combined-11
|
||||
//mapcomplete-installed-theme-1roadAlllanes-combined-length
|
||||
if (!key.startsWith(prefix)) {
|
||||
continue;
|
||||
}
|
||||
const theme = key.substring(prefix.length, key.indexOf("-combined-"))
|
||||
|
||||
if (key.endsWith("-length")) {
|
||||
correctThemeNames.push(theme)
|
||||
} else {
|
||||
knownThemeNames.add(theme);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
for (const correctThemeName of correctThemeNames) {
|
||||
knownThemeNames.delete(correctThemeName);
|
||||
}
|
||||
|
||||
const missingValues = Array.from(knownThemeNames).map(failedTheme => {
|
||||
|
||||
let i = 0;
|
||||
let foundValue = undefined
|
||||
let combined = ""
|
||||
do {
|
||||
const prefix = "mapcomplete-installed-theme-";
|
||||
const key = prefix + failedTheme + "-combined-" + i;
|
||||
foundValue = preferences[key]
|
||||
console.log(key, "-->", foundValue)
|
||||
i++;
|
||||
combined += foundValue ?? ""
|
||||
} while (foundValue !== undefined);
|
||||
|
||||
if (combined === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("COmbined value is", combined)
|
||||
let jsonObject;
|
||||
try {
|
||||
jsonObject = JSON.parse(atob(combined));
|
||||
} catch (e) {
|
||||
try {
|
||||
|
||||
// We try to decode with lz-string
|
||||
jsonObject = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(combined))) as LayoutConfigJson;
|
||||
} catch (e0) {
|
||||
console.log("Could not salvage theme. Initial parsing failed due to:", e, "\nWith LZ failed due ", e0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
themeName: failedTheme,
|
||||
contents: JSON.stringify(jsonObject, null, " ")
|
||||
}
|
||||
})
|
||||
return Utils.NoNull(missingValues);
|
||||
}
|
||||
|
||||
function clearAll(preferences) {
|
||||
for (const key in preferences) {
|
||||
const pref = connection.GetPreference(key, "");
|
||||
if (key.startsWith("mapcomplete")) {
|
||||
pref.setData("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SalvageButton(theme: { themeName: string, contents: string }) {
|
||||
return new SubtleButton("./assets/svg/bug.svg", "Download broken theme " + theme.themeName).onClick(
|
||||
() => {
|
||||
Utils.offerContentsAsDownloadableFile(theme.contents, theme.themeName + ".json")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function createTable(preferences: any) {
|
||||
if (rendered) {
|
||||
return;
|
||||
}
|
||||
rendered = true;
|
||||
const prefs: (BaseUIElement | string)[][] = [];
|
||||
for (const key in preferences) {
|
||||
if (!preferences.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
const pref = connection.GetPreference(key, "");
|
||||
|
||||
let value: BaseUIElement = new FixedUiElement(pref.data);
|
||||
if (connection.userDetails.data.csCount > 500 &&
|
||||
(key.startsWith("mapcomplete") || connection.userDetails.data.csCount > 2500)) {
|
||||
value = new TextField({
|
||||
value: pref
|
||||
});
|
||||
}
|
||||
|
||||
const row = [
|
||||
key,
|
||||
new Button("delete", () => pref.setData(null)),
|
||||
value
|
||||
];
|
||||
prefs.push(row);
|
||||
}
|
||||
|
||||
new Combine(
|
||||
[
|
||||
...salvageThemes(preferences).map(theme => SalvageButton(theme)),
|
||||
new Table(
|
||||
["Key", "", "Value"],
|
||||
prefs
|
||||
),
|
||||
new SubtleButton("./assets/svg/delete_icon.svg", "Delete all mapcomplete preferences (mangrove identies are preserved)").onClick(() => clearAll(preferences))]
|
||||
).AttachTo("maindiv");
|
||||
}
|
||||
|
||||
connection.preferencesHandler.preferences.addCallback((prefs) => createTable(prefs))
|
||||
|
Loading…
Add table
Reference in a new issue