diff --git a/html/field.js b/html/field.js index f81a7af..4ec17e8 100644 --- a/html/field.js +++ b/html/field.js @@ -32,7 +32,15 @@ function boot() { PID = params.get('project') || (ProjectData.getActiveId && ProjectData.getActiveId()) || ''; if (!PID) { showNoProject(); return; } if (ProjectData.getActiveId && ProjectData.getActiveId() !== PID) { try { ProjectData.setActive({ id: PID }); } catch (e) {} } - if (ProjectData.get) { ProjectData.get(PID).then(function (p) { PROJECT = p; renderCtx(); }).catch(function () {}); } + // Publish the resolved record rather than keeping it to ourselves: line 34 could + // only write the id, and the app bar reads the shared record, not PROJECT. + if (ProjectData.get) { + ProjectData.get(PID).then(function (p) { + PROJECT = p; + if (p && p.name) { try { ProjectData.setActive(p); } catch (e) {} } + renderCtx(); + }).catch(function () {}); + } loadWPs(); } function renderCtx() { diff --git a/html/project-data.js b/html/project-data.js index 22db885..dd56abe 100644 --- a/html/project-data.js +++ b/html/project-data.js @@ -112,6 +112,25 @@ } } catch (e) {} notifyActive(p || null); + + // A caller that knew only the id leaves the store holding a stub, and every + // reader then renders "(unnamed)" — field.js sets {id} on boot and resolves the + // record into a variable of its own. Fill the stub in from the cached list, or + // from the API when the cache has not loaded yet. The re-entry carries a name, + // so it cannot loop; the id re-check stops a slow response from overwriting a + // project the user has since switched to. + if (p && p.id && !p.name) { + var self = this; + var cached = readLocal().filter(function (x) { return x.id === p.id; })[0]; + if (cached && cached.name) { self.setActive(cached); return; } + try { + if (self.get) { + self.get(p.id).then(function (full) { + if (full && full.name && self.getActiveId() === full.id) self.setActive(full); + }).catch(function () {}); + } + } catch (e) {} + } }, // Subscribe to active-project changes. Returns an unsubscribe function. diff --git a/html/wp-chrome.js b/html/wp-chrome.js index ae546b4..9783485 100644 --- a/html/wp-chrome.js +++ b/html/wp-chrome.js @@ -163,7 +163,24 @@ .then(function (r) { return r.ok ? r.json() : []; }); } Promise.resolve(p) - .then(function (list) { projects = Array.isArray(list) ? list : []; switcher.wpcRefresh(); }) + .then(function (list) { + projects = Array.isArray(list) ? list : []; + // A deep link names the project, and the bar is the one component every + // page carrying chrome has. The launcher, SOP wizard, creator and field + // view each resolve ?project= themselves; admin.html and users.html have + // no project logic at all, so without this their bar shows whatever was + // last stored — or "Select a project" on a cold browser — while the URL + // says otherwise. Resolving it here covers every page once. + try { + var wanted = new URLSearchParams(location.search).get('project'); + if (wanted && window.ProjectData && ProjectData.setActive) { + var hit = projects.filter(function (x) { return x.id === wanted; })[0]; + var cur = activeProject(); + if (hit && (!cur || cur.id !== hit.id || !cur.name)) ProjectData.setActive(hit); + } + } catch (e) {} + switcher.wpcRefresh(); + }) .catch(function () {}); }