@liiift-studio/deploy-vercel-from-sanity 1.2.0 → 1.3.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.
- package/README.md +171 -37
- package/dist/index.d.mts +54 -36
- package/dist/index.d.ts +54 -36
- package/dist/index.js +687 -468
- package/dist/index.mjs +538 -318
- package/package.json +14 -9
- package/proxy/.env.example +40 -0
- package/proxy/README.md +228 -0
- package/proxy/core.ts +283 -0
- package/proxy/nextjs-app-router/route.ts +129 -0
- package/src/compat/code.tsx +0 -29
- package/src/compat/index.ts +0 -14
- package/src/compat/menu.tsx +0 -225
- package/src/compat/primitives.tsx +0 -93
- package/src/compat/resolve.ts +0 -55
- package/src/compat/toast.tsx +0 -173
- package/src/compat/tooltip.tsx +0 -78
- package/src/components/DeployHistory.tsx +0 -160
- package/src/components/DeployItem.tsx +0 -596
- package/src/components/DeployTargetForm.tsx +0 -172
- package/src/components/DeployTool.tsx +0 -318
- package/src/components/StatusBadge.tsx +0 -23
- package/src/components/TokenSetup.tsx +0 -98
- package/src/icons.tsx +0 -78
- package/src/index.ts +0 -47
- package/src/lib/api.ts +0 -102
- package/src/lib/helpers.ts +0 -131
- package/src/schema/schemaIcon.tsx +0 -38
- package/src/schema/vercelConfig.ts +0 -34
- package/src/schema/vercelDeploy.ts +0 -49
- package/src/types.ts +0 -77
- package/src/version.ts +0 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/index.
|
|
1
|
+
// src/index.tsx
|
|
2
2
|
import { definePlugin } from "sanity";
|
|
3
3
|
|
|
4
4
|
// src/icons.tsx
|
|
@@ -9,10 +9,18 @@ import * as sanityUi from "@sanity/ui";
|
|
|
9
9
|
import * as sanityIcons from "@sanity/icons";
|
|
10
10
|
var UI = sanityUi;
|
|
11
11
|
var ICONS = sanityIcons;
|
|
12
|
-
function
|
|
12
|
+
function resolveComponent(ns, name) {
|
|
13
13
|
const value = ns[name];
|
|
14
14
|
return typeof value === "function" || typeof value === "object" && value !== null ? value : void 0;
|
|
15
15
|
}
|
|
16
|
+
function resolveFunction(ns, name) {
|
|
17
|
+
const value = ns[name];
|
|
18
|
+
return typeof value === "function" ? value : void 0;
|
|
19
|
+
}
|
|
20
|
+
function resolveRecord(ns, name) {
|
|
21
|
+
const value = ns[name];
|
|
22
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
23
|
+
}
|
|
16
24
|
var STACK_USES_GAP = typeof UI.Stack === "function";
|
|
17
25
|
|
|
18
26
|
// src/icons.tsx
|
|
@@ -21,11 +29,11 @@ var GLYPH = { width: "1em", height: "1em", viewBox: "0 0 25 25", fill: "none" };
|
|
|
21
29
|
var MissingIcon = forwardRef(function MissingIcon2(props, ref) {
|
|
22
30
|
return /* @__PURE__ */ jsx("svg", { ...GLYPH, xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", focusable: "false", ...props, ref });
|
|
23
31
|
});
|
|
24
|
-
var SYMBOL_MAP =
|
|
32
|
+
var SYMBOL_MAP = resolveRecord(ICONS, "icons");
|
|
25
33
|
function resolveIcon(name, symbol) {
|
|
26
|
-
const named =
|
|
34
|
+
const named = resolveComponent(ICONS, name);
|
|
27
35
|
if (named) return named;
|
|
28
|
-
const Icon =
|
|
36
|
+
const Icon = resolveComponent(ICONS, "Icon");
|
|
29
37
|
if (!Icon) return MissingIcon;
|
|
30
38
|
if (SYMBOL_MAP && !(symbol in SYMBOL_MAP)) return MissingIcon;
|
|
31
39
|
const Resolved = forwardRef(function SanityIcon(props, ref) {
|
|
@@ -52,7 +60,28 @@ var WarningOutlineIcon = resolveIcon("WarningOutlineIcon", "warning-outline");
|
|
|
52
60
|
|
|
53
61
|
// src/components/DeployTool.tsx
|
|
54
62
|
import { useState as useState8, useEffect as useEffect5, useCallback as useCallback7 } from "react";
|
|
55
|
-
import { useClient as
|
|
63
|
+
import { useClient as useClient4 } from "sanity";
|
|
64
|
+
|
|
65
|
+
// src/config.tsx
|
|
66
|
+
import { createContext, useContext } from "react";
|
|
67
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
68
|
+
var DEFAULTS = { mode: "direct" };
|
|
69
|
+
var ConfigContext = createContext(DEFAULTS);
|
|
70
|
+
function resolveConfig(options) {
|
|
71
|
+
const config = options ?? {};
|
|
72
|
+
return {
|
|
73
|
+
mode: config.mode ?? "direct",
|
|
74
|
+
// Trailing slashes would double up when request paths are appended.
|
|
75
|
+
proxyUrl: config.proxyUrl?.replace(/\/+$/, ""),
|
|
76
|
+
statusKey: config.statusKey
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function ConfigProvider({ value, children }) {
|
|
80
|
+
return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value, children });
|
|
81
|
+
}
|
|
82
|
+
function usePluginConfig() {
|
|
83
|
+
return useContext(ConfigContext);
|
|
84
|
+
}
|
|
56
85
|
|
|
57
86
|
// src/components/DeployItem.tsx
|
|
58
87
|
import { useState as useState5, useEffect as useEffect4, useCallback as useCallback4, useRef as useRef2 } from "react";
|
|
@@ -60,24 +89,46 @@ import { flushSync } from "react-dom";
|
|
|
60
89
|
|
|
61
90
|
// src/compat/primitives.tsx
|
|
62
91
|
import { createElement, forwardRef as forwardRef2 } from "react";
|
|
63
|
-
import { jsx as
|
|
92
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
64
93
|
function domFallback(tag) {
|
|
65
94
|
const Fallback = forwardRef2(function SanityUiFallback(props, ref) {
|
|
66
|
-
const { children, style, id, className, onClick, href, title, ...rest } = props;
|
|
95
|
+
const { children, style, id, className, onClick, href, title, as, ...rest } = props;
|
|
96
|
+
const element = typeof as === "string" ? as : tag;
|
|
67
97
|
const passthrough = { style, id, className, onClick, href, title, ref };
|
|
68
|
-
for (const key of [
|
|
98
|
+
for (const key of [
|
|
99
|
+
"role",
|
|
100
|
+
"type",
|
|
101
|
+
"value",
|
|
102
|
+
"checked",
|
|
103
|
+
"placeholder",
|
|
104
|
+
"disabled",
|
|
105
|
+
"tabIndex",
|
|
106
|
+
"onChange",
|
|
107
|
+
"onKeyDown",
|
|
108
|
+
"onFocus",
|
|
109
|
+
"onBlur",
|
|
110
|
+
"onMouseEnter",
|
|
111
|
+
"onMouseLeave",
|
|
112
|
+
"htmlFor",
|
|
113
|
+
"target",
|
|
114
|
+
"rel",
|
|
115
|
+
"name",
|
|
116
|
+
"autoComplete",
|
|
117
|
+
"required",
|
|
118
|
+
"readOnly"
|
|
119
|
+
]) {
|
|
69
120
|
if (key in rest) passthrough[key] = rest[key];
|
|
70
121
|
}
|
|
71
122
|
for (const key of Object.keys(rest)) {
|
|
72
123
|
if (key.startsWith("aria-") || key.startsWith("data-")) passthrough[key] = rest[key];
|
|
73
124
|
}
|
|
74
|
-
return createElement(
|
|
125
|
+
return createElement(element, passthrough, children);
|
|
75
126
|
});
|
|
76
127
|
Fallback.displayName = `SanityUiFallback(${tag})`;
|
|
77
128
|
return Fallback;
|
|
78
129
|
}
|
|
79
130
|
function primitive(name, tag) {
|
|
80
|
-
return
|
|
131
|
+
return resolveComponent(UI, name) ?? domFallback(tag);
|
|
81
132
|
}
|
|
82
133
|
var Box = primitive("Box", "div");
|
|
83
134
|
var Card = primitive("Card", "div");
|
|
@@ -96,12 +147,12 @@ var Dialog = primitive("Dialog", "div");
|
|
|
96
147
|
var SanityStack = primitive("Stack", "div");
|
|
97
148
|
function Stack({ space, children, ...rest }) {
|
|
98
149
|
const spacing = space === void 0 ? {} : STACK_USES_GAP ? { gap: space } : { space };
|
|
99
|
-
return /* @__PURE__ */
|
|
150
|
+
return /* @__PURE__ */ jsx3(SanityStack, { ...rest, ...spacing, children });
|
|
100
151
|
}
|
|
101
152
|
|
|
102
153
|
// src/compat/toast.tsx
|
|
103
154
|
import { useCallback, useEffect, useState } from "react";
|
|
104
|
-
import { jsx as
|
|
155
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
105
156
|
var LOCAL_TOAST_MS = 6e3;
|
|
106
157
|
var MAX_VISIBLE_TOASTS = 4;
|
|
107
158
|
var TOAST_Z_INDEX = 1e6;
|
|
@@ -136,11 +187,19 @@ function scheduleDismiss(id, status) {
|
|
|
136
187
|
}
|
|
137
188
|
function pushLocalToast(params) {
|
|
138
189
|
const toast = { ...params, id: nextToastId++ };
|
|
139
|
-
|
|
190
|
+
const next = [...localToasts, toast];
|
|
191
|
+
for (const dropped of next.slice(0, Math.max(0, next.length - MAX_VISIBLE_TOASTS))) {
|
|
192
|
+
const timer = dismissTimers.get(dropped.id);
|
|
193
|
+
if (timer) {
|
|
194
|
+
clearTimeout(timer);
|
|
195
|
+
dismissTimers.delete(dropped.id);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
localToasts = next.slice(-MAX_VISIBLE_TOASTS);
|
|
140
199
|
emitToasts();
|
|
141
200
|
scheduleDismiss(toast.id, toast.status);
|
|
142
201
|
}
|
|
143
|
-
var installedUseToast =
|
|
202
|
+
var installedUseToast = resolveFunction(UI, "useToast");
|
|
144
203
|
var localToaster = { push: pushLocalToast };
|
|
145
204
|
function useToast() {
|
|
146
205
|
const real = installedUseToast;
|
|
@@ -157,6 +216,10 @@ function ToastViewport() {
|
|
|
157
216
|
toastListeners.delete(setToasts);
|
|
158
217
|
};
|
|
159
218
|
}, []);
|
|
219
|
+
const resume = useCallback((toast, el) => {
|
|
220
|
+
if (el && el.contains(document.activeElement)) return;
|
|
221
|
+
scheduleDismiss(toast.id, toast.status);
|
|
222
|
+
}, []);
|
|
160
223
|
const hold = useCallback((id) => {
|
|
161
224
|
const timer = dismissTimers.get(id);
|
|
162
225
|
if (timer) {
|
|
@@ -165,12 +228,11 @@ function ToastViewport() {
|
|
|
165
228
|
}
|
|
166
229
|
}, []);
|
|
167
230
|
if (installedUseToast) return null;
|
|
168
|
-
return /* @__PURE__ */
|
|
231
|
+
return /* @__PURE__ */ jsx4(
|
|
169
232
|
Box,
|
|
170
233
|
{
|
|
171
|
-
role: "
|
|
172
|
-
"aria-
|
|
173
|
-
"aria-atomic": false,
|
|
234
|
+
role: "log",
|
|
235
|
+
"aria-label": "Deployment notifications",
|
|
174
236
|
style: {
|
|
175
237
|
position: "fixed",
|
|
176
238
|
bottom: 16,
|
|
@@ -179,23 +241,24 @@ function ToastViewport() {
|
|
|
179
241
|
width: "min(360px, calc(100vw - 32px))",
|
|
180
242
|
pointerEvents: "none"
|
|
181
243
|
},
|
|
182
|
-
children: /* @__PURE__ */
|
|
244
|
+
children: /* @__PURE__ */ jsx4(Stack, { space: 2, children: toasts.map((toast) => /* @__PURE__ */ jsx4(
|
|
183
245
|
Card,
|
|
184
246
|
{
|
|
185
247
|
padding: 3,
|
|
186
248
|
radius: 2,
|
|
187
249
|
shadow: 3,
|
|
188
|
-
tone: LOCAL_TOAST_TONE[toast.status ?? "info"]
|
|
250
|
+
tone: LOCAL_TOAST_TONE[toast.status ?? "info"],
|
|
189
251
|
style: { pointerEvents: "auto" },
|
|
190
252
|
onMouseEnter: () => hold(toast.id),
|
|
191
253
|
onFocusCapture: () => hold(toast.id),
|
|
192
|
-
onMouseLeave: () =>
|
|
254
|
+
onMouseLeave: (e) => resume(toast, e.currentTarget),
|
|
255
|
+
onBlurCapture: (e) => resume(toast, e.currentTarget),
|
|
193
256
|
children: /* @__PURE__ */ jsxs(Flex, { align: "flex-start", gap: 3, children: [
|
|
194
257
|
/* @__PURE__ */ jsxs(Stack, { space: 2, flex: 1, children: [
|
|
195
|
-
toast.title && /* @__PURE__ */
|
|
196
|
-
toast.description && /* @__PURE__ */
|
|
258
|
+
toast.title && /* @__PURE__ */ jsx4(Text, { size: 1, weight: "semibold", children: toast.title }),
|
|
259
|
+
toast.description && /* @__PURE__ */ jsx4(Text, { size: 1, muted: true, children: toast.description })
|
|
197
260
|
] }),
|
|
198
|
-
/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ jsx4(
|
|
199
262
|
Button,
|
|
200
263
|
{
|
|
201
264
|
mode: "bleed",
|
|
@@ -215,50 +278,49 @@ function ToastViewport() {
|
|
|
215
278
|
}
|
|
216
279
|
|
|
217
280
|
// src/compat/tooltip.tsx
|
|
218
|
-
import { useId, useState as useState2 } from "react";
|
|
219
|
-
import { jsx as
|
|
220
|
-
var InstalledTooltip =
|
|
281
|
+
import { cloneElement, isValidElement, useId, useState as useState2 } from "react";
|
|
282
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
283
|
+
var InstalledTooltip = resolveComponent(UI, "Tooltip");
|
|
221
284
|
function Tooltip({ text, children }) {
|
|
222
285
|
const id = useId();
|
|
223
286
|
const [visible, setVisible] = useState2(false);
|
|
224
287
|
if (InstalledTooltip) {
|
|
225
|
-
return /* @__PURE__ */
|
|
288
|
+
return /* @__PURE__ */ jsx5(InstalledTooltip, { content: /* @__PURE__ */ jsx5(Box, { padding: 2, children: /* @__PURE__ */ jsx5(Text, { size: 1, children: text }) }), portal: true, children });
|
|
226
289
|
}
|
|
290
|
+
const described = visible && isValidElement(children) ? cloneElement(children, { "aria-describedby": id }) : children;
|
|
227
291
|
return /* @__PURE__ */ jsxs2(
|
|
228
292
|
"span",
|
|
229
293
|
{
|
|
230
294
|
style: { position: "relative", display: "inline-flex" },
|
|
231
|
-
"aria-describedby": id,
|
|
232
295
|
onMouseEnter: () => setVisible(true),
|
|
233
296
|
onMouseLeave: () => setVisible(false),
|
|
234
297
|
onFocusCapture: () => setVisible(true),
|
|
235
298
|
onBlurCapture: () => setVisible(false),
|
|
236
299
|
onKeyDown: (e) => {
|
|
237
|
-
if (e.key === "Escape")
|
|
300
|
+
if (e.key === "Escape" && visible) {
|
|
301
|
+
e.stopPropagation();
|
|
302
|
+
setVisible(false);
|
|
303
|
+
}
|
|
238
304
|
},
|
|
239
305
|
children: [
|
|
240
|
-
|
|
241
|
-
/* @__PURE__ */
|
|
242
|
-
|
|
306
|
+
described,
|
|
307
|
+
visible && /* @__PURE__ */ jsx5(
|
|
308
|
+
"span",
|
|
243
309
|
{
|
|
244
310
|
id,
|
|
245
311
|
role: "tooltip",
|
|
246
|
-
radius: 2,
|
|
247
|
-
shadow: 2,
|
|
248
|
-
padding: 2,
|
|
249
312
|
style: {
|
|
250
313
|
position: "absolute",
|
|
251
314
|
bottom: "100%",
|
|
252
315
|
left: "50%",
|
|
253
316
|
transform: "translateX(-50%)",
|
|
254
|
-
|
|
317
|
+
// No gap between trigger and tooltip, so the pointer can travel onto it
|
|
318
|
+
// without leaving the hover target (WCAG 1.4.13 Hoverable).
|
|
319
|
+
paddingBottom: 4,
|
|
255
320
|
whiteSpace: "nowrap",
|
|
256
|
-
|
|
257
|
-
zIndex: 1e3,
|
|
258
|
-
// Kept in the accessibility tree when hidden so `aria-describedby` still resolves.
|
|
259
|
-
visibility: visible ? "visible" : "hidden"
|
|
321
|
+
zIndex: 1e3
|
|
260
322
|
},
|
|
261
|
-
children: /* @__PURE__ */
|
|
323
|
+
children: /* @__PURE__ */ jsx5(Card, { radius: 2, shadow: 2, padding: 2, children: /* @__PURE__ */ jsx5(Text, { size: 1, children: text }) })
|
|
262
324
|
}
|
|
263
325
|
)
|
|
264
326
|
]
|
|
@@ -268,10 +330,10 @@ function Tooltip({ text, children }) {
|
|
|
268
330
|
|
|
269
331
|
// src/compat/menu.tsx
|
|
270
332
|
import { useCallback as useCallback2, useEffect as useEffect2, useId as useId2, useRef, useState as useState3 } from "react";
|
|
271
|
-
import { jsx as
|
|
272
|
-
var InstalledMenuButton =
|
|
273
|
-
var InstalledMenu =
|
|
274
|
-
var InstalledMenuItem =
|
|
333
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
334
|
+
var InstalledMenuButton = resolveComponent(UI, "MenuButton");
|
|
335
|
+
var InstalledMenu = resolveComponent(UI, "Menu");
|
|
336
|
+
var InstalledMenuItem = resolveComponent(UI, "MenuItem");
|
|
275
337
|
var INSTALLED_MENU = InstalledMenuButton && InstalledMenu && InstalledMenuItem ? { MenuButton: InstalledMenuButton, Menu: InstalledMenu, MenuItem: InstalledMenuItem } : null;
|
|
276
338
|
var itemKey = (item, index) => item.key ?? `${index}-${item.text}`;
|
|
277
339
|
function ActionMenu({ id, label, items, buttonIcon }) {
|
|
@@ -299,7 +361,10 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
299
361
|
useEffect2(() => {
|
|
300
362
|
if (INSTALLED_MENU || !open) return;
|
|
301
363
|
const onPointerDown = (e) => {
|
|
302
|
-
if (
|
|
364
|
+
if (wrapRef.current?.contains(e.target)) return;
|
|
365
|
+
const hadFocus = wrapRef.current?.contains(document.activeElement);
|
|
366
|
+
setOpen(false);
|
|
367
|
+
if (hadFocus) triggerRef.current?.focus();
|
|
303
368
|
};
|
|
304
369
|
document.addEventListener("mousedown", onPointerDown);
|
|
305
370
|
return () => document.removeEventListener("mousedown", onPointerDown);
|
|
@@ -310,13 +375,13 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
310
375
|
}, [close]);
|
|
311
376
|
if (INSTALLED_MENU) {
|
|
312
377
|
const { MenuButton, Menu, MenuItem } = INSTALLED_MENU;
|
|
313
|
-
return /* @__PURE__ */
|
|
378
|
+
return /* @__PURE__ */ jsx6(
|
|
314
379
|
MenuButton,
|
|
315
380
|
{
|
|
316
381
|
id,
|
|
317
|
-
button: /* @__PURE__ */
|
|
382
|
+
button: /* @__PURE__ */ jsx6(Button, { mode: "ghost", icon: buttonIcon, padding: 2, "aria-label": label }),
|
|
318
383
|
popover: { placement: "bottom-end" },
|
|
319
|
-
menu: /* @__PURE__ */
|
|
384
|
+
menu: /* @__PURE__ */ jsx6(Menu, { children: items.map((item, i) => /* @__PURE__ */ jsx6(
|
|
320
385
|
MenuItem,
|
|
321
386
|
{
|
|
322
387
|
text: item.text,
|
|
@@ -337,7 +402,20 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
337
402
|
return;
|
|
338
403
|
}
|
|
339
404
|
if (e.key === "Tab") {
|
|
340
|
-
|
|
405
|
+
triggerRef.current?.focus();
|
|
406
|
+
setOpen(false);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
410
|
+
e.preventDefault();
|
|
411
|
+
const item = shownItems[activeIndex];
|
|
412
|
+
if (item) {
|
|
413
|
+
if (item.href) {
|
|
414
|
+
itemRefs.current[activeIndex]?.click();
|
|
415
|
+
} else {
|
|
416
|
+
runAction(item);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
341
419
|
return;
|
|
342
420
|
}
|
|
343
421
|
if (e.key === "ArrowDown") {
|
|
@@ -371,7 +449,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
371
449
|
}
|
|
372
450
|
};
|
|
373
451
|
return /* @__PURE__ */ jsxs3("div", { ref: wrapRef, style: { position: "relative" }, children: [
|
|
374
|
-
/* @__PURE__ */
|
|
452
|
+
/* @__PURE__ */ jsx6(
|
|
375
453
|
Button,
|
|
376
454
|
{
|
|
377
455
|
ref: triggerRef,
|
|
@@ -387,7 +465,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
387
465
|
onKeyDown: onTriggerKeyDown
|
|
388
466
|
}
|
|
389
467
|
),
|
|
390
|
-
open && /* @__PURE__ */
|
|
468
|
+
open && /* @__PURE__ */ jsx6(
|
|
391
469
|
Card,
|
|
392
470
|
{
|
|
393
471
|
id: menuId,
|
|
@@ -398,13 +476,13 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
398
476
|
"aria-labelledby": id,
|
|
399
477
|
onKeyDown: onMenuKeyDown,
|
|
400
478
|
style: { position: "absolute", top: "100%", right: 0, marginTop: 4, zIndex: 1e3, minWidth: 200 },
|
|
401
|
-
children: /* @__PURE__ */
|
|
479
|
+
children: /* @__PURE__ */ jsx6(Stack, { space: 1, role: "none", children: shownItems.map((item, i) => {
|
|
402
480
|
const Icon = item.icon;
|
|
403
481
|
const row = /* @__PURE__ */ jsxs3(Flex, { align: "center", gap: 2, paddingX: 2, paddingY: 2, children: [
|
|
404
|
-
/* @__PURE__ */
|
|
405
|
-
/* @__PURE__ */
|
|
482
|
+
/* @__PURE__ */ jsx6(Icon, { width: "1em", height: "1em", "aria-hidden": "true" }),
|
|
483
|
+
/* @__PURE__ */ jsx6(Text, { size: 1, children: item.text })
|
|
406
484
|
] });
|
|
407
|
-
const content = item.tone === "critical" ? /* @__PURE__ */
|
|
485
|
+
const content = item.tone === "critical" ? /* @__PURE__ */ jsx6(Card, { tone: "critical", radius: 1, children: row }) : row;
|
|
408
486
|
const shared = {
|
|
409
487
|
role: "menuitem",
|
|
410
488
|
// Roving tabindex — the menu is one tab stop, arrows move within it.
|
|
@@ -412,7 +490,6 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
412
490
|
ref: (el) => {
|
|
413
491
|
itemRefs.current[i] = el;
|
|
414
492
|
},
|
|
415
|
-
onMouseEnter: () => setActiveIndex(i),
|
|
416
493
|
style: {
|
|
417
494
|
display: "block",
|
|
418
495
|
width: "100%",
|
|
@@ -430,22 +507,24 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
430
507
|
outlineOffset: -2
|
|
431
508
|
}
|
|
432
509
|
};
|
|
433
|
-
return item.href ? /* @__PURE__ */
|
|
510
|
+
return item.href ? /* @__PURE__ */ jsx6(
|
|
434
511
|
"a",
|
|
435
512
|
{
|
|
436
513
|
...shared,
|
|
437
514
|
href: item.href,
|
|
438
515
|
target: "_blank",
|
|
439
516
|
rel: "noreferrer",
|
|
440
|
-
onClick: () =>
|
|
517
|
+
onClick: () => {
|
|
518
|
+
setOpen(false);
|
|
519
|
+
triggerRef.current?.focus();
|
|
520
|
+
},
|
|
441
521
|
children: content
|
|
442
522
|
},
|
|
443
523
|
itemKey(item, i)
|
|
444
|
-
) : /* @__PURE__ */
|
|
445
|
-
"
|
|
524
|
+
) : /* @__PURE__ */ jsx6(
|
|
525
|
+
"div",
|
|
446
526
|
{
|
|
447
527
|
...shared,
|
|
448
|
-
type: "button",
|
|
449
528
|
onClick: () => runAction(item),
|
|
450
529
|
children: content
|
|
451
530
|
},
|
|
@@ -458,8 +537,8 @@ function ActionMenu({ id, label, items, buttonIcon }) {
|
|
|
458
537
|
}
|
|
459
538
|
|
|
460
539
|
// src/compat/code.tsx
|
|
461
|
-
import { jsx as
|
|
462
|
-
var InstalledCode =
|
|
540
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
541
|
+
var InstalledCode = resolveComponent(UI, "Code");
|
|
463
542
|
var FALLBACK_CODE_STYLE = {
|
|
464
543
|
display: "block",
|
|
465
544
|
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
@@ -468,8 +547,8 @@ var FALLBACK_CODE_STYLE = {
|
|
|
468
547
|
margin: 0
|
|
469
548
|
};
|
|
470
549
|
function Code({ style, children }) {
|
|
471
|
-
if (InstalledCode) return /* @__PURE__ */
|
|
472
|
-
return /* @__PURE__ */
|
|
550
|
+
if (InstalledCode) return /* @__PURE__ */ jsx7(InstalledCode, { size: 1, style, children });
|
|
551
|
+
return /* @__PURE__ */ jsx7("code", { style: { ...FALLBACK_CODE_STYLE, ...style }, children });
|
|
473
552
|
}
|
|
474
553
|
|
|
475
554
|
// src/lib/api.ts
|
|
@@ -485,7 +564,7 @@ async function vercelFetch(path, token, init) {
|
|
|
485
564
|
}
|
|
486
565
|
});
|
|
487
566
|
if (!res.ok) {
|
|
488
|
-
const hint = res.status === 401 ? " \u2014 token is invalid or expired. Reconnect your API token." : res.status === 403 ? " \u2014 token lacks the required permissions.
|
|
567
|
+
const hint = res.status === 401 ? " \u2014 token is invalid or expired. Reconnect your API token." : res.status === 403 ? " \u2014 token lacks the required permissions. Scope it to the team that owns the project, and set the target's Team ID." : res.status === 404 ? " \u2014 resource not found. Check the deploy hook URL and team ID." : res.status === 429 ? " \u2014 rate limit reached. Wait a moment and try again." : res.status >= 500 ? " \u2014 Vercel is experiencing issues. Try again shortly." : "";
|
|
489
568
|
throw new Error(`Vercel API ${res.status}${hint}`);
|
|
490
569
|
}
|
|
491
570
|
return res.json();
|
|
@@ -524,15 +603,75 @@ async function getDeploymentEvents(opts) {
|
|
|
524
603
|
const params = new URLSearchParams({ limit: "100", direction: "backward" });
|
|
525
604
|
if (opts.teamId) params.set("teamId", opts.teamId);
|
|
526
605
|
const raw = await vercelFetch(
|
|
527
|
-
`/v2/deployments/${opts.deploymentId}/events?${params}`,
|
|
606
|
+
`/v2/deployments/${encodeURIComponent(opts.deploymentId)}/events?${params}`,
|
|
528
607
|
opts.token
|
|
529
608
|
);
|
|
530
609
|
const events = Array.isArray(raw) ? raw : raw.events ?? [];
|
|
531
610
|
return events.filter((e) => e.text?.trim());
|
|
532
611
|
}
|
|
533
612
|
|
|
613
|
+
// src/lib/transport.ts
|
|
614
|
+
async function proxyFetch(url, statusKey, init) {
|
|
615
|
+
const res = await fetch(url, {
|
|
616
|
+
...init,
|
|
617
|
+
headers: {
|
|
618
|
+
"Content-Type": "application/json",
|
|
619
|
+
...statusKey ? { "x-deploy-status-key": statusKey } : {},
|
|
620
|
+
...init?.headers
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
if (!res.ok) {
|
|
624
|
+
const hint = res.status === 401 ? " \u2014 the proxy rejected the status key. Check `statusKey` matches the proxy." : res.status === 404 ? " \u2014 the proxy has no target with that key. Check `proxyKey` matches the proxy configuration." : res.status >= 500 ? " \u2014 the deploy proxy is failing. Check its logs." : "";
|
|
625
|
+
throw new Error(`Deploy proxy ${res.status}${hint}`);
|
|
626
|
+
}
|
|
627
|
+
return res.json();
|
|
628
|
+
}
|
|
629
|
+
async function fetchDeployments(transport, target, limit) {
|
|
630
|
+
if (transport.mode === "direct") {
|
|
631
|
+
if (!target.projectId || !target.hookId) return [];
|
|
632
|
+
return listDeployments({
|
|
633
|
+
projectId: target.projectId,
|
|
634
|
+
hookId: target.hookId,
|
|
635
|
+
token: transport.token,
|
|
636
|
+
teamId: target.teamId,
|
|
637
|
+
limit
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
const params = new URLSearchParams({ key: target.proxyKey ?? "" });
|
|
641
|
+
if (limit) params.set("limit", String(limit));
|
|
642
|
+
const data = await proxyFetch(
|
|
643
|
+
`${transport.proxyUrl}/deployments?${params}`,
|
|
644
|
+
transport.statusKey
|
|
645
|
+
);
|
|
646
|
+
return data.deployments ?? [];
|
|
647
|
+
}
|
|
648
|
+
async function cancelDeploy(transport, target, deploymentId) {
|
|
649
|
+
if (transport.mode === "direct") {
|
|
650
|
+
return cancelDeployment({ deploymentId, token: transport.token, teamId: target.teamId });
|
|
651
|
+
}
|
|
652
|
+
await proxyFetch(`${transport.proxyUrl}/cancel`, transport.statusKey, {
|
|
653
|
+
method: "POST",
|
|
654
|
+
body: JSON.stringify({ key: target.proxyKey, deploymentId })
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
async function fetchDeploymentEvents(transport, target, deploymentId) {
|
|
658
|
+
if (transport.mode === "direct") {
|
|
659
|
+
return getDeploymentEvents({ deploymentId, token: transport.token, teamId: target.teamId });
|
|
660
|
+
}
|
|
661
|
+
const params = new URLSearchParams({ key: target.proxyKey ?? "", deploymentId });
|
|
662
|
+
const data = await proxyFetch(
|
|
663
|
+
`${transport.proxyUrl}/events?${params}`,
|
|
664
|
+
transport.statusKey
|
|
665
|
+
);
|
|
666
|
+
return data.events ?? [];
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// src/components/DeployItem.tsx
|
|
670
|
+
import { useClient } from "sanity";
|
|
671
|
+
|
|
534
672
|
// src/lib/helpers.ts
|
|
535
673
|
function parseHookUrl(url) {
|
|
674
|
+
if (!url) return { projectId: "", hookId: "" };
|
|
536
675
|
try {
|
|
537
676
|
const path = new URL(url).pathname;
|
|
538
677
|
const parts = path.split("/").filter(Boolean);
|
|
@@ -622,29 +761,33 @@ function projectHref(inspectorUrl) {
|
|
|
622
761
|
}
|
|
623
762
|
|
|
624
763
|
// src/components/StatusBadge.tsx
|
|
625
|
-
import { jsx as
|
|
764
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
626
765
|
function StatusBadge({ state, showSpinner }) {
|
|
627
766
|
const { label, tone } = stateLabel(state);
|
|
628
767
|
const spinning = showSpinner && (state === "QUEUED" || state === "INITIALIZING" || state === "BUILDING");
|
|
629
768
|
return /* @__PURE__ */ jsxs4(Flex, { align: "center", gap: 2, children: [
|
|
630
|
-
spinning && /* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
769
|
+
spinning && /* @__PURE__ */ jsx8(Spinner, { muted: true }),
|
|
770
|
+
/* @__PURE__ */ jsx8(Badge, { tone, padding: 2, children: label })
|
|
632
771
|
] });
|
|
633
772
|
}
|
|
634
773
|
|
|
635
774
|
// src/components/DeployHistory.tsx
|
|
636
|
-
import { useEffect as useEffect3, useState as useState4, useCallback as useCallback3 } from "react";
|
|
637
|
-
import { jsx as
|
|
775
|
+
import { useId as useId3, useEffect as useEffect3, useState as useState4, useCallback as useCallback3 } from "react";
|
|
776
|
+
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
638
777
|
function DeployHistory({ target, token, onClose }) {
|
|
778
|
+
const dialogId = useId3();
|
|
779
|
+
const pluginConfig = usePluginConfig();
|
|
639
780
|
const [deployments, setDeployments] = useState4([]);
|
|
640
781
|
const [loading, setLoading] = useState4(true);
|
|
641
782
|
const [error, setError] = useState4(null);
|
|
642
783
|
const { projectId, hookId } = parseHookUrl(target.url);
|
|
784
|
+
const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
|
|
785
|
+
const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
|
|
643
786
|
const load = useCallback3(async () => {
|
|
644
787
|
setLoading(true);
|
|
645
788
|
setError(null);
|
|
646
789
|
try {
|
|
647
|
-
const data = await
|
|
790
|
+
const data = await fetchDeployments(transport, targetRef, 20);
|
|
648
791
|
setDeployments(data);
|
|
649
792
|
} catch (err) {
|
|
650
793
|
setError(err instanceof Error ? err.message : "Failed to load history");
|
|
@@ -655,52 +798,52 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
655
798
|
useEffect3(() => {
|
|
656
799
|
load();
|
|
657
800
|
}, [load]);
|
|
658
|
-
return /* @__PURE__ */
|
|
801
|
+
return /* @__PURE__ */ jsx9(
|
|
659
802
|
Dialog,
|
|
660
803
|
{
|
|
661
804
|
header: `${target.name} \u2014 Deployment History`,
|
|
662
|
-
id:
|
|
805
|
+
id: dialogId,
|
|
663
806
|
onClose,
|
|
664
807
|
width: 2,
|
|
665
|
-
footer: /* @__PURE__ */
|
|
808
|
+
footer: /* @__PURE__ */ jsx9(Box, { padding: 3, children: /* @__PURE__ */ jsx9(Button, { text: "Close", icon: CloseIcon, mode: "ghost", onClick: onClose }) }),
|
|
666
809
|
children: /* @__PURE__ */ jsxs5(Box, { padding: 4, children: [
|
|
667
|
-
loading && /* @__PURE__ */
|
|
668
|
-
error && /* @__PURE__ */
|
|
669
|
-
!loading && !error && deployments.length === 0 && /* @__PURE__ */
|
|
810
|
+
loading && /* @__PURE__ */ jsx9(Flex, { justify: "center", padding: 6, children: /* @__PURE__ */ jsx9(Spinner, { muted: true }) }),
|
|
811
|
+
error && /* @__PURE__ */ jsx9(Card, { tone: "critical", padding: 4, radius: 2, children: /* @__PURE__ */ jsx9(Text, { size: 1, children: error }) }),
|
|
812
|
+
!loading && !error && deployments.length === 0 && /* @__PURE__ */ jsx9(Card, { tone: "transparent", padding: 4, children: /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, align: "center", children: "No deployments found for this hook." }) }),
|
|
670
813
|
!loading && deployments.length > 0 && /* @__PURE__ */ jsxs5(Stack, { space: 2, children: [
|
|
671
|
-
/* @__PURE__ */
|
|
672
|
-
/* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
675
|
-
/* @__PURE__ */
|
|
676
|
-
/* @__PURE__ */
|
|
814
|
+
/* @__PURE__ */ jsx9(Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, children: [
|
|
815
|
+
/* @__PURE__ */ jsx9(Box, { flex: 2, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Preview URL" }) }),
|
|
816
|
+
/* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Status" }) }),
|
|
817
|
+
/* @__PURE__ */ jsx9(Box, { flex: 2, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Branch \xB7 Commit" }) }),
|
|
818
|
+
/* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Deployed" }) }),
|
|
819
|
+
/* @__PURE__ */ jsx9(Box, { style: { width: 64 }, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Logs" }) })
|
|
677
820
|
] }) }),
|
|
678
821
|
deployments.map((d) => {
|
|
679
822
|
const { label, tone } = stateLabel(d.state);
|
|
680
823
|
const branch = d.meta?.githubCommitRef ?? "\u2014";
|
|
681
824
|
const sha = shortSha(d.meta?.githubCommitSha);
|
|
682
825
|
const message = d.meta?.githubCommitMessage?.split("\n")[0] ?? "";
|
|
683
|
-
return /* @__PURE__ */
|
|
684
|
-
/* @__PURE__ */
|
|
826
|
+
return /* @__PURE__ */ jsx9(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, align: "center", children: [
|
|
827
|
+
/* @__PURE__ */ jsx9(Box, { flex: 2, style: { overflow: "hidden" }, children: deploymentHref(d.url) ? /* @__PURE__ */ jsx9(
|
|
685
828
|
"a",
|
|
686
829
|
{
|
|
687
830
|
href: deploymentHref(d.url),
|
|
688
831
|
target: "_blank",
|
|
689
832
|
rel: "noreferrer",
|
|
690
833
|
style: { color: "inherit" },
|
|
691
|
-
children: /* @__PURE__ */
|
|
834
|
+
children: /* @__PURE__ */ jsx9(Text, { size: 1, style: { textDecoration: "underline" }, children: d.url.length > 36 ? `${d.url.slice(0, 36)}\u2026` : d.url })
|
|
692
835
|
}
|
|
693
|
-
) : /* @__PURE__ */
|
|
694
|
-
/* @__PURE__ */
|
|
695
|
-
/* @__PURE__ */
|
|
696
|
-
/* @__PURE__ */
|
|
836
|
+
) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "\u2014" }) }),
|
|
837
|
+
/* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Badge, { tone, children: label }) }),
|
|
838
|
+
/* @__PURE__ */ jsx9(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ jsxs5(Stack, { space: 1, children: [
|
|
839
|
+
/* @__PURE__ */ jsx9(Text, { size: 1, children: branch }),
|
|
697
840
|
sha && /* @__PURE__ */ jsxs5(Text, { size: 0, muted: true, children: [
|
|
698
841
|
sha,
|
|
699
842
|
message ? ` \xB7 ${message.slice(0, 40)}${message.length > 40 ? "\u2026" : ""}` : ""
|
|
700
843
|
] })
|
|
701
844
|
] }) }),
|
|
702
|
-
/* @__PURE__ */
|
|
703
|
-
/* @__PURE__ */
|
|
845
|
+
/* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: timeAgo(d.created) }) }),
|
|
846
|
+
/* @__PURE__ */ jsx9(Box, { style: { width: 64 }, children: safeHref(d.inspectorUrl) ? /* @__PURE__ */ jsx9(
|
|
704
847
|
Button,
|
|
705
848
|
{
|
|
706
849
|
as: "a",
|
|
@@ -713,7 +856,7 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
713
856
|
icon: LaunchIcon,
|
|
714
857
|
style: { fontSize: "12px" }
|
|
715
858
|
}
|
|
716
|
-
) : /* @__PURE__ */
|
|
859
|
+
) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "\u2014" }) })
|
|
717
860
|
] }) }, d.uid);
|
|
718
861
|
})
|
|
719
862
|
] })
|
|
@@ -723,13 +866,17 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
723
866
|
}
|
|
724
867
|
|
|
725
868
|
// src/components/DeployItem.tsx
|
|
726
|
-
import { Fragment, jsx as
|
|
869
|
+
import { Fragment, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
727
870
|
var POLL_INTERVAL_MS = 5e3;
|
|
728
871
|
var LABEL_WIDTH = 64;
|
|
729
872
|
var PENDING_TIMEOUT_MS = 6e4;
|
|
730
873
|
function DeployItem({ target, token, onDelete, onEdit }) {
|
|
731
874
|
const { projectId, hookId } = parseHookUrl(target.url);
|
|
732
875
|
const toast = useToast();
|
|
876
|
+
const pluginConfig = usePluginConfig();
|
|
877
|
+
const client = useClient({ apiVersion: "2025-01-01" });
|
|
878
|
+
const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
|
|
879
|
+
const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
|
|
733
880
|
const [deployments, setDeployments] = useState5([]);
|
|
734
881
|
const [loadingInitial, setLoadingInitial] = useState5(true);
|
|
735
882
|
const [pendingSince, setPendingSince] = useState5(null);
|
|
@@ -747,17 +894,21 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
747
894
|
const triggeredFromUidRef = useRef2(void 0);
|
|
748
895
|
const requestSeqRef = useRef2(0);
|
|
749
896
|
const mountedRef = useRef2(true);
|
|
750
|
-
useEffect4(() =>
|
|
751
|
-
mountedRef.current =
|
|
897
|
+
useEffect4(() => {
|
|
898
|
+
mountedRef.current = true;
|
|
899
|
+
return () => {
|
|
900
|
+
mountedRef.current = false;
|
|
901
|
+
};
|
|
752
902
|
}, []);
|
|
753
903
|
const latest = deployments[0];
|
|
754
904
|
const isPending = pendingSince !== null;
|
|
755
905
|
const isActive = isPending || isActiveState(latest?.state);
|
|
756
|
-
const
|
|
757
|
-
|
|
906
|
+
const fetchDeployments2 = useCallback4(async () => {
|
|
907
|
+
const ready = transport.mode === "proxy" ? Boolean(target.proxyKey && pluginConfig.proxyUrl) : Boolean(projectId && hookId && token);
|
|
908
|
+
if (!ready) return;
|
|
758
909
|
const seq = ++requestSeqRef.current;
|
|
759
910
|
try {
|
|
760
|
-
const data = await
|
|
911
|
+
const data = await fetchDeployments(transport, targetRef);
|
|
761
912
|
if (seq !== requestSeqRef.current || !mountedRef.current) return;
|
|
762
913
|
setDeployments(data);
|
|
763
914
|
setPollError(null);
|
|
@@ -766,15 +917,15 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
766
917
|
setPollError(err instanceof Error ? err.message : "Could not reach the Vercel API");
|
|
767
918
|
console.error("Deploy-vercel-from-sanity: fetch error", err);
|
|
768
919
|
}
|
|
769
|
-
}, [projectId, hookId, token, target.teamId]);
|
|
920
|
+
}, [projectId, hookId, token, target.teamId, target.proxyKey, transport.mode, pluginConfig.proxyUrl]);
|
|
770
921
|
useEffect4(() => {
|
|
771
|
-
|
|
772
|
-
}, [
|
|
922
|
+
fetchDeployments2().finally(() => setLoadingInitial(false));
|
|
923
|
+
}, [fetchDeployments2]);
|
|
773
924
|
useEffect4(() => {
|
|
774
925
|
if (!isActive) return;
|
|
775
|
-
const id = setInterval(
|
|
926
|
+
const id = setInterval(fetchDeployments2, POLL_INTERVAL_MS);
|
|
776
927
|
return () => clearInterval(id);
|
|
777
|
-
}, [isActive,
|
|
928
|
+
}, [isActive, fetchDeployments2]);
|
|
778
929
|
useEffect4(() => {
|
|
779
930
|
if (!isPending) return;
|
|
780
931
|
if (latest?.uid && latest.uid !== triggeredFromUidRef.current) setPendingSince(null);
|
|
@@ -828,26 +979,36 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
828
979
|
});
|
|
829
980
|
void (async () => {
|
|
830
981
|
try {
|
|
831
|
-
|
|
832
|
-
|
|
982
|
+
if (pluginConfig.mode === "proxy") {
|
|
983
|
+
if (!target.proxyKey) throw new Error("Target has no proxy key \u2014 set one on the deploy target");
|
|
984
|
+
await client.create({
|
|
985
|
+
_type: "vercelDeploy.request",
|
|
986
|
+
target: { _type: "reference", _ref: target._id },
|
|
987
|
+
proxyKey: target.proxyKey,
|
|
988
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
989
|
+
});
|
|
990
|
+
} else {
|
|
991
|
+
await triggerDeploy(target.url ?? "");
|
|
992
|
+
}
|
|
993
|
+
setTimeout(fetchDeployments2, 2e3);
|
|
833
994
|
} catch (err) {
|
|
834
995
|
setPendingSince(null);
|
|
835
996
|
setDeployError(err instanceof Error ? err.message : "Deploy failed");
|
|
836
997
|
}
|
|
837
998
|
})();
|
|
838
|
-
}, [target.url,
|
|
999
|
+
}, [target.url, target.proxyKey, target._id, pluginConfig.mode, client, fetchDeployments2, latest?.uid]);
|
|
839
1000
|
const cancel = useCallback4(async () => {
|
|
840
1001
|
if (!latest?.uid) return;
|
|
841
1002
|
setCanceling(true);
|
|
842
1003
|
try {
|
|
843
|
-
await
|
|
844
|
-
await
|
|
1004
|
+
await cancelDeploy(transport, targetRef, latest.uid);
|
|
1005
|
+
await fetchDeployments2();
|
|
845
1006
|
} catch (err) {
|
|
846
1007
|
console.error("deploy-vercel-from-sanity: cancel error", err);
|
|
847
1008
|
} finally {
|
|
848
1009
|
setCanceling(false);
|
|
849
1010
|
}
|
|
850
|
-
}, [latest?.uid, token, target.teamId,
|
|
1011
|
+
}, [latest?.uid, token, target.teamId, fetchDeployments2]);
|
|
851
1012
|
const copyUrl = useCallback4(() => {
|
|
852
1013
|
if (!latest?.url) return;
|
|
853
1014
|
const fullUrl = deploymentHref(latest.url) ?? "";
|
|
@@ -863,11 +1024,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
863
1024
|
setLoadingLogs(true);
|
|
864
1025
|
setLogError(null);
|
|
865
1026
|
try {
|
|
866
|
-
const events = await
|
|
867
|
-
deploymentId: latest.uid,
|
|
868
|
-
token,
|
|
869
|
-
teamId: target.teamId
|
|
870
|
-
});
|
|
1027
|
+
const events = await fetchDeploymentEvents(transport, targetRef, latest.uid);
|
|
871
1028
|
const lines = events.filter((e) => e.type === "stderr" || e.type === "stdout").map((e) => e.text ?? "").filter(Boolean).reverse().slice(-30);
|
|
872
1029
|
setErrorLines(lines.length > 0 ? lines : ["No stderr or stdout was captured for this build. Open the full build log in Vercel for details."]);
|
|
873
1030
|
} catch (err) {
|
|
@@ -890,19 +1047,19 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
890
1047
|
const vercelProjectUrl = projectHref(latest?.inspectorUrl);
|
|
891
1048
|
const isError = latest?.state === "ERROR";
|
|
892
1049
|
return /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
893
|
-
/* @__PURE__ */
|
|
1050
|
+
/* @__PURE__ */ jsx10(Card, { radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs6(Flex, { align: "stretch", className: "dvfs-card-flex", children: [
|
|
894
1051
|
/* @__PURE__ */ jsxs6(Flex, { direction: "column", flex: 1, style: { minWidth: 0 }, children: [
|
|
895
1052
|
/* @__PURE__ */ jsxs6(Stack, { space: 3, padding: 3, style: { flex: 1 }, children: [
|
|
896
1053
|
/* @__PURE__ */ jsxs6(Flex, { align: "center", justify: "space-between", gap: 2, children: [
|
|
897
1054
|
/* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, style: { minWidth: 0, flexWrap: "wrap" }, children: [
|
|
898
|
-
/* @__PURE__ */
|
|
899
|
-
branch && /* @__PURE__ */
|
|
1055
|
+
/* @__PURE__ */ jsx10(Text, { size: 2, weight: "semibold", style: { flexShrink: 0 }, children: target.name }),
|
|
1056
|
+
branch && /* @__PURE__ */ jsx10(Badge, { tone: "default", padding: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
|
|
900
1057
|
branch,
|
|
901
|
-
/* @__PURE__ */
|
|
1058
|
+
/* @__PURE__ */ jsx10("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", style: { marginLeft: "-0.1em", opacity: 0.5 }, children: /* @__PURE__ */ jsx10("path", { d: "M5 3.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm0 2.122a2.25 2.25 0 1 0-1.5 0v.878A2.25 2.25 0 0 0 5.75 8.5h1.5v2.128a2.251 2.251 0 1 0 1.5 0V8.5h1.5a2.25 2.25 0 0 0 2.25-2.25v-.878a2.25 2.25 0 1 0-1.5 0v.878a.75.75 0 0 1-.75.75h-4.5A.75.75 0 0 1 5 6.25v-.878zm3.75 7.378a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm3-8.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0z" }) })
|
|
902
1059
|
] }) }),
|
|
903
1060
|
token && !loadingInitial && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
904
|
-
isPending ? /* @__PURE__ */
|
|
905
|
-
isActiveState(latest?.state) && /* @__PURE__ */
|
|
1061
|
+
isPending ? /* @__PURE__ */ jsx10(StatusBadge, { state: "QUEUED" }) : /* @__PURE__ */ jsx10(StatusBadge, { state: latest?.state }),
|
|
1062
|
+
isActiveState(latest?.state) && /* @__PURE__ */ jsx10(
|
|
906
1063
|
Button,
|
|
907
1064
|
{
|
|
908
1065
|
text: "Cancel",
|
|
@@ -916,14 +1073,14 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
916
1073
|
),
|
|
917
1074
|
isPending ? (
|
|
918
1075
|
/* Optimistic — dimmed spinner only; no elapsed time until a real build exists */
|
|
919
|
-
/* @__PURE__ */
|
|
1076
|
+
/* @__PURE__ */ jsx10(Spinner, { muted: true, style: { marginLeft: 4, opacity: 0.5 } })
|
|
920
1077
|
) : isActive ? /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
|
|
921
|
-
/* @__PURE__ */
|
|
922
|
-
/* @__PURE__ */
|
|
923
|
-
] }) : deployedAt ? /* @__PURE__ */
|
|
1078
|
+
/* @__PURE__ */ jsx10(Spinner, { muted: true, style: { marginLeft: 4 } }),
|
|
1079
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: formatDuration(elapsed) })
|
|
1080
|
+
] }) : deployedAt ? /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: deployedAt }) : null
|
|
924
1081
|
] })
|
|
925
1082
|
] }),
|
|
926
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsx10(
|
|
927
1084
|
ActionMenu,
|
|
928
1085
|
{
|
|
929
1086
|
id: `menu-${target._id}`,
|
|
@@ -939,32 +1096,32 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
939
1096
|
}
|
|
940
1097
|
)
|
|
941
1098
|
] }),
|
|
942
|
-
/* @__PURE__ */
|
|
943
|
-
!token ? /* @__PURE__ */
|
|
944
|
-
/* @__PURE__ */
|
|
945
|
-
/* @__PURE__ */
|
|
1099
|
+
/* @__PURE__ */ jsx10("hr", { style: { border: "none", borderTop: "1px solid currentColor", opacity: 0.1, margin: 0 } }),
|
|
1100
|
+
!token ? /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: pluginConfig.mode === "proxy" ? target.proxyKey ? "Waiting for status from the deploy proxy." : "Set a Proxy Key on this target to see deployment status." : "Connect a Vercel API token to see deployment status." }) : loadingInitial ? /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
|
|
1101
|
+
/* @__PURE__ */ jsx10(Spinner, { muted: true }),
|
|
1102
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: "Loading\u2026" })
|
|
946
1103
|
] }) : /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
|
|
947
1104
|
/* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
|
|
948
|
-
latest?.url && latest.state === "READY" && /* @__PURE__ */
|
|
1105
|
+
latest?.url && latest.state === "READY" && /* @__PURE__ */ jsx10(Fragment, { children: /* @__PURE__ */ jsx10(
|
|
949
1106
|
"a",
|
|
950
1107
|
{
|
|
951
1108
|
href: deploymentHref(latest.url),
|
|
952
1109
|
target: "_blank",
|
|
953
1110
|
rel: "noreferrer",
|
|
954
1111
|
style: { color: "inherit" },
|
|
955
|
-
children: /* @__PURE__ */
|
|
1112
|
+
children: /* @__PURE__ */ jsx10(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx10(Text, { size: 1, children: latest.url }) })
|
|
956
1113
|
}
|
|
957
1114
|
) }),
|
|
958
|
-
sha && /* @__PURE__ */
|
|
1115
|
+
sha && /* @__PURE__ */ jsx10(Tooltip, { text: commitMsg ?? sha, children: commitHref ? /* @__PURE__ */ jsx10(
|
|
959
1116
|
"a",
|
|
960
1117
|
{
|
|
961
1118
|
href: commitHref,
|
|
962
1119
|
target: "_blank",
|
|
963
1120
|
rel: "noreferrer",
|
|
964
1121
|
style: { color: "inherit", textDecoration: "none" },
|
|
965
|
-
children: /* @__PURE__ */
|
|
1122
|
+
children: /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, style: { cursor: "pointer", fontFamily: "monospace" }, children: sha })
|
|
966
1123
|
}
|
|
967
|
-
) : /* @__PURE__ */
|
|
1124
|
+
) : /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, style: { cursor: "default", fontFamily: "monospace" }, children: sha }) }),
|
|
968
1125
|
creator && /* @__PURE__ */ jsxs6(Text, { size: 1, muted: true, children: [
|
|
969
1126
|
"by ",
|
|
970
1127
|
creator
|
|
@@ -974,20 +1131,39 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
974
1131
|
formatDuration(Math.floor((latest.ready - latest.created) / 1e3)),
|
|
975
1132
|
" to build"
|
|
976
1133
|
] }),
|
|
977
|
-
latest?.url && latest.state === "READY" && /* @__PURE__ */
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1134
|
+
latest?.url && latest.state === "READY" && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1135
|
+
/* @__PURE__ */ jsx10(Tooltip, { text: copied ? "Copied" : "Copy deployment URL", children: /* @__PURE__ */ jsx10(
|
|
1136
|
+
Button,
|
|
1137
|
+
{
|
|
1138
|
+
mode: "ghost",
|
|
1139
|
+
icon: copied ? CheckmarkIcon : CopyIcon,
|
|
1140
|
+
padding: 1,
|
|
1141
|
+
tone: copied ? "positive" : "default",
|
|
1142
|
+
onClick: copyUrl,
|
|
1143
|
+
"aria-label": copied ? "Deployment URL copied" : "Copy deployment URL",
|
|
1144
|
+
style: { cursor: "pointer" }
|
|
1145
|
+
}
|
|
1146
|
+
) }),
|
|
1147
|
+
/* @__PURE__ */ jsx10(
|
|
1148
|
+
"span",
|
|
1149
|
+
{
|
|
1150
|
+
role: "status",
|
|
1151
|
+
"aria-live": "polite",
|
|
1152
|
+
style: {
|
|
1153
|
+
position: "absolute",
|
|
1154
|
+
width: 1,
|
|
1155
|
+
height: 1,
|
|
1156
|
+
overflow: "hidden",
|
|
1157
|
+
clip: "rect(0 0 0 0)",
|
|
1158
|
+
whiteSpace: "nowrap"
|
|
1159
|
+
},
|
|
1160
|
+
children: copied ? "Deployment URL copied to clipboard" : ""
|
|
1161
|
+
}
|
|
1162
|
+
)
|
|
1163
|
+
] })
|
|
988
1164
|
] }),
|
|
989
1165
|
/* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
|
|
990
|
-
commitMsg && /* @__PURE__ */
|
|
1166
|
+
commitMsg && /* @__PURE__ */ jsx10(
|
|
991
1167
|
Text,
|
|
992
1168
|
{
|
|
993
1169
|
size: 0,
|
|
@@ -997,7 +1173,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
997
1173
|
}
|
|
998
1174
|
),
|
|
999
1175
|
isError && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
|
|
1000
|
-
/* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ jsx10(
|
|
1001
1177
|
Button,
|
|
1002
1178
|
{
|
|
1003
1179
|
"aria-expanded": showErrorLogs,
|
|
@@ -1013,30 +1189,30 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1013
1189
|
),
|
|
1014
1190
|
showErrorLogs && /* @__PURE__ */ jsxs6(Card, { tone: "critical", radius: 2, padding: 3, children: [
|
|
1015
1191
|
loadingLogs && /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
|
|
1016
|
-
/* @__PURE__ */
|
|
1017
|
-
/* @__PURE__ */
|
|
1192
|
+
/* @__PURE__ */ jsx10(Spinner, { muted: true }),
|
|
1193
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: "Loading logs\u2026" })
|
|
1018
1194
|
] }),
|
|
1019
1195
|
logError && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
|
|
1020
|
-
/* @__PURE__ */
|
|
1021
|
-
safeHref(latest?.inspectorUrl) && /* @__PURE__ */
|
|
1022
|
-
/* @__PURE__ */
|
|
1023
|
-
/* @__PURE__ */
|
|
1196
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, children: logError }),
|
|
1197
|
+
safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
|
|
1198
|
+
/* @__PURE__ */ jsx10(LaunchIcon, {}),
|
|
1199
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, children: "View full logs in Vercel" })
|
|
1024
1200
|
] }) })
|
|
1025
1201
|
] }),
|
|
1026
1202
|
!loadingLogs && !logError && errorLines.length > 0 && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
|
|
1027
|
-
/* @__PURE__ */
|
|
1028
|
-
safeHref(latest?.inspectorUrl) && /* @__PURE__ */
|
|
1029
|
-
/* @__PURE__ */
|
|
1030
|
-
/* @__PURE__ */
|
|
1203
|
+
/* @__PURE__ */ jsx10(Box, { style: { maxHeight: 240, overflowY: "auto", fontFamily: "monospace", fontSize: 13, lineHeight: 1.6 }, children: errorLines.map((line, i) => /* @__PURE__ */ jsx10(Code, { style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: line }, i)) }),
|
|
1204
|
+
safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
|
|
1205
|
+
/* @__PURE__ */ jsx10(LaunchIcon, {}),
|
|
1206
|
+
/* @__PURE__ */ jsx10(Text, { size: 1, children: "View full logs in Vercel" })
|
|
1031
1207
|
] }) })
|
|
1032
1208
|
] })
|
|
1033
1209
|
] })
|
|
1034
1210
|
] }),
|
|
1035
|
-
deployError && /* @__PURE__ */
|
|
1211
|
+
deployError && /* @__PURE__ */ jsx10(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsx10(Text, { size: 1, children: deployError }) })
|
|
1036
1212
|
] })
|
|
1037
1213
|
] }),
|
|
1038
|
-
pollError && /* @__PURE__ */
|
|
1039
|
-
/* @__PURE__ */
|
|
1214
|
+
pollError && /* @__PURE__ */ jsx10(Card, { tone: "caution", padding: 3, radius: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
|
|
1215
|
+
/* @__PURE__ */ jsx10(WarningOutlineIcon, { "aria-hidden": "true" }),
|
|
1040
1216
|
/* @__PURE__ */ jsxs6(Text, { size: 1, children: [
|
|
1041
1217
|
"Status updates paused \u2014 ",
|
|
1042
1218
|
pollError
|
|
@@ -1044,7 +1220,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1044
1220
|
] }) })
|
|
1045
1221
|
] }),
|
|
1046
1222
|
/* @__PURE__ */ jsxs6(Box, { children: [
|
|
1047
|
-
/* @__PURE__ */
|
|
1223
|
+
/* @__PURE__ */ jsx10(
|
|
1048
1224
|
Button,
|
|
1049
1225
|
{
|
|
1050
1226
|
mode: "ghost",
|
|
@@ -1057,61 +1233,61 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1057
1233
|
style: { width: "100%", justifyContent: "flex-start", borderRadius: 0, cursor: "pointer" }
|
|
1058
1234
|
}
|
|
1059
1235
|
),
|
|
1060
|
-
showDetails && /* @__PURE__ */
|
|
1236
|
+
showDetails && /* @__PURE__ */ jsx10(Card, { tone: "primary", padding: 3, className: "dvfs-accordion-content", style: { borderRadius: 0, borderTop: "1px solid rgba(128,128,128,0.15)" }, children: /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
|
|
1061
1237
|
/* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1062
|
-
/* @__PURE__ */
|
|
1063
|
-
/* @__PURE__ */
|
|
1238
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Project" }),
|
|
1239
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: projectId || "\u2014" })
|
|
1064
1240
|
] }),
|
|
1065
1241
|
/* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1066
|
-
/* @__PURE__ */
|
|
1067
|
-
/* @__PURE__ */
|
|
1242
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Hook" }),
|
|
1243
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: hookId || "\u2014" })
|
|
1068
1244
|
] }),
|
|
1069
1245
|
target.teamId && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
/* @__PURE__ */
|
|
1246
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Team" }),
|
|
1247
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: target.teamId })
|
|
1072
1248
|
] }),
|
|
1073
1249
|
fullSha && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "flex-start", children: [
|
|
1074
|
-
/* @__PURE__ */
|
|
1075
|
-
/* @__PURE__ */
|
|
1250
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Commit" }),
|
|
1251
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: fullSha })
|
|
1076
1252
|
] }),
|
|
1077
1253
|
latest?.meta?.githubCommitAuthorName && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1078
|
-
/* @__PURE__ */
|
|
1079
|
-
/* @__PURE__ */
|
|
1254
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Author" }),
|
|
1255
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, children: latest.meta.githubCommitAuthorName })
|
|
1080
1256
|
] }),
|
|
1081
1257
|
branch && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1082
|
-
/* @__PURE__ */
|
|
1083
|
-
/* @__PURE__ */
|
|
1258
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Branch" }),
|
|
1259
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: branch })
|
|
1084
1260
|
] }),
|
|
1085
1261
|
latest?.uid && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1086
|
-
/* @__PURE__ */
|
|
1087
|
-
/* @__PURE__ */
|
|
1262
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Deploy ID" }),
|
|
1263
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: latest.uid })
|
|
1088
1264
|
] }),
|
|
1089
1265
|
latest?.url && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "flex-start", children: [
|
|
1090
|
-
/* @__PURE__ */
|
|
1091
|
-
/* @__PURE__ */
|
|
1266
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "URL" }),
|
|
1267
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: latest.url })
|
|
1092
1268
|
] }),
|
|
1093
1269
|
safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
1096
|
-
/* @__PURE__ */
|
|
1097
|
-
/* @__PURE__ */
|
|
1270
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Inspector" }),
|
|
1271
|
+
/* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
|
|
1272
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: "Open in Vercel" }),
|
|
1273
|
+
/* @__PURE__ */ jsx10(LaunchIcon, { style: { width: 10, height: 10 } })
|
|
1098
1274
|
] }) })
|
|
1099
1275
|
] }),
|
|
1100
1276
|
latest?.created && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
|
|
1101
|
-
/* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1277
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Created" }),
|
|
1278
|
+
/* @__PURE__ */ jsx10(Text, { size: 0, muted: true, children: new Date(latest.created).toLocaleString() })
|
|
1103
1279
|
] })
|
|
1104
1280
|
] }) })
|
|
1105
1281
|
] })
|
|
1106
1282
|
] }),
|
|
1107
|
-
/* @__PURE__ */
|
|
1283
|
+
/* @__PURE__ */ jsx10(
|
|
1108
1284
|
Flex,
|
|
1109
1285
|
{
|
|
1110
1286
|
direction: "column",
|
|
1111
1287
|
gap: 2,
|
|
1112
1288
|
className: "dvfs-deploy-col",
|
|
1113
1289
|
style: { flexShrink: 0, alignSelf: "stretch" },
|
|
1114
|
-
children: /* @__PURE__ */
|
|
1290
|
+
children: /* @__PURE__ */ jsx10(
|
|
1115
1291
|
Button,
|
|
1116
1292
|
{
|
|
1117
1293
|
text: "Deploy",
|
|
@@ -1131,7 +1307,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1131
1307
|
}
|
|
1132
1308
|
)
|
|
1133
1309
|
] }) }),
|
|
1134
|
-
showHistory && /* @__PURE__ */
|
|
1310
|
+
showHistory && /* @__PURE__ */ jsx10(
|
|
1135
1311
|
DeployHistory,
|
|
1136
1312
|
{
|
|
1137
1313
|
target,
|
|
@@ -1143,16 +1319,18 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1143
1319
|
}
|
|
1144
1320
|
|
|
1145
1321
|
// src/components/TokenSetup.tsx
|
|
1146
|
-
import { useId as
|
|
1147
|
-
import { useClient } from "sanity";
|
|
1148
|
-
import { jsx as
|
|
1322
|
+
import { useId as useId4, useState as useState6, useCallback as useCallback5 } from "react";
|
|
1323
|
+
import { useClient as useClient2 } from "sanity";
|
|
1324
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1149
1325
|
var TOKEN_DOC_ID = "config.vercelDeploy";
|
|
1150
|
-
function TokenSetup({ onSaved, onCancel }) {
|
|
1151
|
-
const
|
|
1152
|
-
const
|
|
1326
|
+
function TokenSetup({ onSaved, onCancel, hasToken = false }) {
|
|
1327
|
+
const dialogId = useId4();
|
|
1328
|
+
const tokenId = useId4();
|
|
1329
|
+
const client = useClient2({ apiVersion: "2025-01-01" });
|
|
1153
1330
|
const [token, setToken] = useState6("");
|
|
1154
1331
|
const [saving, setSaving] = useState6(false);
|
|
1155
1332
|
const [error, setError] = useState6(null);
|
|
1333
|
+
const [revoking, setRevoking] = useState6(false);
|
|
1156
1334
|
const save = useCallback5(async () => {
|
|
1157
1335
|
if (!token.trim()) return;
|
|
1158
1336
|
setSaving(true);
|
|
@@ -1170,43 +1348,71 @@ function TokenSetup({ onSaved, onCancel }) {
|
|
|
1170
1348
|
setSaving(false);
|
|
1171
1349
|
}
|
|
1172
1350
|
}, [client, token, onSaved]);
|
|
1173
|
-
|
|
1351
|
+
const revoke = useCallback5(async () => {
|
|
1352
|
+
setRevoking(true);
|
|
1353
|
+
setError(null);
|
|
1354
|
+
try {
|
|
1355
|
+
await client.delete(TOKEN_DOC_ID);
|
|
1356
|
+
onSaved();
|
|
1357
|
+
} catch (err) {
|
|
1358
|
+
setError(err instanceof Error ? err.message : "Failed to remove token");
|
|
1359
|
+
} finally {
|
|
1360
|
+
setRevoking(false);
|
|
1361
|
+
}
|
|
1362
|
+
}, [client, onSaved]);
|
|
1363
|
+
return /* @__PURE__ */ jsx11(
|
|
1174
1364
|
Dialog,
|
|
1175
1365
|
{
|
|
1176
1366
|
header: "Connect Vercel API token",
|
|
1177
|
-
id:
|
|
1367
|
+
id: dialogId,
|
|
1178
1368
|
onClose: onCancel,
|
|
1179
1369
|
width: 1,
|
|
1180
|
-
footer: /* @__PURE__ */ jsxs7(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
|
|
1181
|
-
|
|
1182
|
-
/* @__PURE__ */ jsx10(
|
|
1370
|
+
footer: /* @__PURE__ */ jsxs7(Flex, { padding: 3, gap: 2, justify: hasToken ? "space-between" : "flex-end", children: [
|
|
1371
|
+
hasToken && /* @__PURE__ */ jsx11(
|
|
1183
1372
|
Button,
|
|
1184
1373
|
{
|
|
1185
|
-
text: "
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1374
|
+
text: "Remove token",
|
|
1375
|
+
mode: "ghost",
|
|
1376
|
+
tone: "critical",
|
|
1377
|
+
icon: TrashIcon,
|
|
1378
|
+
loading: revoking,
|
|
1379
|
+
disabled: revoking || saving,
|
|
1380
|
+
onClick: revoke,
|
|
1191
1381
|
style: { cursor: "pointer" }
|
|
1192
1382
|
}
|
|
1193
|
-
)
|
|
1383
|
+
),
|
|
1384
|
+
/* @__PURE__ */ jsxs7(Flex, { gap: 2, children: [
|
|
1385
|
+
onCancel && /* @__PURE__ */ jsx11(Button, { text: "Cancel", mode: "ghost", onClick: onCancel, style: { cursor: "pointer" } }),
|
|
1386
|
+
/* @__PURE__ */ jsx11(
|
|
1387
|
+
Button,
|
|
1388
|
+
{
|
|
1389
|
+
text: "Save and connect",
|
|
1390
|
+
tone: "primary",
|
|
1391
|
+
icon: CheckmarkCircleIcon,
|
|
1392
|
+
loading: saving,
|
|
1393
|
+
disabled: !token.trim() || saving,
|
|
1394
|
+
onClick: save,
|
|
1395
|
+
style: { cursor: "pointer" }
|
|
1396
|
+
}
|
|
1397
|
+
)
|
|
1398
|
+
] })
|
|
1194
1399
|
] }),
|
|
1195
1400
|
children: /* @__PURE__ */ jsxs7(Stack, { space: 4, padding: 4, children: [
|
|
1196
1401
|
/* @__PURE__ */ jsxs7(Stack, { space: 3, children: [
|
|
1197
|
-
/* @__PURE__ */
|
|
1402
|
+
/* @__PURE__ */ jsx11(Text, { size: 1, muted: true, children: "A Vercel API token lets this tool read deployment status, history, build logs, and branch metadata. Without it you can still trigger deploys \u2014 you just won't see any feedback." }),
|
|
1198
1403
|
/* @__PURE__ */ jsxs7(Text, { size: 1, muted: true, children: [
|
|
1199
1404
|
"Create one at ",
|
|
1200
|
-
/* @__PURE__ */
|
|
1405
|
+
/* @__PURE__ */ jsx11("strong", { children: "vercel.com \u2192 Settings \u2192 Tokens" }),
|
|
1201
1406
|
" with",
|
|
1202
1407
|
" ",
|
|
1203
|
-
|
|
1204
|
-
|
|
1408
|
+
"scope limited to the ",
|
|
1409
|
+
/* @__PURE__ */ jsx11("strong", { children: "team" }),
|
|
1410
|
+
" that owns your projects. The token is stored in cleartext in your Sanity dataset \u2014 readable by anyone who can read the dataset, including unauthenticated readers if it is public and shared across all authenticated studio users."
|
|
1205
1411
|
] })
|
|
1206
1412
|
] }),
|
|
1207
1413
|
/* @__PURE__ */ jsxs7(Stack, { space: 2, children: [
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
/* @__PURE__ */
|
|
1414
|
+
/* @__PURE__ */ jsx11(Label, { as: "label", size: 1, htmlFor: tokenId, children: "Vercel API Token" }),
|
|
1415
|
+
/* @__PURE__ */ jsx11(
|
|
1210
1416
|
TextInput,
|
|
1211
1417
|
{
|
|
1212
1418
|
id: tokenId,
|
|
@@ -1217,35 +1423,40 @@ function TokenSetup({ onSaved, onCancel }) {
|
|
|
1217
1423
|
}
|
|
1218
1424
|
)
|
|
1219
1425
|
] }),
|
|
1220
|
-
error && /* @__PURE__ */
|
|
1426
|
+
error && /* @__PURE__ */ jsx11(Card, { tone: "critical", padding: 3, radius: 2, role: "alert", children: /* @__PURE__ */ jsx11(Text, { size: 1, children: error }) })
|
|
1221
1427
|
] })
|
|
1222
1428
|
}
|
|
1223
1429
|
);
|
|
1224
1430
|
}
|
|
1225
1431
|
|
|
1226
1432
|
// src/components/DeployTargetForm.tsx
|
|
1227
|
-
import { useId as
|
|
1228
|
-
import { useClient as
|
|
1229
|
-
import { jsx as
|
|
1433
|
+
import { useId as useId5, useState as useState7, useCallback as useCallback6 } from "react";
|
|
1434
|
+
import { useClient as useClient3 } from "sanity";
|
|
1435
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1230
1436
|
var VERCEL_HOOK_RE2 = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\//;
|
|
1231
1437
|
function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
1232
|
-
const client =
|
|
1438
|
+
const client = useClient3({ apiVersion: "2025-01-01" });
|
|
1233
1439
|
const isEdit = Boolean(initial);
|
|
1234
|
-
const
|
|
1235
|
-
const
|
|
1236
|
-
const
|
|
1237
|
-
const
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1440
|
+
const pluginConfig = usePluginConfig();
|
|
1441
|
+
const proxyKeyId = useId5();
|
|
1442
|
+
const dialogId = useId5();
|
|
1443
|
+
const nameId = useId5();
|
|
1444
|
+
const urlId = useId5();
|
|
1445
|
+
const urlErrorId = useId5();
|
|
1446
|
+
const urlHelpId = useId5();
|
|
1447
|
+
const teamId_ = useId5();
|
|
1448
|
+
const teamHelpId = useId5();
|
|
1449
|
+
const disableId = useId5();
|
|
1241
1450
|
const [name, setName] = useState7(initial?.name ?? "");
|
|
1242
1451
|
const [url, setUrl] = useState7(initial?.url ?? "");
|
|
1243
1452
|
const [teamId, setTeamId] = useState7(initial?.teamId ?? "");
|
|
1453
|
+
const [proxyKey, setProxyKey] = useState7(initial?.proxyKey ?? "");
|
|
1244
1454
|
const [disableDelete, setDisableDelete] = useState7(initial?.disableDeleteAction ?? false);
|
|
1245
1455
|
const [saving, setSaving] = useState7(false);
|
|
1246
1456
|
const [error, setError] = useState7(null);
|
|
1247
1457
|
const urlValid = !url || VERCEL_HOOK_RE2.test(url.trim());
|
|
1248
|
-
const
|
|
1458
|
+
const isProxy = pluginConfig.mode === "proxy";
|
|
1459
|
+
const canSave = Boolean(name.trim()) && urlValid && (isProxy ? Boolean(proxyKey.trim()) : Boolean(url.trim()));
|
|
1249
1460
|
const save = useCallback6(async () => {
|
|
1250
1461
|
if (!canSave) return;
|
|
1251
1462
|
setSaving(true);
|
|
@@ -1254,6 +1465,7 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1254
1465
|
name: name.trim(),
|
|
1255
1466
|
url: url.trim(),
|
|
1256
1467
|
teamId: teamId.trim() || null,
|
|
1468
|
+
proxyKey: proxyKey.trim() || null,
|
|
1257
1469
|
disableDeleteAction: disableDelete
|
|
1258
1470
|
};
|
|
1259
1471
|
try {
|
|
@@ -1268,17 +1480,17 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1268
1480
|
} finally {
|
|
1269
1481
|
setSaving(false);
|
|
1270
1482
|
}
|
|
1271
|
-
}, [canSave, isEdit, initial, client, name, url, teamId, disableDelete, onSaved]);
|
|
1272
|
-
return /* @__PURE__ */
|
|
1483
|
+
}, [canSave, isEdit, initial, client, name, url, teamId, proxyKey, disableDelete, onSaved]);
|
|
1484
|
+
return /* @__PURE__ */ jsx12(
|
|
1273
1485
|
Dialog,
|
|
1274
1486
|
{
|
|
1275
1487
|
header: isEdit ? `Edit "${initial?.name}"` : "Add deploy target",
|
|
1276
|
-
id:
|
|
1488
|
+
id: dialogId,
|
|
1277
1489
|
onClose,
|
|
1278
1490
|
width: 1,
|
|
1279
1491
|
footer: /* @__PURE__ */ jsxs8(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
|
|
1280
|
-
/* @__PURE__ */
|
|
1281
|
-
/* @__PURE__ */
|
|
1492
|
+
/* @__PURE__ */ jsx12(Button, { text: "Cancel", mode: "ghost", onClick: onClose, style: { cursor: "pointer" } }),
|
|
1493
|
+
/* @__PURE__ */ jsx12(
|
|
1282
1494
|
Button,
|
|
1283
1495
|
{
|
|
1284
1496
|
text: isEdit ? "Save changes" : "Add target",
|
|
@@ -1291,13 +1503,13 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1291
1503
|
}
|
|
1292
1504
|
)
|
|
1293
1505
|
] }),
|
|
1294
|
-
children: /* @__PURE__ */
|
|
1506
|
+
children: /* @__PURE__ */ jsx12(Box, { padding: 4, children: /* @__PURE__ */ jsxs8(Stack, { space: 4, children: [
|
|
1295
1507
|
/* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
|
|
1296
1508
|
/* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: nameId, children: [
|
|
1297
1509
|
"Name ",
|
|
1298
|
-
/* @__PURE__ */
|
|
1510
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
|
|
1299
1511
|
] }),
|
|
1300
|
-
/* @__PURE__ */
|
|
1512
|
+
/* @__PURE__ */ jsx12(
|
|
1301
1513
|
TextInput,
|
|
1302
1514
|
{
|
|
1303
1515
|
id: nameId,
|
|
@@ -1309,12 +1521,29 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1309
1521
|
}
|
|
1310
1522
|
)
|
|
1311
1523
|
] }),
|
|
1312
|
-
/* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
|
|
1524
|
+
isProxy ? /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
|
|
1525
|
+
/* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: proxyKeyId, children: [
|
|
1526
|
+
"Proxy Key ",
|
|
1527
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
|
|
1528
|
+
] }),
|
|
1529
|
+
/* @__PURE__ */ jsx12(
|
|
1530
|
+
TextInput,
|
|
1531
|
+
{
|
|
1532
|
+
id: proxyKeyId,
|
|
1533
|
+
required: true,
|
|
1534
|
+
"aria-required": "true",
|
|
1535
|
+
value: proxyKey,
|
|
1536
|
+
onChange: (e) => setProxyKey(e.target.value),
|
|
1537
|
+
placeholder: "production"
|
|
1538
|
+
}
|
|
1539
|
+
),
|
|
1540
|
+
/* @__PURE__ */ jsx12(Text, { size: 0, muted: true, children: "Matches a key configured on your deploy proxy, which holds the real hook URL. Contains no secret." })
|
|
1541
|
+
] }) : /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
|
|
1313
1542
|
/* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: urlId, children: [
|
|
1314
1543
|
"Deploy hook URL ",
|
|
1315
|
-
/* @__PURE__ */
|
|
1544
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
|
|
1316
1545
|
] }),
|
|
1317
|
-
/* @__PURE__ */
|
|
1546
|
+
/* @__PURE__ */ jsx12(
|
|
1318
1547
|
TextInput,
|
|
1319
1548
|
{
|
|
1320
1549
|
id: urlId,
|
|
@@ -1327,15 +1556,15 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1327
1556
|
placeholder: "https://api.vercel.com/v1/integrations/deploy/\u2026"
|
|
1328
1557
|
}
|
|
1329
1558
|
),
|
|
1330
|
-
url && !urlValid && /* @__PURE__ */
|
|
1331
|
-
/* @__PURE__ */
|
|
1559
|
+
url && !urlValid && /* @__PURE__ */ jsx12(Card, { tone: "critical", padding: 2, radius: 2, role: "alert", children: /* @__PURE__ */ jsx12(Text, { id: urlErrorId, size: 1, children: "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)" }) }),
|
|
1560
|
+
/* @__PURE__ */ jsx12(Text, { id: urlHelpId, size: 0, muted: true, children: "Vercel dashboard \u2192 Project \u2192 Settings \u2192 Git \u2192 Deploy Hooks" })
|
|
1332
1561
|
] }),
|
|
1333
1562
|
/* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
|
|
1334
1563
|
/* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: teamId_, children: [
|
|
1335
1564
|
"Team ID ",
|
|
1336
|
-
/* @__PURE__ */
|
|
1565
|
+
/* @__PURE__ */ jsx12("span", { style: { opacity: 0.5, fontWeight: "normal" }, children: "\u2014 optional" })
|
|
1337
1566
|
] }),
|
|
1338
|
-
/* @__PURE__ */
|
|
1567
|
+
/* @__PURE__ */ jsx12(
|
|
1339
1568
|
TextInput,
|
|
1340
1569
|
{
|
|
1341
1570
|
id: teamId_,
|
|
@@ -1345,14 +1574,10 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1345
1574
|
placeholder: "team_xxxxxxxx"
|
|
1346
1575
|
}
|
|
1347
1576
|
),
|
|
1348
|
-
/* @__PURE__ */
|
|
1349
|
-
"Required for team-owned Vercel projects. Find it at Vercel \u2192 Settings \u2192 General \u2192 Team ID (starts with ",
|
|
1350
|
-
/* @__PURE__ */ jsx11("code", { children: "team_" }),
|
|
1351
|
-
")."
|
|
1352
|
-
] })
|
|
1577
|
+
/* @__PURE__ */ jsx12(Text, { id: teamHelpId, size: 0, muted: true, children: isProxy ? "Not used in proxy mode \u2014 the proxy supplies the team from its own configuration." : "Required for team-owned Vercel projects. Find it at Vercel \u2192 Settings \u2192 General \u2192 Team ID (starts with team_)." })
|
|
1353
1578
|
] }),
|
|
1354
1579
|
/* @__PURE__ */ jsxs8(Flex, { align: "center", gap: 3, children: [
|
|
1355
|
-
/* @__PURE__ */
|
|
1580
|
+
/* @__PURE__ */ jsx12(
|
|
1356
1581
|
Switch,
|
|
1357
1582
|
{
|
|
1358
1583
|
checked: disableDelete,
|
|
@@ -1361,25 +1586,27 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1361
1586
|
}
|
|
1362
1587
|
),
|
|
1363
1588
|
/* @__PURE__ */ jsxs8(Stack, { space: 1, children: [
|
|
1364
|
-
/* @__PURE__ */
|
|
1365
|
-
/* @__PURE__ */
|
|
1589
|
+
/* @__PURE__ */ jsx12(Label, { as: "label", size: 1, htmlFor: disableId, children: "Disable delete action" }),
|
|
1590
|
+
/* @__PURE__ */ jsx12(Text, { size: 0, muted: true, children: "Hides the delete button for this target in the studio." })
|
|
1366
1591
|
] })
|
|
1367
1592
|
] }),
|
|
1368
|
-
error && /* @__PURE__ */
|
|
1593
|
+
error && /* @__PURE__ */ jsx12(Card, { tone: "critical", padding: 3, radius: 2, children: /* @__PURE__ */ jsx12(Text, { size: 1, children: error }) })
|
|
1369
1594
|
] }) })
|
|
1370
1595
|
}
|
|
1371
1596
|
);
|
|
1372
1597
|
}
|
|
1373
1598
|
|
|
1374
1599
|
// src/version.ts
|
|
1375
|
-
var VERSION = "1.
|
|
1600
|
+
var VERSION = "1.3.0";
|
|
1376
1601
|
|
|
1377
1602
|
// src/components/DeployTool.tsx
|
|
1378
|
-
import { jsx as
|
|
1603
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1379
1604
|
var TOKEN_QUERY = `*[_id == "config.vercelDeploy"][0].accessToken`;
|
|
1380
1605
|
var TARGETS_QUERY = `*[_type == "vercel_deploy" && !(_id in path("drafts.**"))] | order(_createdAt asc)`;
|
|
1381
1606
|
function DeployTool() {
|
|
1382
|
-
const client =
|
|
1607
|
+
const client = useClient4({ apiVersion: "2025-01-01" });
|
|
1608
|
+
const pluginConfig = usePluginConfig();
|
|
1609
|
+
const usesToken = pluginConfig.mode === "direct";
|
|
1383
1610
|
const toast = useToast();
|
|
1384
1611
|
const [token, setToken] = useState8(null);
|
|
1385
1612
|
const [targets, setTargets] = useState8([]);
|
|
@@ -1470,14 +1697,14 @@ function DeployTool() {
|
|
|
1470
1697
|
}
|
|
1471
1698
|
}, [client, pendingDelete, toast]);
|
|
1472
1699
|
if (loading) {
|
|
1473
|
-
return /* @__PURE__ */
|
|
1700
|
+
return /* @__PURE__ */ jsx13(Card, { height: "fill", tone: "transparent", children: /* @__PURE__ */ jsx13(Flex, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ jsx13(Spinner, { muted: true }) }) });
|
|
1474
1701
|
}
|
|
1475
1702
|
return /* @__PURE__ */ jsxs9(Card, { height: "fill", tone: "transparent", children: [
|
|
1476
|
-
/* @__PURE__ */
|
|
1703
|
+
/* @__PURE__ */ jsx13(Box, { padding: 5, children: /* @__PURE__ */ jsxs9(Stack, { space: 5, children: [
|
|
1477
1704
|
/* @__PURE__ */ jsxs9(Flex, { align: "center", justify: "space-between", className: "dvfs-header", children: [
|
|
1478
|
-
/* @__PURE__ */
|
|
1705
|
+
/* @__PURE__ */ jsx13(Heading, { size: 2, children: "Deploy with Vercel" }),
|
|
1479
1706
|
/* @__PURE__ */ jsxs9(Flex, { align: "center", gap: 3, className: "dvfs-header-actions", children: [
|
|
1480
|
-
/* @__PURE__ */
|
|
1707
|
+
usesToken && /* @__PURE__ */ jsx13(
|
|
1481
1708
|
Button,
|
|
1482
1709
|
{
|
|
1483
1710
|
text: token ? "Token connected" : "Connect API token",
|
|
@@ -1489,7 +1716,7 @@ function DeployTool() {
|
|
|
1489
1716
|
style: { cursor: "pointer" }
|
|
1490
1717
|
}
|
|
1491
1718
|
),
|
|
1492
|
-
/* @__PURE__ */
|
|
1719
|
+
/* @__PURE__ */ jsx13(
|
|
1493
1720
|
Button,
|
|
1494
1721
|
{
|
|
1495
1722
|
text: "Add target",
|
|
@@ -1502,12 +1729,12 @@ function DeployTool() {
|
|
|
1502
1729
|
)
|
|
1503
1730
|
] })
|
|
1504
1731
|
] }),
|
|
1505
|
-
!token && /* @__PURE__ */
|
|
1732
|
+
usesToken && !token && /* @__PURE__ */ jsx13(Card, { padding: 4, radius: 2, tone: "caution", shadow: 1, children: /* @__PURE__ */ jsxs9(Flex, { align: "center", justify: "space-between", gap: 4, children: [
|
|
1506
1733
|
/* @__PURE__ */ jsxs9(Stack, { space: 2, children: [
|
|
1507
|
-
/* @__PURE__ */
|
|
1508
|
-
/* @__PURE__ */
|
|
1734
|
+
/* @__PURE__ */ jsx13(Text, { size: 1, weight: "semibold", children: "Deploy status is not connected" }),
|
|
1735
|
+
/* @__PURE__ */ jsx13(Text, { size: 1, muted: true, children: "You can trigger deploys now. Connect a Vercel API token to also see deployment status, build logs, history, and commit metadata." })
|
|
1509
1736
|
] }),
|
|
1510
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsx13(
|
|
1511
1738
|
Button,
|
|
1512
1739
|
{
|
|
1513
1740
|
text: "Connect",
|
|
@@ -1518,15 +1745,15 @@ function DeployTool() {
|
|
|
1518
1745
|
}
|
|
1519
1746
|
)
|
|
1520
1747
|
] }) }),
|
|
1521
|
-
targets.length === 0 && /* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
1748
|
+
targets.length === 0 && /* @__PURE__ */ jsx13(Card, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ jsxs9(Stack, { space: 4, style: { textAlign: "center" }, children: [
|
|
1749
|
+
/* @__PURE__ */ jsx13(Text, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
|
|
1523
1750
|
/* @__PURE__ */ jsxs9(Text, { size: 1, muted: true, children: [
|
|
1524
1751
|
"Add a deploy target using the button above, or create a",
|
|
1525
1752
|
" ",
|
|
1526
|
-
/* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ jsx13("code", { children: "vercel_deploy" }),
|
|
1527
1754
|
" document directly in the dataset."
|
|
1528
1755
|
] }),
|
|
1529
|
-
/* @__PURE__ */
|
|
1756
|
+
/* @__PURE__ */ jsx13(Flex, { justify: "center", children: /* @__PURE__ */ jsx13(
|
|
1530
1757
|
Button,
|
|
1531
1758
|
{
|
|
1532
1759
|
text: "Add deploy target",
|
|
@@ -1537,12 +1764,12 @@ function DeployTool() {
|
|
|
1537
1764
|
}
|
|
1538
1765
|
) })
|
|
1539
1766
|
] }) }),
|
|
1540
|
-
targets.length > 0 && /* @__PURE__ */
|
|
1767
|
+
targets.length > 0 && /* @__PURE__ */ jsx13("div", { className: "dvfs-grid", style: {
|
|
1541
1768
|
display: "grid",
|
|
1542
1769
|
gridTemplateColumns: "repeat(auto-fill, minmax(min(540px, 100%), 1fr))",
|
|
1543
1770
|
gap: "16px",
|
|
1544
1771
|
alignItems: "start"
|
|
1545
|
-
}, children: targets.map((target) => /* @__PURE__ */
|
|
1772
|
+
}, children: targets.map((target) => /* @__PURE__ */ jsx13(
|
|
1546
1773
|
DeployItem,
|
|
1547
1774
|
{
|
|
1548
1775
|
target,
|
|
@@ -1553,7 +1780,7 @@ function DeployTool() {
|
|
|
1553
1780
|
target._id
|
|
1554
1781
|
)) })
|
|
1555
1782
|
] }) }),
|
|
1556
|
-
/* @__PURE__ */
|
|
1783
|
+
/* @__PURE__ */ jsx13(
|
|
1557
1784
|
Box,
|
|
1558
1785
|
{
|
|
1559
1786
|
style: {
|
|
@@ -1570,17 +1797,18 @@ function DeployTool() {
|
|
|
1570
1797
|
] })
|
|
1571
1798
|
}
|
|
1572
1799
|
),
|
|
1573
|
-
showTokenSetup && /* @__PURE__ */
|
|
1800
|
+
showTokenSetup && /* @__PURE__ */ jsx13(
|
|
1574
1801
|
TokenSetup,
|
|
1575
1802
|
{
|
|
1576
1803
|
onSaved: () => {
|
|
1577
1804
|
setShowTokenSetup(false);
|
|
1578
1805
|
load();
|
|
1579
1806
|
},
|
|
1580
|
-
onCancel: () => setShowTokenSetup(false)
|
|
1807
|
+
onCancel: () => setShowTokenSetup(false),
|
|
1808
|
+
hasToken: Boolean(token)
|
|
1581
1809
|
}
|
|
1582
1810
|
),
|
|
1583
|
-
showCreateForm && /* @__PURE__ */
|
|
1811
|
+
showCreateForm && /* @__PURE__ */ jsx13(
|
|
1584
1812
|
DeployTargetForm,
|
|
1585
1813
|
{
|
|
1586
1814
|
onSaved: () => {
|
|
@@ -1590,7 +1818,7 @@ function DeployTool() {
|
|
|
1590
1818
|
onClose: () => setShowCreateForm(false)
|
|
1591
1819
|
}
|
|
1592
1820
|
),
|
|
1593
|
-
pendingEdit && /* @__PURE__ */
|
|
1821
|
+
pendingEdit && /* @__PURE__ */ jsx13(
|
|
1594
1822
|
DeployTargetForm,
|
|
1595
1823
|
{
|
|
1596
1824
|
initial: pendingEdit,
|
|
@@ -1601,7 +1829,7 @@ function DeployTool() {
|
|
|
1601
1829
|
onClose: () => setPendingEdit(null)
|
|
1602
1830
|
}
|
|
1603
1831
|
),
|
|
1604
|
-
pendingDelete && /* @__PURE__ */
|
|
1832
|
+
pendingDelete && /* @__PURE__ */ jsx13(
|
|
1605
1833
|
Dialog,
|
|
1606
1834
|
{
|
|
1607
1835
|
header: "Delete deploy target?",
|
|
@@ -1609,7 +1837,7 @@ function DeployTool() {
|
|
|
1609
1837
|
onClose: () => setPendingDelete(null),
|
|
1610
1838
|
width: 1,
|
|
1611
1839
|
footer: /* @__PURE__ */ jsxs9(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
|
|
1612
|
-
/* @__PURE__ */
|
|
1840
|
+
/* @__PURE__ */ jsx13(
|
|
1613
1841
|
Button,
|
|
1614
1842
|
{
|
|
1615
1843
|
text: "Cancel",
|
|
@@ -1618,7 +1846,7 @@ function DeployTool() {
|
|
|
1618
1846
|
style: { cursor: "pointer" }
|
|
1619
1847
|
}
|
|
1620
1848
|
),
|
|
1621
|
-
/* @__PURE__ */
|
|
1849
|
+
/* @__PURE__ */ jsx13(
|
|
1622
1850
|
Button,
|
|
1623
1851
|
{
|
|
1624
1852
|
text: "Delete",
|
|
@@ -1631,16 +1859,16 @@ function DeployTool() {
|
|
|
1631
1859
|
}
|
|
1632
1860
|
)
|
|
1633
1861
|
] }),
|
|
1634
|
-
children: /* @__PURE__ */
|
|
1862
|
+
children: /* @__PURE__ */ jsx13(Box, { padding: 4, children: /* @__PURE__ */ jsxs9(Stack, { space: 3, children: [
|
|
1635
1863
|
/* @__PURE__ */ jsxs9(Flex, { align: "center", gap: 2, children: [
|
|
1636
|
-
/* @__PURE__ */
|
|
1637
|
-
/* @__PURE__ */
|
|
1864
|
+
/* @__PURE__ */ jsx13(WarningOutlineIcon, {}),
|
|
1865
|
+
/* @__PURE__ */ jsx13(Text, { size: 2, weight: "semibold", children: pendingDelete.name })
|
|
1638
1866
|
] }),
|
|
1639
|
-
/* @__PURE__ */
|
|
1867
|
+
/* @__PURE__ */ jsx13(Text, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
|
|
1640
1868
|
] }) })
|
|
1641
1869
|
}
|
|
1642
1870
|
),
|
|
1643
|
-
/* @__PURE__ */
|
|
1871
|
+
/* @__PURE__ */ jsx13(ToastViewport, {})
|
|
1644
1872
|
] });
|
|
1645
1873
|
}
|
|
1646
1874
|
|
|
@@ -1649,10 +1877,10 @@ import { defineField, defineType } from "sanity";
|
|
|
1649
1877
|
|
|
1650
1878
|
// src/schema/schemaIcon.tsx
|
|
1651
1879
|
import { forwardRef as forwardRef3 } from "react";
|
|
1652
|
-
import { jsx as
|
|
1880
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1653
1881
|
var SchemaRocketIcon = forwardRef3(
|
|
1654
1882
|
function SchemaRocketIcon2(props, ref) {
|
|
1655
|
-
return /* @__PURE__ */
|
|
1883
|
+
return /* @__PURE__ */ jsx14(
|
|
1656
1884
|
"svg",
|
|
1657
1885
|
{
|
|
1658
1886
|
width: "1em",
|
|
@@ -1664,7 +1892,7 @@ var SchemaRocketIcon = forwardRef3(
|
|
|
1664
1892
|
focusable: "false",
|
|
1665
1893
|
...props,
|
|
1666
1894
|
ref,
|
|
1667
|
-
children: /* @__PURE__ */
|
|
1895
|
+
children: /* @__PURE__ */ jsx14(
|
|
1668
1896
|
"path",
|
|
1669
1897
|
{
|
|
1670
1898
|
d: "M12.5 20.5L15.5 14M11 9.49999L4.5 12.5M9 14C9 14 7.54688 14.9531 6.5 16C5.5 17 4.5 20.5 4.5 20.5C4.5 20.5 8 19.5 9 18.5C10 17.5 11 16 11 16M9 14C9 14 10.1 9.9 12.5 7.5C15.5 4.5 20.5 4.5 20.5 4.5C20.5 4.5 20.5 9.5 17.5 12.5C15.7492 14.2508 11 16 11 16L9 14ZM16.5 9.99999C16.5 10.8284 15.8284 11.5 15 11.5C14.1716 11.5 13.5 10.8284 13.5 9.99999C13.5 9.17157 14.1716 8.49999 15 8.49999C15.8284 8.49999 16.5 9.17157 16.5 9.99999Z",
|
|
@@ -1696,8 +1924,11 @@ var vercelDeploySchema = defineType({
|
|
|
1696
1924
|
name: "url",
|
|
1697
1925
|
title: "Deploy Hook URL",
|
|
1698
1926
|
type: "url",
|
|
1699
|
-
description: "From Vercel \u2192 Project Settings \u2192 Git \u2192 Deploy Hooks",
|
|
1700
|
-
validation: (Rule) => Rule.
|
|
1927
|
+
description: "From Vercel \u2192 Project Settings \u2192 Git \u2192 Deploy Hooks. Leave empty in proxy mode and set Proxy Key instead \u2014 a hook URL is itself a deploy credential, so anyone who can read this dataset can trigger a build with it.",
|
|
1928
|
+
validation: (Rule) => Rule.uri({ scheme: ["https"] }).custom((url, context) => {
|
|
1929
|
+
const doc = context.document;
|
|
1930
|
+
if (!url && !doc?.proxyKey) return "Set either a Deploy Hook URL or a Proxy Key";
|
|
1931
|
+
if (!url) return true;
|
|
1701
1932
|
if (typeof url !== "string") return true;
|
|
1702
1933
|
if (!url.includes("api.vercel.com/v1/integrations/deploy/")) {
|
|
1703
1934
|
return "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)";
|
|
@@ -1705,6 +1936,17 @@ var vercelDeploySchema = defineType({
|
|
|
1705
1936
|
return true;
|
|
1706
1937
|
})
|
|
1707
1938
|
}),
|
|
1939
|
+
defineField({
|
|
1940
|
+
name: "proxyKey",
|
|
1941
|
+
title: "Proxy Key",
|
|
1942
|
+
type: "string",
|
|
1943
|
+
description: "Used in proxy mode. Matches a key configured on the deploy proxy, which holds the real hook URL. Contains no secret.",
|
|
1944
|
+
validation: (Rule) => Rule.custom((key, context) => {
|
|
1945
|
+
const doc = context.document;
|
|
1946
|
+
if (!key && !doc?.url) return "Set either a Deploy Hook URL or a Proxy Key";
|
|
1947
|
+
return true;
|
|
1948
|
+
})
|
|
1949
|
+
}),
|
|
1708
1950
|
defineField({
|
|
1709
1951
|
name: "teamId",
|
|
1710
1952
|
title: "Vercel Team ID",
|
|
@@ -1724,50 +1966,28 @@ var vercelDeploySchema = defineType({
|
|
|
1724
1966
|
}
|
|
1725
1967
|
});
|
|
1726
1968
|
|
|
1727
|
-
// src/
|
|
1728
|
-
import {
|
|
1729
|
-
var vercelConfigSchema = defineType2({
|
|
1730
|
-
name: "vercelDeploy.config",
|
|
1731
|
-
title: "Vercel Deploy Configuration",
|
|
1732
|
-
type: "document",
|
|
1733
|
-
fields: [
|
|
1734
|
-
defineField2({
|
|
1735
|
-
name: "accessToken",
|
|
1736
|
-
title: "Vercel API Token",
|
|
1737
|
-
type: "string",
|
|
1738
|
-
description: "Readable by anyone who can read this dataset. Delete this document to revoke the stored token."
|
|
1739
|
-
})
|
|
1740
|
-
],
|
|
1741
|
-
preview: {
|
|
1742
|
-
select: { token: "accessToken" },
|
|
1743
|
-
prepare: ({ token }) => ({
|
|
1744
|
-
title: "Vercel API Token",
|
|
1745
|
-
// Never render the secret itself in a preview.
|
|
1746
|
-
subtitle: token ? "Connected" : "Not set"
|
|
1747
|
-
})
|
|
1748
|
-
}
|
|
1749
|
-
});
|
|
1750
|
-
|
|
1751
|
-
// src/index.ts
|
|
1969
|
+
// src/index.tsx
|
|
1970
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1752
1971
|
var vercelDeploy = definePlugin((options) => {
|
|
1753
1972
|
const config = options ?? {};
|
|
1973
|
+
const resolved = resolveConfig(options);
|
|
1754
1974
|
return {
|
|
1755
1975
|
name: "deploy-vercel-from-sanity",
|
|
1756
1976
|
schema: {
|
|
1757
|
-
types: [vercelDeploySchema
|
|
1977
|
+
types: [vercelDeploySchema]
|
|
1758
1978
|
},
|
|
1759
1979
|
tools: [
|
|
1760
1980
|
{
|
|
1761
1981
|
name: config.name ?? "vercel-deploy",
|
|
1762
1982
|
title: config.title ?? "Deploy",
|
|
1763
1983
|
icon: config.icon ?? RocketIcon,
|
|
1764
|
-
|
|
1984
|
+
// Wrapped so the tool tree can read the resolved config without prop drilling.
|
|
1985
|
+
component: () => /* @__PURE__ */ jsx15(ConfigProvider, { value: resolved, children: /* @__PURE__ */ jsx15(DeployTool, {}) })
|
|
1765
1986
|
}
|
|
1766
1987
|
]
|
|
1767
1988
|
};
|
|
1768
1989
|
});
|
|
1769
1990
|
export {
|
|
1770
|
-
vercelConfigSchema,
|
|
1771
1991
|
vercelDeploy,
|
|
1772
1992
|
vercelDeploySchema
|
|
1773
1993
|
};
|