vibespot 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,34 +23,45 @@ async function startUpload() {
23
23
  if (uploadBtn) { uploadBtn.textContent = "Deploy"; uploadBtn.disabled = false; }
24
24
  }
25
25
 
26
- // Fetch portal info and check HubSpot CLI readiness
26
+ // Fetch portal info and check readiness
27
27
  try {
28
28
  const res = await fetch("/api/settings/status");
29
29
  const data = await res.json();
30
+ const uploadMode = data.config?.hubspotUploadMode || "api";
30
31
  let hs = data.environment?.tools?.hubspot;
31
32
 
32
- // HubSpot CLI not installed — guide the user through install
33
- if (!hs || !hs.found) {
34
- const installed = await showHubSpotSetupDialog("install");
35
- if (!installed) { resetUploadBtn(); return; }
36
- // Re-check after install
37
- const recheck = await fetch("/api/settings/status").then((r) => r.json());
38
- hs = recheck.environment?.tools?.hubspot;
39
- }
40
-
41
- // HubSpot CLI installed but not authenticated — guide through auth
42
- if (hs && hs.found && !hs.authenticated) {
43
- const authed = await showHubSpotSetupDialog("auth");
44
- if (!authed) { resetUploadBtn(); return; }
45
- // Re-check after auth
46
- const recheck = await fetch("/api/settings/status").then((r) => r.json());
47
- hs = recheck.environment?.tools?.hubspot;
48
- }
49
-
50
- // Confirm portal before deploying
51
- if (hs && hs.authenticated && hs.portalName) {
52
- const confirmed = await confirmUpload(hs.portalName, hs.portalId);
53
- if (!confirmed) { resetUploadBtn(); return; }
33
+ if (uploadMode === "api") {
34
+ // API mode just need a PAK configured
35
+ const accounts = data.config?.hubspotAccounts || [];
36
+ if (accounts.length === 0) {
37
+ const authed = await showHubSpotSetupDialog("auth");
38
+ if (!authed) { resetUploadBtn(); return; }
39
+ const recheck = await fetch("/api/settings/status").then((r) => r.json());
40
+ hs = recheck.environment?.tools?.hubspot;
41
+ }
42
+ // Confirm portal
43
+ if (hs && hs.authenticated && hs.portalName) {
44
+ const confirmed = await confirmUpload(hs.portalName, hs.portalId);
45
+ if (!confirmed) { resetUploadBtn(); return; }
46
+ }
47
+ } else {
48
+ // CLI mode — need CLI installed and authed
49
+ if (!hs || !hs.found) {
50
+ const installed = await showHubSpotSetupDialog("install");
51
+ if (!installed) { resetUploadBtn(); return; }
52
+ const recheck = await fetch("/api/settings/status").then((r) => r.json());
53
+ hs = recheck.environment?.tools?.hubspot;
54
+ }
55
+ if (hs && hs.found && !hs.authenticated) {
56
+ const authed = await showHubSpotSetupDialog("auth");
57
+ if (!authed) { resetUploadBtn(); return; }
58
+ const recheck = await fetch("/api/settings/status").then((r) => r.json());
59
+ hs = recheck.environment?.tools?.hubspot;
60
+ }
61
+ if (hs && hs.authenticated && hs.portalName) {
62
+ const confirmed = await confirmUpload(hs.portalName, hs.portalId);
63
+ if (!confirmed) { resetUploadBtn(); return; }
64
+ }
54
65
  }
55
66
  } catch {
56
67
  // If we can't detect, proceed and let the upload fail with a meaningful error
@@ -125,8 +136,8 @@ function showHubSpotSetupDialog(mode) {
125
136
  <div class="confirm-dialog__title">Connect your HubSpot account</div>
126
137
  <p class="confirm-dialog__detail">Create a Personal Access Key to connect vibeSpot to your HubSpot portal.</p>
127
138
  <ol class="hs-setup__steps">
128
- <li>Open <a href="https://app.hubspot.com/portal-recommend/l?slug=personal-access-key" target="_blank" rel="noopener">HubSpot Settings</a></li>
129
- <li>Click "Create personal access key" or copy an existing one</li>
139
+ <li>Open <a href="https://app.hubspot.com/l/personal-access-key" target="_blank" rel="noopener">HubSpot Personal Access Key</a></li>
140
+ <li>Create a key with the <strong>Content</strong> scope enabled</li>
130
141
  <li>Paste the key below</li>
131
142
  </ol>
132
143
  <input type="password" class="confirm-dialog__input" id="hs-pak-input" placeholder="pat-na1-..." />
@@ -206,7 +217,9 @@ function confirmUpload(portalName, portalId) {
206
217
  <div class="confirm-dialog__title">Deploy to HubSpot?</div>
207
218
  <p class="confirm-dialog__detail">
208
219
  Uploading to <strong>${esc(portalName)}</strong>${portalId ? ` (${esc(portalId)})` : ""}
220
+ <button class="btn-link" id="confirm-upload-change">Change</button>
209
221
  </p>
222
+ <div id="confirm-upload-switch" class="hidden" style="margin:12px 0"></div>
210
223
  <div class="confirm-dialog__actions">
211
224
  <button class="btn btn--secondary" id="confirm-upload-cancel">Cancel</button>
212
225
  <button class="btn btn--primary" id="confirm-upload-go">Deploy</button>
@@ -215,16 +228,57 @@ function confirmUpload(portalName, portalId) {
215
228
  `;
216
229
  document.body.appendChild(overlay);
217
230
 
218
- document.getElementById("confirm-upload-cancel").addEventListener("click", () => {
219
- overlay.remove();
220
- resolve(false);
221
- });
222
- overlay.addEventListener("click", (e) => {
223
- if (e.target === overlay) { overlay.remove(); resolve(false); }
224
- });
225
- document.getElementById("confirm-upload-go").addEventListener("click", () => {
226
- overlay.remove();
227
- resolve(true);
231
+ const close = (val) => { overlay.remove(); resolve(val); };
232
+
233
+ document.getElementById("confirm-upload-cancel").addEventListener("click", () => close(false));
234
+ overlay.addEventListener("click", (e) => { if (e.target === overlay) close(false); });
235
+ document.getElementById("confirm-upload-go").addEventListener("click", () => close(true));
236
+
237
+ document.getElementById("confirm-upload-change").addEventListener("click", async () => {
238
+ const switchArea = document.getElementById("confirm-upload-switch");
239
+ if (!switchArea.classList.contains("hidden")) { switchArea.classList.add("hidden"); return; }
240
+ switchArea.classList.remove("hidden");
241
+ switchArea.innerHTML = '<span class="upload-spinner"></span> Loading accounts...';
242
+
243
+ try {
244
+ const res = await fetch("/api/settings/status");
245
+ const data = await res.json();
246
+ const accounts = data.config?.hubspotAccounts || [];
247
+ const activeId = data.config?.activeHubSpotAccount;
248
+
249
+ let html = '<div style="display:flex;flex-direction:column;gap:6px">';
250
+ for (const acct of accounts) {
251
+ const isActive = acct.portalId === activeId;
252
+ html += `<button class="btn btn--${isActive ? "primary" : "secondary"} confirm-acct-btn" data-portal="${esc(acct.portalId)}" style="text-align:left;padding:6px 12px;font-size:13px">${esc(acct.portalName || acct.portalId)} (${esc(acct.portalId)})${isActive ? " ✓" : ""}</button>`;
253
+ }
254
+ html += `<button class="btn btn--secondary confirm-acct-btn" data-portal="__new" style="text-align:left;padding:6px 12px;font-size:13px">+ Add another account</button>`;
255
+ html += '</div>';
256
+ switchArea.innerHTML = html;
257
+
258
+ switchArea.querySelectorAll(".confirm-acct-btn").forEach((btn) => {
259
+ btn.addEventListener("click", async () => {
260
+ const pid = btn.dataset.portal;
261
+ if (pid === "__new") {
262
+ close(false);
263
+ const added = await showHubSpotSetupDialog("auth");
264
+ if (added) startUpload();
265
+ return;
266
+ }
267
+ if (pid === activeId) { switchArea.classList.add("hidden"); return; }
268
+ // Switch active account
269
+ await fetch("/api/settings/hs-switch", {
270
+ method: "POST",
271
+ headers: { "Content-Type": "application/json" },
272
+ body: JSON.stringify({ portalId: pid }),
273
+ });
274
+ // Restart the deploy flow with the new account
275
+ close(false);
276
+ startUpload();
277
+ });
278
+ });
279
+ } catch {
280
+ switchArea.innerHTML = '<span style="color:var(--error)">Failed to load accounts</span>';
281
+ }
228
282
  });
229
283
  });
230
284
  }
@@ -421,6 +475,16 @@ function handleUploadWsMessage(msg) {
421
475
  setUploadState("uploading");
422
476
  break;
423
477
 
478
+ case "upload_progress":
479
+ if (msg.completed !== undefined && msg.total) {
480
+ const pct = Math.round((msg.completed / msg.total) * 100);
481
+ const statusEl = document.getElementById("upload-status-text");
482
+ if (statusEl) {
483
+ statusEl.textContent = `Uploading to HubSpot... ${msg.completed}/${msg.total} files (${pct}%)`;
484
+ }
485
+ }
486
+ break;
487
+
424
488
  case "upload_output":
425
489
  appendUploadLog(msg.chunk);
426
490
  break;