From abf3bd1fa03be918b1cc77b657c9a3c81895b7fe Mon Sep 17 00:00:00 2001 From: Birk Skyum <74932975+birkskyum@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:57:38 +0100 Subject: [PATCH] Fix insertion of access tokens, when swapping renderer (#1021) Going from e.g. MapTiler to OpenLayers and back will lose the maptlier key. This code finds the urls in the style that has "{key}" and insert the correct API keys Fixes the error reported here, cc @nyurik - Fixes https://github.com/maplibre/maputnik/issues/874#issuecomment-2605896666 Related to: - https://github.com/maplibre/maputnik/issues/869 ## Launch Checklist - [ ] Briefly describe the changes in this PR. - [ ] Link to related issues. - [ ] Include before/after visuals or gifs if this PR includes visual changes. - [ ] Write tests for all new functionality. - [ ] Add an entry to `CHANGELOG.md` under the `## main` section. --- .github/workflows/ci.yml | 2 +- cypress/e2e/modals.cy.ts | 37 ++++++++++++++++++++++++++++++++++++- src/components/App.tsx | 21 +++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c31789cf..02583f4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,7 +93,7 @@ jobs: strategy: fail-fast: false matrix: - browser: [chrome, firefox] + browser: [chrome] runs-on: ubuntu-22.04 steps: diff --git a/cypress/e2e/modals.cy.ts b/cypress/e2e/modals.cy.ts index 92d6732a..6ebdca41 100644 --- a/cypress/e2e/modals.cy.ts +++ b/cypress/e2e/modals.cy.ts @@ -1,7 +1,8 @@ import { MaputnikDriver } from "./maputnik-driver"; +import tokens from "../../src/config/tokens.json" with {type: "json"}; describe("modals", () => { - const { beforeAndAfter, when, get, then } = new MaputnikDriver(); + const { beforeAndAfter, when, get, given, then } = new MaputnikDriver(); beforeAndAfter(); beforeEach(() => { @@ -235,6 +236,40 @@ describe("modals", () => { metadata: { "maputnik:renderer": "ol" }, }); }); + + + + it("inlcude API key when change renderer", () => { + + when.click("modal:settings.close-modal") + when.click("nav:open"); + + get.elementByAttribute('aria-label', "MapTiler Basic").should('exist').click(); + + when.click("nav:settings"); + + when.select("modal:settings.maputnik:renderer", "mlgljs"); + then(get.inputValue("modal:settings.maputnik:renderer")).shouldEqual( + "mlgljs" + ); + + when.select("modal:settings.maputnik:renderer", "ol"); + then(get.inputValue("modal:settings.maputnik:renderer")).shouldEqual( + "ol" + ); + + given.intercept("https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=*", "tileRequest", "GET"); + + when.select("modal:settings.maputnik:renderer", "mlgljs"); + then(get.inputValue("modal:settings.maputnik:renderer")).shouldEqual( + "mlgljs" + ); + + when.waitForResponse("tileRequest").its("request").its("url").should("include", `https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=${tokens.openmaptiles}`); + when.waitForResponse("tileRequest").its("request").its("url").should("include", `https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=${tokens.openmaptiles}`); + when.waitForResponse("tileRequest").its("request").its("url").should("include", `https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=${tokens.openmaptiles}`); + }); + }); describe("sources", () => { diff --git a/src/components/App.tsx b/src/components/App.tsx index 31e2cf57..fcee5f93 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -363,6 +363,7 @@ export default class App extends React.Component { [property]: value } } + this.onStyleChanged(changedStyle) } @@ -374,6 +375,24 @@ export default class App extends React.Component { ...opts, }; + // For the style object, find the urls that has "{key}" and insert the correct API keys + // Without this, going from e.g. MapTiler to OpenLayers and back will lose the maptlier key. + + if (newStyle.glyphs && typeof newStyle.glyphs === 'string') { + newStyle.glyphs = setFetchAccessToken(newStyle.glyphs, newStyle); + } + + if (newStyle.sprite && typeof newStyle.sprite === 'string') { + newStyle.sprite = setFetchAccessToken(newStyle.sprite, newStyle); + } + + for (const [_sourceId, source] of Object.entries(newStyle.sources)) { + if (source && 'url' in source && typeof source.url === 'string') { + source.url = setFetchAccessToken(source.url, newStyle); + } + } + + if (opts.initialLoad) { this.getInitialStateFromUrl(newStyle); } @@ -737,6 +756,7 @@ export default class App extends React.Component { onLayerSelect={this.onLayerSelect} /> } else { + mapElement = { getInitialStateFromUrl = (mapStyle: StyleSpecification) => { const url = new URL(location.href); const modalParam = url.searchParams.get("modal"); + if (modalParam && modalParam !== "") { const modals = modalParam.split(","); const modalObj: {[key: string]: boolean} = {};