@liiift-studio/deploy-vercel-from-sanity 0.1.4 → 0.1.7

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.
package/dist/index.mjs CHANGED
@@ -14,10 +14,11 @@ import {
14
14
  Heading as Heading2,
15
15
  Spinner as Spinner4,
16
16
  Button as Button4,
17
+ Badge as Badge4,
17
18
  Dialog as Dialog2,
18
19
  useToast
19
20
  } from "@sanity/ui";
20
- import { RocketIcon as RocketIcon2, TokenIcon as TokenIcon2, TrashIcon as TrashIcon2, WarningOutlineIcon } from "@sanity/icons";
21
+ import { RocketIcon as RocketIcon2, TokenIcon as TokenIcon2, TrashIcon as TrashIcon2, WarningOutlineIcon as WarningOutlineIcon2 } from "@sanity/icons";
21
22
 
22
23
  // src/components/DeployItem.tsx
23
24
  import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef } from "react";
@@ -33,18 +34,23 @@ import {
33
34
  Spinner as Spinner3,
34
35
  MenuButton,
35
36
  Menu,
36
- MenuItem
37
+ MenuItem,
38
+ Code
37
39
  } from "@sanity/ui";
38
40
  import {
39
41
  RocketIcon,
40
42
  ClockIcon,
41
43
  TrashIcon,
42
44
  EllipsisVerticalIcon,
43
- LaunchIcon as LaunchIcon2
45
+ LaunchIcon as LaunchIcon2,
46
+ CopyIcon,
47
+ CheckmarkIcon,
48
+ WarningOutlineIcon
44
49
  } from "@sanity/icons";
45
50
 
46
51
  // src/lib/api.ts
47
52
  var BASE = "https://api.vercel.com";
53
+ var VERCEL_HOOK_RE = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\//;
48
54
  async function vercelFetch(path, token, init) {
49
55
  const res = await fetch(`${BASE}${path}`, {
50
56
  ...init,
@@ -80,9 +86,22 @@ async function cancelDeployment(opts) {
80
86
  });
81
87
  }
82
88
  async function triggerDeploy(hookUrl) {
89
+ if (!VERCEL_HOOK_RE.test(hookUrl)) {
90
+ throw new Error("Invalid deploy hook URL \u2014 must be a Vercel hook (api.vercel.com/v1/integrations/deploy/\u2026)");
91
+ }
83
92
  const res = await fetch(hookUrl, { method: "POST" });
84
93
  if (!res.ok) throw new Error(`Deploy hook returned ${res.status}`);
85
94
  }
95
+ async function getDeploymentEvents(opts) {
96
+ const params = new URLSearchParams({ limit: "100", direction: "backward" });
97
+ if (opts.teamId) params.set("teamId", opts.teamId);
98
+ const raw = await vercelFetch(
99
+ `/v2/deployments/${opts.deploymentId}/events?${params}`,
100
+ opts.token
101
+ );
102
+ const events = Array.isArray(raw) ? raw : raw.events ?? [];
103
+ return events.filter((e) => e.text?.trim());
104
+ }
86
105
 
87
106
  // src/lib/helpers.ts
88
107
  function parseHookUrl(url) {
@@ -151,6 +170,17 @@ function stateLabel(state) {
151
170
  return { label: "Unknown", tone: "default" };
152
171
  }
153
172
  }
173
+ function projectHref(inspectorUrl) {
174
+ if (!inspectorUrl) return null;
175
+ try {
176
+ const { origin, pathname } = new URL(inspectorUrl);
177
+ const parts = pathname.split("/").filter(Boolean);
178
+ if (parts.length < 2) return null;
179
+ return `${origin}/${parts[0]}/${parts[1]}`;
180
+ } catch {
181
+ return null;
182
+ }
183
+ }
154
184
 
155
185
  // src/components/StatusBadge.tsx
156
186
  import { Badge, Spinner, Flex } from "@sanity/ui";
@@ -274,6 +304,11 @@ function DeployItem({ target, token, onDelete }) {
274
304
  const [deployError, setDeployError] = useState2(null);
275
305
  const [showHistory, setShowHistory] = useState2(false);
276
306
  const [elapsed, setElapsed] = useState2(0);
307
+ const [copied, setCopied] = useState2(false);
308
+ const [showErrorLogs, setShowErrorLogs] = useState2(false);
309
+ const [errorLines, setErrorLines] = useState2([]);
310
+ const [loadingLogs, setLoadingLogs] = useState2(false);
311
+ const [logError, setLogError] = useState2(null);
277
312
  const latest = deployments[0];
278
313
  const isActive = triggering || isActiveState(latest?.state);
279
314
  const fetchDeployments = useCallback2(async () => {
@@ -294,10 +329,13 @@ function DeployItem({ target, token, onDelete }) {
294
329
  return () => clearInterval(id);
295
330
  }, [isActive, fetchDeployments]);
296
331
  useEffect2(() => {
297
- if (triggering && latest && latest.state !== void 0) {
298
- setTriggering(false);
299
- }
332
+ if (triggering && latest && latest.state !== void 0) setTriggering(false);
300
333
  }, [triggering, latest]);
334
+ useEffect2(() => {
335
+ setShowErrorLogs(false);
336
+ setErrorLines([]);
337
+ setLogError(null);
338
+ }, [latest?.uid]);
301
339
  const timerRef = useRef(null);
302
340
  useEffect2(() => {
303
341
  if (isActive) {
@@ -337,141 +375,308 @@ function DeployItem({ target, token, onDelete }) {
337
375
  setCanceling(false);
338
376
  }
339
377
  }, [latest?.uid, token, target.teamId, fetchDeployments]);
378
+ const copyUrl = useCallback2(() => {
379
+ if (!latest?.url) return;
380
+ navigator.clipboard.writeText(`https://${latest.url}`).then(() => {
381
+ setCopied(true);
382
+ setTimeout(() => setCopied(false), 2e3);
383
+ }).catch((err) => {
384
+ console.error("deploy-vercel-from-sanity: clipboard error", err);
385
+ });
386
+ }, [latest?.url]);
387
+ const fetchErrorLogs = useCallback2(async () => {
388
+ if (!latest?.uid) return;
389
+ setLoadingLogs(true);
390
+ setLogError(null);
391
+ try {
392
+ const events = await getDeploymentEvents({
393
+ deploymentId: latest.uid,
394
+ token,
395
+ teamId: target.teamId
396
+ });
397
+ const lines = events.filter((e) => e.type === "stderr" || e.type === "stdout").map((e) => e.text ?? "").filter(Boolean).reverse().slice(-30);
398
+ setErrorLines(lines.length > 0 ? lines : ["No log output captured."]);
399
+ } catch (err) {
400
+ setLogError(err instanceof Error ? err.message : "Failed to load build logs");
401
+ } finally {
402
+ setLoadingLogs(false);
403
+ }
404
+ }, [latest?.uid, token, target.teamId]);
405
+ const toggleErrorLogs = useCallback2(() => {
406
+ if (!showErrorLogs && errorLines.length === 0 && !logError) {
407
+ fetchErrorLogs();
408
+ }
409
+ setShowErrorLogs((v) => !v);
410
+ }, [showErrorLogs, errorLines.length, logError, fetchErrorLogs]);
340
411
  const branch = latest?.meta?.githubCommitRef;
341
412
  const commitMsg = latest?.meta?.githubCommitMessage?.split("\n")[0];
342
413
  const sha = shortSha(latest?.meta?.githubCommitSha);
343
414
  const creator = latest?.creator?.username;
344
415
  const deployedAt = latest?.created ? timeAgo(latest.created) : null;
416
+ const vercelProjectUrl = projectHref(latest?.inspectorUrl);
417
+ const isError = latest?.state === "ERROR";
345
418
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
346
- /* @__PURE__ */ jsx3(Card2, { padding: 4, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs3(Stack2, { space: 4, children: [
347
- /* @__PURE__ */ jsxs3(Flex3, { align: "flex-start", justify: "space-between", gap: 3, children: [
348
- /* @__PURE__ */ jsxs3(Stack2, { space: 2, flex: 1, children: [
419
+ /* @__PURE__ */ jsx3(Card2, { padding: 5, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs3(Flex3, { gap: 4, align: "stretch", children: [
420
+ /* @__PURE__ */ jsxs3(Stack2, { space: 3, flex: 1, style: { minWidth: 0 }, children: [
421
+ /* @__PURE__ */ jsxs3(Flex3, { align: "center", justify: "space-between", gap: 2, children: [
349
422
  /* @__PURE__ */ jsx3(Text2, { size: 2, weight: "semibold", children: target.name }),
350
- /* @__PURE__ */ jsxs3(Flex3, { gap: 2, wrap: "wrap", children: [
351
- /* @__PURE__ */ jsx3(Text2, { size: 0, muted: true, children: projectId ? `${projectId.slice(0, 18)}\u2026` : "\u2014" }),
423
+ /* @__PURE__ */ jsx3(
424
+ MenuButton,
425
+ {
426
+ button: /* @__PURE__ */ jsx3(Button2, { mode: "ghost", icon: EllipsisVerticalIcon, padding: 2 }),
427
+ id: `menu-${target._id}`,
428
+ menu: /* @__PURE__ */ jsxs3(Menu, { children: [
429
+ /* @__PURE__ */ jsx3(
430
+ MenuItem,
431
+ {
432
+ text: "History",
433
+ icon: ClockIcon,
434
+ onClick: () => setShowHistory(true)
435
+ }
436
+ ),
437
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx3(
438
+ MenuItem,
439
+ {
440
+ text: "Build logs",
441
+ icon: LaunchIcon2,
442
+ as: "a",
443
+ href: safeHref(latest?.inspectorUrl),
444
+ target: "_blank",
445
+ rel: "noreferrer"
446
+ }
447
+ ),
448
+ vercelProjectUrl && /* @__PURE__ */ jsx3(
449
+ MenuItem,
450
+ {
451
+ text: "Open in Vercel",
452
+ icon: LaunchIcon2,
453
+ as: "a",
454
+ href: vercelProjectUrl,
455
+ target: "_blank",
456
+ rel: "noreferrer"
457
+ }
458
+ ),
459
+ !target.disableDeleteAction && /* @__PURE__ */ jsx3(
460
+ MenuItem,
461
+ {
462
+ text: "Delete",
463
+ icon: TrashIcon,
464
+ tone: "critical",
465
+ onClick: () => onDelete(target)
466
+ }
467
+ )
468
+ ] }),
469
+ popover: { placement: "bottom-end" }
470
+ }
471
+ )
472
+ ] }),
473
+ /* @__PURE__ */ jsxs3(Flex3, { gap: 2, wrap: "wrap", children: [
474
+ /* @__PURE__ */ jsx3(Text2, { size: 0, muted: true, children: projectId ? `${projectId.slice(0, 18)}\u2026` : "\u2014" }),
475
+ /* @__PURE__ */ jsx3(Text2, { size: 0, muted: true, children: "\xB7" }),
476
+ /* @__PURE__ */ jsxs3(Text2, { size: 0, muted: true, children: [
477
+ "Hook: ",
478
+ hookId || "\u2014"
479
+ ] }),
480
+ target.teamId && /* @__PURE__ */ jsxs3(Fragment, { children: [
352
481
  /* @__PURE__ */ jsx3(Text2, { size: 0, muted: true, children: "\xB7" }),
353
482
  /* @__PURE__ */ jsxs3(Text2, { size: 0, muted: true, children: [
354
- "Hook: ",
355
- hookId || "\u2014"
356
- ] }),
357
- target.teamId && /* @__PURE__ */ jsxs3(Fragment, { children: [
358
- /* @__PURE__ */ jsx3(Text2, { size: 0, muted: true, children: "\xB7" }),
359
- /* @__PURE__ */ jsxs3(Text2, { size: 0, muted: true, children: [
360
- "Team: ",
361
- target.teamId
362
- ] })
483
+ "Team: ",
484
+ target.teamId
363
485
  ] })
364
486
  ] })
365
487
  ] }),
366
- /* @__PURE__ */ jsx3(
367
- MenuButton,
368
- {
369
- button: /* @__PURE__ */ jsx3(Button2, { mode: "ghost", icon: EllipsisVerticalIcon }),
370
- id: `menu-${target._id}`,
371
- menu: /* @__PURE__ */ jsxs3(Menu, { children: [
488
+ loadingInitial ? /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, children: [
489
+ /* @__PURE__ */ jsx3(Spinner3, { muted: true }),
490
+ /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: "Loading\u2026" })
491
+ ] }) : /* @__PURE__ */ jsxs3(Stack2, { space: 2, children: [
492
+ /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, wrap: "wrap", children: [
493
+ triggering ? /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, children: [
494
+ /* @__PURE__ */ jsx3(Spinner3, { muted: true }),
495
+ /* @__PURE__ */ jsx3(Badge3, { tone: "caution", mode: "outline", children: "Triggering\u2026" })
496
+ ] }) : /* @__PURE__ */ jsx3(StatusBadge, { state: latest?.state, showSpinner: true }),
497
+ isActive && elapsed > 0 ? /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
498
+ /* @__PURE__ */ jsx3(ClockIcon, {}),
499
+ /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: formatDuration(elapsed) })
500
+ ] }) : !isActive && deployedAt ? /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: deployedAt }) : null,
501
+ branch && /* @__PURE__ */ jsxs3(Fragment, { children: [
502
+ /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: "\xB7" }),
503
+ /* @__PURE__ */ jsx3(Badge3, { tone: "default", mode: "outline", children: branch })
504
+ ] }),
505
+ sha && /* @__PURE__ */ jsx3(
506
+ Tooltip,
507
+ {
508
+ content: /* @__PURE__ */ jsx3(Box2, { padding: 2, children: /* @__PURE__ */ jsx3(Text2, { size: 1, children: commitMsg ?? sha }) }),
509
+ portal: true,
510
+ children: /* @__PURE__ */ jsx3(
511
+ Text2,
512
+ {
513
+ size: 1,
514
+ muted: true,
515
+ style: { cursor: "default", fontFamily: "monospace" },
516
+ children: sha
517
+ }
518
+ )
519
+ }
520
+ ),
521
+ creator && /* @__PURE__ */ jsxs3(Text2, { size: 1, muted: true, children: [
522
+ "by ",
523
+ creator
524
+ ] }),
525
+ latest?.url && latest.state === "READY" && /* @__PURE__ */ jsxs3(Fragment, { children: [
372
526
  /* @__PURE__ */ jsx3(
373
- MenuItem,
374
- {
375
- text: "History",
376
- icon: ClockIcon,
377
- onClick: () => setShowHistory(true)
378
- }
379
- ),
380
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx3(
381
- MenuItem,
527
+ "a",
382
528
  {
383
- text: "Build logs",
384
- icon: LaunchIcon2,
385
- as: "a",
386
- href: safeHref(latest?.inspectorUrl),
529
+ href: `https://${latest.url}`,
387
530
  target: "_blank",
388
- rel: "noreferrer"
531
+ rel: "noreferrer",
532
+ style: { color: "inherit" },
533
+ children: /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
534
+ /* @__PURE__ */ jsx3(LaunchIcon2, {}),
535
+ /* @__PURE__ */ jsx3(Text2, { size: 1, children: "Preview" })
536
+ ] })
389
537
  }
390
538
  ),
391
- !target.disableDeleteAction && /* @__PURE__ */ jsx3(
392
- MenuItem,
539
+ /* @__PURE__ */ jsx3(
540
+ Tooltip,
393
541
  {
394
- text: "Delete",
395
- icon: TrashIcon,
396
- tone: "critical",
397
- onClick: () => onDelete(target)
542
+ content: /* @__PURE__ */ jsx3(Box2, { padding: 2, children: /* @__PURE__ */ jsx3(Text2, { size: 1, children: copied ? "Copied!" : "Copy URL" }) }),
543
+ portal: true,
544
+ children: /* @__PURE__ */ jsx3(
545
+ Button2,
546
+ {
547
+ mode: "ghost",
548
+ icon: copied ? CheckmarkIcon : CopyIcon,
549
+ padding: 1,
550
+ tone: copied ? "positive" : "default",
551
+ onClick: copyUrl
552
+ }
553
+ )
398
554
  }
399
555
  )
400
- ] }),
401
- popover: { placement: "bottom-end" }
402
- }
403
- )
404
- ] }),
405
- loadingInitial ? /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, children: [
406
- /* @__PURE__ */ jsx3(Spinner3, { muted: true }),
407
- /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: "Loading\u2026" })
408
- ] }) : /* @__PURE__ */ jsxs3(Stack2, { space: 3, children: [
409
- /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 3, wrap: "wrap", children: [
410
- triggering ? /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, children: [
411
- /* @__PURE__ */ jsx3(Spinner3, { muted: true }),
412
- /* @__PURE__ */ jsx3(Badge3, { tone: "caution", mode: "outline", children: "Triggering\u2026" })
413
- ] }) : /* @__PURE__ */ jsx3(StatusBadge, { state: latest?.state, showSpinner: true }),
414
- isActive && elapsed > 0 && /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
415
- /* @__PURE__ */ jsx3(ClockIcon, {}),
416
- /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: formatDuration(elapsed) })
417
- ] }),
418
- !isActive && deployedAt && /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: deployedAt }),
419
- branch && /* @__PURE__ */ jsxs3(Fragment, { children: [
420
- /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: "\xB7" }),
421
- /* @__PURE__ */ jsx3(Badge3, { tone: "default", mode: "outline", children: branch })
556
+ ] })
422
557
  ] }),
423
- sha && /* @__PURE__ */ jsx3(
424
- Tooltip,
558
+ commitMsg && /* @__PURE__ */ jsx3(
559
+ Text2,
425
560
  {
426
- content: /* @__PURE__ */ jsx3(Box2, { padding: 2, children: /* @__PURE__ */ jsx3(Text2, { size: 1, children: commitMsg ?? sha }) }),
427
- portal: true,
428
- children: /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, style: { cursor: "default" }, children: sha })
561
+ size: 0,
562
+ muted: true,
563
+ style: {
564
+ overflow: "hidden",
565
+ textOverflow: "ellipsis",
566
+ whiteSpace: "nowrap"
567
+ },
568
+ children: commitMsg
429
569
  }
430
570
  ),
431
- creator && /* @__PURE__ */ jsxs3(Text2, { size: 1, muted: true, children: [
432
- "by ",
433
- creator
434
- ] }),
435
- latest?.url && latest.state === "READY" && /* @__PURE__ */ jsx3(
436
- "a",
437
- {
438
- href: `https://${latest.url}`,
439
- target: "_blank",
440
- rel: "noreferrer",
441
- style: { color: "inherit" },
442
- children: /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
443
- /* @__PURE__ */ jsx3(LaunchIcon2, {}),
444
- /* @__PURE__ */ jsx3(Text2, { size: 1, children: "Preview" })
571
+ isError && /* @__PURE__ */ jsxs3(Stack2, { space: 2, children: [
572
+ /* @__PURE__ */ jsx3(
573
+ Button2,
574
+ {
575
+ text: showErrorLogs ? "Hide error details" : "Show error details",
576
+ mode: "ghost",
577
+ tone: "critical",
578
+ icon: WarningOutlineIcon,
579
+ fontSize: 1,
580
+ padding: 2,
581
+ onClick: toggleErrorLogs,
582
+ style: { alignSelf: "flex-start" }
583
+ }
584
+ ),
585
+ showErrorLogs && /* @__PURE__ */ jsxs3(Card2, { tone: "critical", radius: 2, padding: 3, children: [
586
+ loadingLogs && /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 2, children: [
587
+ /* @__PURE__ */ jsx3(Spinner3, { muted: true }),
588
+ /* @__PURE__ */ jsx3(Text2, { size: 1, muted: true, children: "Loading logs\u2026" })
589
+ ] }),
590
+ logError && /* @__PURE__ */ jsxs3(Stack2, { space: 2, children: [
591
+ /* @__PURE__ */ jsx3(Text2, { size: 1, children: logError }),
592
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx3(
593
+ "a",
594
+ {
595
+ href: safeHref(latest?.inspectorUrl),
596
+ target: "_blank",
597
+ rel: "noreferrer",
598
+ style: { color: "inherit" },
599
+ children: /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
600
+ /* @__PURE__ */ jsx3(LaunchIcon2, {}),
601
+ /* @__PURE__ */ jsx3(Text2, { size: 1, children: "View full logs in Vercel" })
602
+ ] })
603
+ }
604
+ )
605
+ ] }),
606
+ !loadingLogs && !logError && errorLines.length > 0 && /* @__PURE__ */ jsxs3(Stack2, { space: 2, children: [
607
+ /* @__PURE__ */ jsx3(
608
+ Box2,
609
+ {
610
+ style: {
611
+ maxHeight: 240,
612
+ overflowY: "auto",
613
+ fontFamily: "monospace",
614
+ fontSize: 11,
615
+ lineHeight: 1.6
616
+ },
617
+ children: errorLines.map((line, i) => /* @__PURE__ */ jsx3(
618
+ Code,
619
+ {
620
+ size: 1,
621
+ style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" },
622
+ children: line
623
+ },
624
+ i
625
+ ))
626
+ }
627
+ ),
628
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx3(
629
+ "a",
630
+ {
631
+ href: safeHref(latest?.inspectorUrl),
632
+ target: "_blank",
633
+ rel: "noreferrer",
634
+ style: { color: "inherit" },
635
+ children: /* @__PURE__ */ jsxs3(Flex3, { align: "center", gap: 1, children: [
636
+ /* @__PURE__ */ jsx3(LaunchIcon2, {}),
637
+ /* @__PURE__ */ jsx3(Text2, { size: 1, children: "View full logs in Vercel" })
638
+ ] })
639
+ }
640
+ )
445
641
  ] })
446
- }
447
- )
448
- ] }),
449
- deployError && /* @__PURE__ */ jsx3(Card2, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsx3(Text2, { size: 1, children: deployError }) })
642
+ ] })
643
+ ] }),
644
+ deployError && /* @__PURE__ */ jsx3(Card2, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsx3(Text2, { size: 1, children: deployError }) })
645
+ ] })
450
646
  ] }),
451
- /* @__PURE__ */ jsxs3(Flex3, { align: "center", justify: "flex-end", gap: 2, children: [
452
- isActiveState(latest?.state) && /* @__PURE__ */ jsx3(
453
- Button2,
454
- {
455
- text: "Cancel",
456
- mode: "ghost",
457
- tone: "critical",
458
- loading: canceling,
459
- disabled: canceling,
460
- onClick: cancel
461
- }
462
- ),
463
- /* @__PURE__ */ jsx3(
464
- Button2,
465
- {
466
- text: "Deploy",
467
- tone: "primary",
468
- icon: RocketIcon,
469
- loading: triggering,
470
- disabled: isActive,
471
- onClick: deploy
472
- }
473
- )
474
- ] })
647
+ /* @__PURE__ */ jsxs3(
648
+ Flex3,
649
+ {
650
+ direction: "column",
651
+ gap: 2,
652
+ style: { flexShrink: 0, alignSelf: "stretch" },
653
+ children: [
654
+ isActiveState(latest?.state) && /* @__PURE__ */ jsx3(
655
+ Button2,
656
+ {
657
+ text: "Cancel",
658
+ mode: "ghost",
659
+ tone: "critical",
660
+ loading: canceling,
661
+ disabled: canceling,
662
+ onClick: cancel
663
+ }
664
+ ),
665
+ /* @__PURE__ */ jsx3(
666
+ Button2,
667
+ {
668
+ text: "Deploy",
669
+ tone: "primary",
670
+ icon: RocketIcon,
671
+ loading: triggering,
672
+ disabled: isActive,
673
+ onClick: deploy,
674
+ style: { flex: 1 }
675
+ }
676
+ )
677
+ ]
678
+ }
679
+ )
475
680
  ] }) }),
476
681
  showHistory && /* @__PURE__ */ jsx3(
477
682
  DeployHistory,
@@ -625,13 +830,7 @@ function DeployTool() {
625
830
  if (loading) {
626
831
  return /* @__PURE__ */ jsx5(Card4, { height: "fill", tone: "transparent", children: /* @__PURE__ */ jsx5(Flex5, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ jsx5(Spinner4, { muted: true }) }) });
627
832
  }
628
- if (!token && !showTokenSetup) {
629
- return /* @__PURE__ */ jsx5(TokenSetup, { onSaved: () => {
630
- setShowTokenSetup(false);
631
- load();
632
- } });
633
- }
634
- if (showTokenSetup) {
833
+ if (!token || showTokenSetup) {
635
834
  return /* @__PURE__ */ jsx5(
636
835
  TokenSetup,
637
836
  {
@@ -649,26 +848,33 @@ function DeployTool() {
649
848
  /* @__PURE__ */ jsx5(RocketIcon2, {}),
650
849
  /* @__PURE__ */ jsx5(Heading2, { size: 2, children: "Deploy" })
651
850
  ] }),
652
- /* @__PURE__ */ jsx5(
653
- Button4,
654
- {
655
- text: "API Token",
656
- mode: "ghost",
657
- icon: TokenIcon2,
658
- fontSize: 1,
659
- onClick: () => setShowTokenSetup(true)
660
- }
661
- )
851
+ /* @__PURE__ */ jsxs5(Flex5, { align: "center", gap: 3, children: [
852
+ /* @__PURE__ */ jsx5(Badge4, { tone: "positive", mode: "outline", children: "Connected" }),
853
+ /* @__PURE__ */ jsx5(
854
+ Button4,
855
+ {
856
+ text: "Change Token",
857
+ mode: "ghost",
858
+ icon: TokenIcon2,
859
+ fontSize: 1,
860
+ onClick: () => setShowTokenSetup(true)
861
+ }
862
+ )
863
+ ] })
662
864
  ] }),
663
865
  targets.length === 0 && /* @__PURE__ */ jsx5(Card4, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ jsxs5(Stack4, { space: 3, style: { textAlign: "center" }, children: [
664
866
  /* @__PURE__ */ jsx5(Text4, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
665
867
  /* @__PURE__ */ jsxs5(Text4, { size: 1, muted: true, children: [
666
868
  "Create a ",
667
869
  /* @__PURE__ */ jsx5("code", { children: "vercel_deploy" }),
668
- " document in the dataset with a Vercel deploy hook URL, or add one via the Sanity CLI."
870
+ " document in the dataset with a Vercel deploy hook URL."
669
871
  ] })
670
872
  ] }) }),
671
- token && targets.map((target) => /* @__PURE__ */ jsx5(
873
+ targets.length > 0 && /* @__PURE__ */ jsx5("div", { style: {
874
+ display: "grid",
875
+ gridTemplateColumns: "repeat(auto-fill, minmax(540px, 1fr))",
876
+ gap: "16px"
877
+ }, children: targets.map((target) => /* @__PURE__ */ jsx5(
672
878
  DeployItem,
673
879
  {
674
880
  target,
@@ -676,7 +882,7 @@ function DeployTool() {
676
882
  onDelete: setPendingDelete
677
883
  },
678
884
  target._id
679
- ))
885
+ )) })
680
886
  ] }) }),
681
887
  pendingDelete && /* @__PURE__ */ jsx5(
682
888
  Dialog2,
@@ -708,7 +914,7 @@ function DeployTool() {
708
914
  ] }),
709
915
  children: /* @__PURE__ */ jsx5(Box4, { padding: 4, children: /* @__PURE__ */ jsxs5(Stack4, { space: 3, children: [
710
916
  /* @__PURE__ */ jsxs5(Flex5, { align: "center", gap: 2, children: [
711
- /* @__PURE__ */ jsx5(WarningOutlineIcon, {}),
917
+ /* @__PURE__ */ jsx5(WarningOutlineIcon2, {}),
712
918
  /* @__PURE__ */ jsx5(Text4, { size: 2, weight: "semibold", children: pendingDelete.name })
713
919
  ] }),
714
920
  /* @__PURE__ */ jsx5(Text4, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liiift-studio/deploy-vercel-from-sanity",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "Sanity Studio v5 plugin — trigger and monitor Vercel deployments with full status, history, and build logs",
5
5
  "license": "MIT",
6
6
  "author": "Liiift Studio",