@orange-soft/strapi-deployment-trigger 1.1.0 → 1.2.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.
@@ -7,17 +7,22 @@ const react = require("react");
7
7
  const reactIntl = require("react-intl");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  const icons = require("@strapi/icons");
10
- const index = require("./index-DGatQB-9.js");
10
+ const index = require("./index-w-vQ80Px.js");
11
11
  const getTranslation = (id) => `${index.PLUGIN_ID}.${id}`;
12
12
  const HomePage = () => {
13
13
  const { formatMessage } = reactIntl.useIntl();
14
14
  const { get, post } = admin.useFetchClient();
15
+ const location = reactRouterDom.useLocation();
15
16
  const [status, setStatus] = react.useState(null);
16
17
  const [loading, setLoading] = react.useState(true);
17
18
  const [deployingTargetId, setDeployingTargetId] = react.useState(null);
18
19
  const [notification, setNotification] = react.useState(null);
19
20
  react.useEffect(() => {
20
21
  fetchStatus();
22
+ if (location.state?.notification) {
23
+ setNotification(location.state.notification);
24
+ window.history.replaceState({}, document.title);
25
+ }
21
26
  }, []);
22
27
  const fetchStatus = async () => {
23
28
  try {
@@ -62,9 +67,18 @@ const HomePage = () => {
62
67
  }
63
68
  const settings = status?.settings || {};
64
69
  const parsed = status?.parsed || {};
65
- const isConfigured = status?.configured;
70
+ status?.configured;
66
71
  const hasToken = status?.hasToken;
67
72
  const targets = settings.targets || [];
73
+ const hasGitHubTargets = targets.some((t) => (t.type || "github") === "github");
74
+ targets.some((t) => t.type === "vercel");
75
+ const canTrigger = (target) => {
76
+ const targetType = target.type || "github";
77
+ if (targetType === "github") {
78
+ return hasToken && parsed.owner && parsed.repo;
79
+ }
80
+ return !!target.webhookUrl;
81
+ };
68
82
  return /* @__PURE__ */ jsxRuntime.jsxs(admin.Layouts.Root, { children: [
69
83
  /* @__PURE__ */ jsxRuntime.jsx(
70
84
  admin.Layouts.Header,
@@ -100,8 +114,8 @@ const HomePage = () => {
100
114
  ] })
101
115
  }
102
116
  ) }),
103
- !hasToken && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Token Missing", variant: "danger", children: "GitHub Personal Access Token is not configured. Please add it in Settings." }) }),
104
- !settings.repoUrl && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Configuration Required", variant: "warning", children: "Please configure your GitHub repository in the Settings page before triggering deployments." }) }),
117
+ hasGitHubTargets && !hasToken && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Token Missing", variant: "danger", children: "GitHub Personal Access Token is not configured. Please add it in Settings." }) }),
118
+ hasGitHubTargets && !settings.repoUrl && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Configuration Required", variant: "warning", children: "Please configure your GitHub repository in the Settings page before triggering deployments." }) }),
105
119
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
106
120
  /* @__PURE__ */ jsxRuntime.jsx(
107
121
  designSystem.Box,
@@ -154,27 +168,34 @@ const HomePage = () => {
154
168
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: "Deployment Targets" }),
155
169
  targets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
156
170
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
171
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Type" }) }),
157
172
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Name" }) }),
158
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Workflow" }) }),
159
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Branch" }) }),
173
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Details" }) }),
160
174
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Action" }) })
161
175
  ] }) }),
162
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: targets.map((target) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
163
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: target.name }) }),
164
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.workflow }) }),
165
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.branch }) }),
166
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
167
- designSystem.Button,
168
- {
169
- onClick: () => handleDeploy(target.id, target.name),
170
- loading: deployingTargetId === target.id,
171
- disabled: !isConfigured || deployingTargetId !== null,
172
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Rocket, {}),
173
- size: "S",
174
- children: deployingTargetId === target.id ? "Triggering..." : "Trigger"
175
- }
176
- ) })
177
- ] }, target.id)) })
176
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: targets.map((target) => {
177
+ const targetType = target.type || "github";
178
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
179
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", textColor: targetType === "github" ? "neutral800" : "secondary600", children: targetType === "github" ? "GitHub" : "Vercel" }) }),
180
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: target.name }) }),
181
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: targetType === "github" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: [
182
+ target.workflow,
183
+ " / ",
184
+ target.branch
185
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Webhook" }) }),
186
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
187
+ designSystem.Button,
188
+ {
189
+ onClick: () => handleDeploy(target.id, target.name),
190
+ loading: deployingTargetId === target.id,
191
+ disabled: !canTrigger(target) || deployingTargetId !== null,
192
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Rocket, {}),
193
+ size: "S",
194
+ children: deployingTargetId === target.id ? "Triggering..." : "Trigger"
195
+ }
196
+ ) })
197
+ ] }, target.id);
198
+ }) })
178
199
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", gap: 3, padding: 6, children: [
179
200
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "No deployment targets configured" }),
180
201
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/plugins/${index.PLUGIN_ID}/settings`, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "default", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cog, {}), children: "Add Targets in Settings" }) })
@@ -182,7 +203,7 @@ const HomePage = () => {
182
203
  ] })
183
204
  }
184
205
  ),
185
- !isConfigured && targets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
206
+ hasGitHubTargets && (!hasToken || !parsed.owner || !parsed.repo) && /* @__PURE__ */ jsxRuntime.jsx(
186
207
  designSystem.Box,
187
208
  {
188
209
  background: "neutral0",
@@ -193,8 +214,8 @@ const HomePage = () => {
193
214
  paddingLeft: 7,
194
215
  paddingRight: 7,
195
216
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", gap: 3, children: [
196
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", textColor: "neutral600", textAlign: "center", children: "Setup Incomplete" }),
197
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "Please ensure repository URL and GitHub token are configured in Settings." }),
217
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", textColor: "neutral600", textAlign: "center", children: "GitHub Setup Incomplete" }),
218
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "Please ensure repository URL and GitHub token are configured in Settings for GitHub targets." }),
198
219
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/plugins/${index.PLUGIN_ID}/settings`, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "default", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cog, {}), children: "Go to Settings" }) }) })
199
220
  ] })
200
221
  }
@@ -206,6 +227,7 @@ const HomePage = () => {
206
227
  const TOKEN_PATTERN = /^github_pat_[a-zA-Z0-9_]+$/;
207
228
  const REPO_URL_PATTERN = /^https:\/\/github\.com\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+\/?$/;
208
229
  const WORKFLOW_PATTERN = /^[a-zA-Z0-9_.-]+\.ya?ml$/;
230
+ const VERCEL_WEBHOOK_PATTERN = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\/.+$/;
209
231
  const validateToken = (value) => {
210
232
  if (!value) return null;
211
233
  if (!TOKEN_PATTERN.test(value)) {
@@ -227,7 +249,15 @@ const validateWorkflow = (value) => {
227
249
  }
228
250
  return null;
229
251
  };
252
+ const validateVercelWebhook = (value) => {
253
+ if (!value) return "Webhook URL is required";
254
+ if (!VERCEL_WEBHOOK_PATTERN.test(value)) {
255
+ return "Must be a valid Vercel deploy hook URL (https://api.vercel.com/v1/integrations/deploy/...)";
256
+ }
257
+ return null;
258
+ };
230
259
  const SettingsPage = () => {
260
+ const navigate = reactRouterDom.useNavigate();
231
261
  const { get, put, post, del } = admin.useFetchClient();
232
262
  const [settings, setSettings] = react.useState({
233
263
  githubToken: "",
@@ -241,7 +271,7 @@ const SettingsPage = () => {
241
271
  const [saving, setSaving] = react.useState(false);
242
272
  const [notification, setNotification] = react.useState(null);
243
273
  const [editingTarget, setEditingTarget] = react.useState(null);
244
- const [targetForm, setTargetForm] = react.useState({ name: "", workflow: "", branch: "" });
274
+ const [targetForm, setTargetForm] = react.useState({ type: "github", name: "", workflow: "", branch: "", webhookUrl: "" });
245
275
  const [targetErrors, setTargetErrors] = react.useState({});
246
276
  const [showAddForm, setShowAddForm] = react.useState(false);
247
277
  const [deleteDialogOpen, setDeleteDialogOpen] = react.useState(false);
@@ -288,17 +318,14 @@ const SettingsPage = () => {
288
318
  dataToSave.githubToken = settings.githubToken;
289
319
  }
290
320
  const { data } = await put(`/${index.PLUGIN_ID}/settings`, { data: dataToSave });
291
- if (settings.githubToken) {
292
- setHasExistingToken(true);
293
- setMaskedToken(data.data?.maskedToken);
294
- }
295
- setSettings((prev) => ({ ...prev, githubToken: "" }));
296
- setNotification({ type: "success", message: "Settings saved successfully" });
321
+ navigate(`/plugins/${index.PLUGIN_ID}`, {
322
+ state: { notification: { type: "success", message: "Settings saved successfully" } }
323
+ });
297
324
  } catch (error) {
298
325
  console.error("Error saving settings:", error);
299
326
  setNotification({ type: "danger", message: "Failed to save settings" });
327
+ setSaving(false);
300
328
  }
301
- setSaving(false);
302
329
  };
303
330
  const handleChange = (field) => (e) => {
304
331
  const value = e.target.value;
@@ -308,7 +335,7 @@ const SettingsPage = () => {
308
335
  }
309
336
  };
310
337
  const resetTargetForm = () => {
311
- setTargetForm({ name: "", workflow: "deploy.yml", branch: "master" });
338
+ setTargetForm({ type: "github", name: "", workflow: "deploy.yml", branch: "master", webhookUrl: "" });
312
339
  setTargetErrors({});
313
340
  setEditingTarget(null);
314
341
  setShowAddForm(false);
@@ -316,9 +343,14 @@ const SettingsPage = () => {
316
343
  const validateTargetForm = () => {
317
344
  const newErrors = {};
318
345
  if (!targetForm.name.trim()) newErrors.name = "Name is required";
319
- const workflowError = validateWorkflow(targetForm.workflow);
320
- if (workflowError) newErrors.workflow = workflowError;
321
- if (!targetForm.branch.trim()) newErrors.branch = "Branch is required";
346
+ if (targetForm.type === "github") {
347
+ const workflowError = validateWorkflow(targetForm.workflow);
348
+ if (workflowError) newErrors.workflow = workflowError;
349
+ if (!targetForm.branch.trim()) newErrors.branch = "Branch is required";
350
+ } else if (targetForm.type === "vercel") {
351
+ const webhookError = validateVercelWebhook(targetForm.webhookUrl);
352
+ if (webhookError) newErrors.webhookUrl = webhookError;
353
+ }
322
354
  setTargetErrors(newErrors);
323
355
  return Object.keys(newErrors).length === 0;
324
356
  };
@@ -339,7 +371,13 @@ const SettingsPage = () => {
339
371
  };
340
372
  const handleEditTarget = (target) => {
341
373
  setEditingTarget(target.id);
342
- setTargetForm({ name: target.name, workflow: target.workflow, branch: target.branch });
374
+ setTargetForm({
375
+ type: target.type || "github",
376
+ name: target.name,
377
+ workflow: target.workflow || "deploy.yml",
378
+ branch: target.branch || "master",
379
+ webhookUrl: target.webhookUrl || ""
380
+ });
343
381
  setShowAddForm(false);
344
382
  };
345
383
  const handleUpdateTarget = async () => {
@@ -481,7 +519,7 @@ const SettingsPage = () => {
481
519
  startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
482
520
  onClick: () => {
483
521
  setShowAddForm(true);
484
- setTargetForm({ name: "", workflow: "deploy.yml", branch: "master" });
522
+ setTargetForm({ type: "github", name: "", workflow: "deploy.yml", branch: "master", webhookUrl: "" });
485
523
  },
486
524
  size: "S",
487
525
  children: "Add Target"
@@ -497,7 +535,21 @@ const SettingsPage = () => {
497
535
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
498
536
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: editingTarget ? "Edit Target" : "Add New Target" }),
499
537
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
500
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetName", required: true, error: targetErrors.name, children: [
538
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetType", required: true, children: [
539
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Type" }),
540
+ /* @__PURE__ */ jsxRuntime.jsxs(
541
+ designSystem.SingleSelect,
542
+ {
543
+ value: targetForm.type,
544
+ onChange: (value) => setTargetForm((prev) => ({ ...prev, type: value })),
545
+ children: [
546
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "github", children: "GitHub" }),
547
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "vercel", children: "Vercel" })
548
+ ]
549
+ }
550
+ )
551
+ ] }) }),
552
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetName", required: true, error: targetErrors.name, children: [
501
553
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Name" }),
502
554
  /* @__PURE__ */ jsxRuntime.jsx(
503
555
  designSystem.Field.Input,
@@ -509,26 +561,40 @@ const SettingsPage = () => {
509
561
  ),
510
562
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
511
563
  ] }) }),
512
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetWorkflow", required: true, error: targetErrors.workflow, children: [
513
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Workflow File" }),
514
- /* @__PURE__ */ jsxRuntime.jsx(
515
- designSystem.Field.Input,
516
- {
517
- placeholder: "deploy.yml",
518
- value: targetForm.workflow,
519
- onChange: handleTargetFormChange("workflow")
520
- }
521
- ),
522
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
523
- ] }) }),
524
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetBranch", required: true, error: targetErrors.branch, children: [
525
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Branch" }),
564
+ targetForm.type === "github" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
565
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetWorkflow", required: true, error: targetErrors.workflow, children: [
566
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Workflow File" }),
567
+ /* @__PURE__ */ jsxRuntime.jsx(
568
+ designSystem.Field.Input,
569
+ {
570
+ placeholder: "deploy.yml",
571
+ value: targetForm.workflow,
572
+ onChange: handleTargetFormChange("workflow")
573
+ }
574
+ ),
575
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
576
+ ] }) }),
577
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetBranch", required: true, error: targetErrors.branch, children: [
578
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Branch" }),
579
+ /* @__PURE__ */ jsxRuntime.jsx(
580
+ designSystem.Field.Input,
581
+ {
582
+ placeholder: "main",
583
+ value: targetForm.branch,
584
+ onChange: handleTargetFormChange("branch")
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
588
+ ] }) })
589
+ ] }),
590
+ targetForm.type === "vercel" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetWebhookUrl", required: true, error: targetErrors.webhookUrl, children: [
591
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Webhook URL" }),
526
592
  /* @__PURE__ */ jsxRuntime.jsx(
527
593
  designSystem.Field.Input,
528
594
  {
529
- placeholder: "main",
530
- value: targetForm.branch,
531
- onChange: handleTargetFormChange("branch")
595
+ placeholder: "https://api.vercel.com/v1/integrations/deploy/...",
596
+ value: targetForm.webhookUrl,
597
+ onChange: handleTargetFormChange("webhookUrl")
532
598
  }
533
599
  ),
534
600
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
@@ -550,39 +616,48 @@ const SettingsPage = () => {
550
616
  ),
551
617
  settings.targets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
552
618
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
619
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Type" }) }),
553
620
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Name" }) }),
554
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Workflow" }) }),
555
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Branch" }) }),
621
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Details" }) }),
556
622
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Actions" }) })
557
623
  ] }) }),
558
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: settings.targets.map((target) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
559
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.name }) }),
560
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.workflow }) }),
561
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.branch }) }),
562
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, children: [
563
- /* @__PURE__ */ jsxRuntime.jsx(
564
- designSystem.IconButton,
565
- {
566
- onClick: () => handleEditTarget(target),
567
- label: "Edit",
568
- variant: "ghost",
569
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {})
570
- }
571
- ),
572
- /* @__PURE__ */ jsxRuntime.jsx(
573
- designSystem.IconButton,
574
- {
575
- onClick: () => {
576
- setTargetToDelete(target.id);
577
- setDeleteDialogOpen(true);
578
- },
579
- label: "Delete",
580
- variant: "ghost",
581
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
582
- }
583
- )
584
- ] }) })
585
- ] }, target.id)) })
624
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: settings.targets.map((target) => {
625
+ const targetType = target.type || "github";
626
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
627
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", textColor: targetType === "github" ? "neutral800" : "secondary600", children: targetType === "github" ? "GitHub" : "Vercel" }) }),
628
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.name }) }),
629
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: targetType === "github" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: [
630
+ target.workflow,
631
+ " / ",
632
+ target.branch
633
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Webhook configured" }) }),
634
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
635
+ /* @__PURE__ */ jsxRuntime.jsx(
636
+ designSystem.Button,
637
+ {
638
+ onClick: () => handleEditTarget(target),
639
+ variant: "tertiary",
640
+ size: "S",
641
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}),
642
+ children: "Edit"
643
+ }
644
+ ),
645
+ /* @__PURE__ */ jsxRuntime.jsx(
646
+ designSystem.Button,
647
+ {
648
+ onClick: () => {
649
+ setTargetToDelete(target.id);
650
+ setDeleteDialogOpen(true);
651
+ },
652
+ variant: "danger-light",
653
+ size: "S",
654
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}),
655
+ children: "Delete"
656
+ }
657
+ )
658
+ ] }) })
659
+ ] }, target.id);
660
+ }) })
586
661
  ] }) : !showAddForm && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: 'No deployment targets configured. Click "Add Target" to create one.' })
587
662
  ] })
588
663
  }
@@ -36,7 +36,7 @@ const index = {
36
36
  defaultMessage: PLUGIN_ID
37
37
  },
38
38
  Component: async () => {
39
- const { App } = await import("./App-vakyp6FE.mjs");
39
+ const { App } = await import("./App-k07qAAvE.mjs");
40
40
  return App;
41
41
  }
42
42
  });
@@ -37,7 +37,7 @@ const index = {
37
37
  defaultMessage: PLUGIN_ID
38
38
  },
39
39
  Component: async () => {
40
- const { App } = await Promise.resolve().then(() => require("./App-CuSCtdH7.js"));
40
+ const { App } = await Promise.resolve().then(() => require("./App-vIrt97zQ.js"));
41
41
  return App;
42
42
  }
43
43
  });
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-DGatQB-9.js");
2
+ const index = require("../_chunks/index-w-vQ80Px.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-CZWWYGR3.mjs";
1
+ import { i } from "../_chunks/index-BwZtnn__.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
@@ -69,6 +69,30 @@ const controller = ({ strapi }) => ({
69
69
  },
70
70
  // Trigger deployment for a specific target
71
71
  async trigger(ctx) {
72
+ const service2 = getService(strapi);
73
+ const { targetId } = ctx.request.body || {};
74
+ let target;
75
+ if (targetId) {
76
+ target = await service2.getTarget(targetId);
77
+ if (!target) {
78
+ return ctx.badRequest("Target not found");
79
+ }
80
+ } else {
81
+ const settings = await service2.getSettings();
82
+ target = settings.targets?.[0];
83
+ if (!target) {
84
+ return ctx.badRequest("No deployment targets configured");
85
+ }
86
+ }
87
+ const targetType = target.type || "github";
88
+ if (targetType === "vercel") {
89
+ return this.triggerVercel(ctx, target);
90
+ } else {
91
+ return this.triggerGitHub(ctx, target);
92
+ }
93
+ },
94
+ // Trigger GitHub Actions deployment
95
+ async triggerGitHub(ctx, target) {
72
96
  const service2 = getService(strapi);
73
97
  const githubToken = await service2.getToken();
74
98
  if (!githubToken) {
@@ -79,22 +103,9 @@ const controller = ({ strapi }) => ({
79
103
  if (!owner || !repo) {
80
104
  return ctx.badRequest("GitHub repository URL is not configured or invalid. Please configure it in Settings.");
81
105
  }
82
- const { targetId, workflow: overrideWorkflow, branch: overrideBranch } = ctx.request.body || {};
83
- let workflow, branch, targetName;
84
- if (targetId) {
85
- const target = await service2.getTarget(targetId);
86
- if (!target) {
87
- return ctx.badRequest("Target not found");
88
- }
89
- workflow = overrideWorkflow || target.workflow;
90
- branch = overrideBranch || target.branch;
91
- targetName = target.name;
92
- } else {
93
- const firstTarget = settings.targets?.[0];
94
- workflow = overrideWorkflow || firstTarget?.workflow || "deploy.yml";
95
- branch = overrideBranch || firstTarget?.branch || "master";
96
- targetName = firstTarget?.name || "Default";
97
- }
106
+ const workflow = target.workflow || "deploy.yml";
107
+ const branch = target.branch || "master";
108
+ const targetName = target.name;
98
109
  const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
99
110
  try {
100
111
  const response = await fetch(url, {
@@ -111,11 +122,12 @@ const controller = ({ strapi }) => ({
111
122
  strapi.log.error(`GitHub API error: ${response.status} - ${errorText}`);
112
123
  return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
113
124
  }
114
- strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
125
+ strapi.log.info(`GitHub deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
115
126
  const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
116
127
  ctx.body = {
117
128
  data: {
118
129
  success: true,
130
+ type: "github",
119
131
  message: `Deployment triggered successfully for ${owner}/${repo}`,
120
132
  repository: `${owner}/${repo}`,
121
133
  targetName,
@@ -125,9 +137,39 @@ const controller = ({ strapi }) => ({
125
137
  }
126
138
  };
127
139
  } catch (error) {
128
- strapi.log.error("Error triggering deployment:", error);
140
+ strapi.log.error("Error triggering GitHub deployment:", error);
129
141
  return ctx.badRequest(`Failed to trigger deployment: ${error.message}`);
130
142
  }
143
+ },
144
+ // Trigger Vercel deployment via webhook
145
+ async triggerVercel(ctx, target) {
146
+ const webhookUrl = target.webhookUrl;
147
+ const targetName = target.name;
148
+ if (!webhookUrl) {
149
+ return ctx.badRequest("Vercel webhook URL is not configured for this target.");
150
+ }
151
+ try {
152
+ const response = await fetch(webhookUrl, {
153
+ method: "POST"
154
+ });
155
+ if (!response.ok) {
156
+ const errorText = await response.text();
157
+ strapi.log.error(`Vercel webhook error: ${response.status} - ${errorText}`);
158
+ return ctx.badRequest(`Vercel webhook error: ${response.status} - ${errorText}`);
159
+ }
160
+ strapi.log.info(`Vercel deployment triggered [${targetName}]`);
161
+ ctx.body = {
162
+ data: {
163
+ success: true,
164
+ type: "vercel",
165
+ message: "Vercel deployment triggered successfully",
166
+ targetName
167
+ }
168
+ };
169
+ } catch (error) {
170
+ strapi.log.error("Error triggering Vercel deployment:", error);
171
+ return ctx.badRequest(`Failed to trigger Vercel deployment: ${error.message}`);
172
+ }
131
173
  }
132
174
  });
133
175
  const controllers = {
@@ -249,7 +291,14 @@ const service = ({ strapi }) => ({
249
291
  migrateSettings(settings) {
250
292
  if (!settings) return null;
251
293
  if (Array.isArray(settings.targets)) {
252
- return settings;
294
+ const targetsWithType = settings.targets.map((target) => ({
295
+ ...target,
296
+ type: target.type || "github"
297
+ }));
298
+ return {
299
+ ...settings,
300
+ targets: targetsWithType
301
+ };
253
302
  }
254
303
  if (settings.workflow || settings.branch) {
255
304
  return {
@@ -257,6 +306,7 @@ const service = ({ strapi }) => ({
257
306
  githubToken: settings.githubToken || "",
258
307
  targets: [{
259
308
  id: generateId(),
309
+ type: "github",
260
310
  name: "Default",
261
311
  workflow: settings.workflow || "deploy.yml",
262
312
  branch: settings.branch || "master"
@@ -268,7 +318,11 @@ const service = ({ strapi }) => ({
268
318
  async getSettings() {
269
319
  const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
270
320
  let dbSettings = await store.get({ key: STORE_KEY });
321
+ const needsMigration = dbSettings && !Array.isArray(dbSettings.targets) && (dbSettings.workflow || dbSettings.branch);
271
322
  dbSettings = this.migrateSettings(dbSettings);
323
+ if (needsMigration && dbSettings) {
324
+ await store.set({ key: STORE_KEY, value: dbSettings });
325
+ }
272
326
  if (!dbSettings) {
273
327
  return {
274
328
  ...DEFAULT_SETTINGS,
@@ -309,12 +363,18 @@ const service = ({ strapi }) => ({
309
363
  const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
310
364
  let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
311
365
  settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
366
+ const targetType = target.type || "github";
312
367
  const newTarget = {
313
368
  id: generateId(),
314
- name: target.name || "New Target",
315
- workflow: target.workflow || "deploy.yml",
316
- branch: target.branch || "master"
369
+ type: targetType,
370
+ name: target.name || "New Target"
317
371
  };
372
+ if (targetType === "github") {
373
+ newTarget.workflow = target.workflow || "deploy.yml";
374
+ newTarget.branch = target.branch || "master";
375
+ } else if (targetType === "vercel") {
376
+ newTarget.webhookUrl = target.webhookUrl || "";
377
+ }
318
378
  settings.targets = [...settings.targets || [], newTarget];
319
379
  await store.set({ key: STORE_KEY, value: settings });
320
380
  return newTarget;
@@ -326,12 +386,20 @@ const service = ({ strapi }) => ({
326
386
  if (!settings?.targets) return null;
327
387
  const targetIndex = settings.targets.findIndex((t) => t.id === targetId);
328
388
  if (targetIndex === -1) return null;
329
- settings.targets[targetIndex] = {
330
- ...settings.targets[targetIndex],
331
- ...updates,
332
- id: targetId
333
- // Preserve ID
389
+ const existingTarget = settings.targets[targetIndex];
390
+ const targetType = updates.type || existingTarget.type || "github";
391
+ const updatedTarget = {
392
+ id: targetId,
393
+ type: targetType,
394
+ name: updates.name !== void 0 ? updates.name : existingTarget.name
334
395
  };
396
+ if (targetType === "github") {
397
+ updatedTarget.workflow = updates.workflow !== void 0 ? updates.workflow : existingTarget.workflow;
398
+ updatedTarget.branch = updates.branch !== void 0 ? updates.branch : existingTarget.branch;
399
+ } else if (targetType === "vercel") {
400
+ updatedTarget.webhookUrl = updates.webhookUrl !== void 0 ? updates.webhookUrl : existingTarget.webhookUrl;
401
+ }
402
+ settings.targets[targetIndex] = updatedTarget;
335
403
  await store.set({ key: STORE_KEY, value: settings });
336
404
  return settings.targets[targetIndex];
337
405
  },