Remove unmaintained preferences page, re-add earlier visited installed themes (only remove themes)

This commit is contained in:
Pieter Vander Vennet 2021-12-21 20:57:25 +01:00
parent 4b6769d601
commit 7fe79600fb
6 changed files with 78 additions and 282 deletions

View file

@ -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);
}
}
}

View file

@ -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(

View file

@ -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)

View file

@ -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)

View file

@ -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>

View file

@ -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))