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 () {});
}