@upsnap/strapi 1.0.9 → 1.0.11

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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { Layouts, Page } from "@strapi/strapi/admin";
3
3
  import { NavLink, useNavigate, useParams, useSearchParams, Routes, Route } from "react-router-dom";
4
- import { SubNav, SubNavHeader, SubNavSection, SubNavLink, Box, Table, Thead, Tr, Th, Checkbox, Typography, VisuallyHidden, Tbody, Td, Flex, Badge, IconButton, Card, CardHeader, Switch, CardBody, CardContent, SingleSelect, SingleSelectOption, Accordion, TextInput, Loader, Tooltip, Field, Button, Dialog, Alert, Modal, SimpleMenu, MenuItem, Tabs, Divider, Link, CardTitle, CardSubtitle, CardBadge, EmptyStateLayout, Main, Grid, MultiSelect, MultiSelectOption, Popover, Pagination, PreviousLink, Dots, PageLink, NextLink } from "@strapi/design-system";
4
+ import { SubNav, SubNavHeader, SubNavSection, SubNavLink, Box, Table, Thead, Tr, Th, Checkbox, Typography, VisuallyHidden, Tbody, Td, Flex, Badge, IconButton, Card, CardHeader, Switch, CardBody, CardContent, SingleSelect, SingleSelectOption, Accordion, TextInput, Loader, Button, Tooltip, Field, Dialog, Alert, Modal, SimpleMenu, MenuItem, Tabs, Divider, Link, CardTitle, CardSubtitle, CardBadge, EmptyStateLayout, Main, Grid, MultiSelect, MultiSelectOption, Popover, Pagination, PreviousLink, Dots, PageLink, NextLink } from "@strapi/design-system";
5
5
  import { House, BulletList, Monitor, Cog, Pencil, Trash, Search, Cross, ChevronDown, Plus, EyeStriked, Eye, Graph, MinusCircle, Play, More, CrossCircle, SealCheck, ArrowsCounterClockwise, ArrowRight, ArrowLeft, CheckCircle, Information, ArrowDown, Rocket, Filter, FileCsv, FilePdf, CaretDown, CaretUp } from "@strapi/icons";
6
6
  import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
7
7
  import { toast, ToastContainer } from "react-toastify";
@@ -91,6 +91,11 @@ const MONITOR = {
91
91
  LIGHTHOUSE_DEFAULT_INTERVAL_SECONDS: 7 * 86400
92
92
  // 7 days
93
93
  };
94
+ const MONITOR_TYPE_OPTIONS = [
95
+ { value: MONITOR_TYPE.WEBSITE, label: "Website Monitoring" },
96
+ { value: MONITOR_TYPE.PORT, label: "Port Monitoring" },
97
+ { value: MONITOR_TYPE.KEYWORD, label: "Keyword Monitoring" }
98
+ ];
94
99
  const INTEGRATIONS_TYPES = {
95
100
  webhook: {
96
101
  name: "webhook",
@@ -170,6 +175,88 @@ const INCIDENTS_EXPORT_TYPES = {
170
175
  pdf: "pdf"
171
176
  };
172
177
  const INCIDENT_CHECK_TYPE_KEYS = Object.keys(INCIDENT_CHECK_TYPES);
178
+ const generateRandomColor = () => {
179
+ const colors2 = [
180
+ "#d3ed75",
181
+ "#33FF57",
182
+ "#3357FF",
183
+ "#FF33F5",
184
+ "#33FFF5",
185
+ "#eed33b",
186
+ "#47c8ff",
187
+ "#4169E1",
188
+ "#32CD32",
189
+ "#FF1493",
190
+ "#8A2BE2",
191
+ "#00CED1",
192
+ "#FF4500",
193
+ "#2E8B57",
194
+ "#DC143C"
195
+ ];
196
+ return colors2[Math.floor(Math.random() * colors2.length)];
197
+ };
198
+ const STORAGE_KEY = "selectedMonitor";
199
+ function getUserData() {
200
+ if (typeof window === "undefined") return null;
201
+ try {
202
+ const userDataString = localStorage.getItem("userDetails");
203
+ if (!userDataString) return null;
204
+ const userData = JSON.parse(userDataString);
205
+ return userData;
206
+ } catch (error) {
207
+ console.error("Error parsing userData from localStorage:", error);
208
+ return null;
209
+ }
210
+ }
211
+ async function getUserDetailsCached(forceFetchFromMicroservice = false) {
212
+ if (typeof window === "undefined") return null;
213
+ try {
214
+ const userDetailsString = localStorage.getItem("userDetails");
215
+ if (!userDetailsString) return null;
216
+ if (!forceFetchFromMicroservice) {
217
+ try {
218
+ const cached2 = JSON.parse(userDetailsString);
219
+ if (cached2.updated_at) {
220
+ const cachedTime = Date.parse(cached2.updated_at);
221
+ if (!isNaN(cachedTime)) {
222
+ const ageMs = Date.now() - cachedTime;
223
+ if (ageMs < 5 * 60 * 1e3) {
224
+ return cached2;
225
+ }
226
+ }
227
+ }
228
+ } catch (e) {
229
+ console.error("Error parsing cached user details:", e);
230
+ }
231
+ }
232
+ const data = await getUserDetails();
233
+ if (!data) {
234
+ return null;
235
+ }
236
+ setUserDetails(data);
237
+ return data;
238
+ } catch (error) {
239
+ console.error("Error parsing userDetails from localStorage:", error);
240
+ return null;
241
+ }
242
+ }
243
+ function setUserDetails(details) {
244
+ if (typeof window === "undefined") return;
245
+ try {
246
+ const toStore = { ...details, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
247
+ localStorage.setItem("userDetails", JSON.stringify(toStore));
248
+ } catch (error) {
249
+ console.error("Error storing userDetails in localStorage:", error);
250
+ }
251
+ }
252
+ const clearAllStoredMonitors = () => {
253
+ if (typeof window === "undefined") return;
254
+ Object.keys(localStorage).forEach((key) => {
255
+ if (key.startsWith(`${STORAGE_KEY}`)) {
256
+ localStorage.removeItem(key);
257
+ }
258
+ });
259
+ };
173
260
  const request = async (url, options = {}) => {
174
261
  const response = await axios({
175
262
  url: `/upsnap${url}`,
@@ -335,69 +422,22 @@ const fetchRegionsData = async () => {
335
422
  return [];
336
423
  }
337
424
  };
338
- const STORAGE_KEY = "selectedMonitor";
339
- function getUserData() {
340
- if (typeof window === "undefined") return null;
341
- try {
342
- const userDataString = localStorage.getItem("userDetails");
343
- if (!userDataString) return null;
344
- const userData = JSON.parse(userDataString);
345
- return userData;
346
- } catch (error) {
347
- console.error("Error parsing userData from localStorage:", error);
348
- return null;
349
- }
350
- }
351
- async function getUserDetailsCached(forceFetchFromMicroservice = false) {
352
- if (typeof window === "undefined") return null;
425
+ const fetchTags = async (setIsLoading, setTags) => {
426
+ setIsLoading(true);
353
427
  try {
354
- const userDetailsString = localStorage.getItem("userDetails");
355
- if (!userDetailsString) return null;
356
- if (!forceFetchFromMicroservice) {
357
- try {
358
- const cached2 = JSON.parse(userDetailsString);
359
- if (cached2.updated_at) {
360
- const cachedTime = Date.parse(cached2.updated_at);
361
- if (!isNaN(cachedTime)) {
362
- const ageMs = Date.now() - cachedTime;
363
- if (ageMs < 5 * 60 * 1e3) {
364
- return cached2;
365
- }
366
- }
367
- }
368
- } catch (e) {
369
- console.error("Error parsing cached user details:", e);
370
- }
371
- }
372
- const data = await getUserDetails();
373
- if (!data) {
374
- return null;
428
+ const result = await request("/tags", {
429
+ method: "GET"
430
+ });
431
+ if (!result?.tagsData) {
432
+ throw new Error("Failed to fetch tags");
375
433
  }
376
- setUserDetails(data);
377
- return data;
378
- } catch (error) {
379
- console.error("Error parsing userDetails from localStorage:", error);
380
- return null;
381
- }
382
- }
383
- function setUserDetails(details) {
384
- if (typeof window === "undefined") return;
385
- try {
386
- const toStore = { ...details, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
387
- localStorage.setItem("userDetails", JSON.stringify(toStore));
434
+ setTags(result?.tagsData?.data);
388
435
  } catch (error) {
389
- console.error("Error storing userDetails in localStorage:", error);
436
+ console.error("Error fetching tags:", error);
437
+ } finally {
438
+ setIsLoading(false);
390
439
  }
391
- }
392
- const clearAllStoredMonitors = () => {
393
- if (typeof window === "undefined") return;
394
- Object.keys(localStorage).forEach((key) => {
395
- if (key.startsWith(`${STORAGE_KEY}`)) {
396
- localStorage.removeItem(key);
397
- }
398
- });
399
440
  };
400
- getUserData()?.user?.email ?? "";
401
441
  function MonitorsTable({
402
442
  monitors = [],
403
443
  onChange,
@@ -405,15 +445,15 @@ function MonitorsTable({
405
445
  handleDelete,
406
446
  setBulkDeleteIds
407
447
  }) {
408
- const [open, setOpen] = useState(false);
409
- const [channels, setChannels] = useState([]);
410
448
  const [selected, setSelected] = useState([]);
411
449
  const [loading, setLoading] = useState(true);
412
- const [search, setSearch] = useState("");
413
- const [defaultEmail, setDefaultEmail] = useState();
414
450
  const isInternalUpdate = useRef(false);
415
451
  const [primaryMonitorId, setPrimaryMonitorIdState] = useState(null);
452
+ const [availableTags, setAvailableTags] = useState([]);
416
453
  const navigate = useNavigate();
454
+ useEffect(() => {
455
+ fetchTags(setLoading, setAvailableTags);
456
+ }, [monitors]);
417
457
  useEffect(() => {
418
458
  async function fetchPrimaryMonitorId() {
419
459
  try {
@@ -439,7 +479,7 @@ function MonitorsTable({
439
479
  });
440
480
  };
441
481
  const toggleAll = async () => {
442
- const allMonitorIds = Array.isArray(monitors) ? monitors.filter((m) => m.id !== null).map((m) => m.id.toString()) : [];
482
+ const allMonitorIds = Array.isArray(monitors) ? monitors.filter((monitor) => monitor.id !== null).map((monitor) => monitor.id.toString()) : [];
443
483
  const isAllSelected = allMonitorIds.every((id) => selected.includes(id));
444
484
  setSelected((prev) => {
445
485
  const updated = isAllSelected ? [] : allMonitorIds;
@@ -447,10 +487,6 @@ function MonitorsTable({
447
487
  return updated;
448
488
  });
449
489
  };
450
- Array.isArray(channels) ? channels.filter((ch) => {
451
- const email2 = ch.config?.recipients?.to ?? "";
452
- return ch.name.toLowerCase().includes(search.toLowerCase()) || email2.toLowerCase().includes(search.toLowerCase());
453
- }) : [];
454
490
  useEffect(() => {
455
491
  if (isInternalUpdate.current) ;
456
492
  setBulkDeleteIds(selected);
@@ -476,7 +512,9 @@ function MonitorsTable({
476
512
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
477
513
  Checkbox,
478
514
  {
479
- checked: monitors.length > 0 && monitors.every((c) => c.id !== null && selected.includes(c.id.toString())),
515
+ checked: monitors.length > 0 && monitors.every(
516
+ (monitor) => monitor.id !== null && selected.includes(monitor.id.toString())
517
+ ),
480
518
  onCheckedChange: toggleAll
481
519
  }
482
520
  ) }),
@@ -494,7 +532,35 @@ function MonitorsTable({
494
532
  ) }),
495
533
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "self-start", direction: "column", children: [
496
534
  /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: monitor.name }),
497
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: monitor.config.meta.url })
535
+ /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: 1, children: [
536
+ /* @__PURE__ */ jsx(
537
+ Badge,
538
+ {
539
+ size: "S",
540
+ active: monitor.is_enabled,
541
+ textColor: "primary500",
542
+ background: "neutral150",
543
+ children: monitor.service_type
544
+ }
545
+ ),
546
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: monitor.config.meta.url }),
547
+ monitor.tag_ids && monitor.tag_ids.length > 0 && /* @__PURE__ */ jsx(Flex, { wrap: "wrap", gap: 1, width: "300px", children: monitor.tag_ids.map((tagId) => {
548
+ const tag = availableTags.find((tag2) => tag2.id === tagId);
549
+ if (!tag) return null;
550
+ return /* @__PURE__ */ jsx(
551
+ Badge,
552
+ {
553
+ size: "S",
554
+ style: {
555
+ backgroundColor: `${tag.color}20`,
556
+ border: `1px solid ${tag.color}40`
557
+ },
558
+ children: tag.name
559
+ },
560
+ tagId
561
+ );
562
+ }) })
563
+ ] })
498
564
  ] }) }),
499
565
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
500
566
  Badge,
@@ -4887,7 +4953,7 @@ function MonitorIntervalSlider({
4887
4953
  const effectiveValue = userPlan === PLAN_TYPES.TRIAL && value < minMonitoringInterval ? minMonitoringInterval : value;
4888
4954
  const sliderPercent = secondsToSlider(effectiveValue);
4889
4955
  return /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
4890
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Monitor interval" }),
4956
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Monitor interval" }),
4891
4957
  /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
4892
4958
  "Your monitor will be checked every ",
4893
4959
  /* @__PURE__ */ jsx("strong", { children: format(effectiveValue) }),
@@ -4934,7 +5000,7 @@ function MonitorIntervalSlider({
4934
5000
  style: {
4935
5001
  left: `${pos}%`,
4936
5002
  transform: "translateX(-50%)",
4937
- fontSize: 11,
5003
+ fontSize: 10,
4938
5004
  color: disabled ? "#C0C0CF" : "#666687",
4939
5005
  cursor: disabled ? "not-allowed" : "default"
4940
5006
  },
@@ -4985,7 +5051,7 @@ function IntervalSlider({
4985
5051
  const safeValue = Math.max(value, minAllowedSeconds);
4986
5052
  const sliderPercent = secondsToSlider(safeValue);
4987
5053
  return /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
4988
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Monitor interval" }),
5054
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Monitor interval" }),
4989
5055
  /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
4990
5056
  "Your monitor will be checked every ",
4991
5057
  /* @__PURE__ */ jsx("strong", { children: formatSeconds(safeValue) }),
@@ -5145,7 +5211,7 @@ function AdvancedSettings({
5145
5211
  }
5146
5212
  fetchUser();
5147
5213
  }, []);
5148
- const getPercent = (value) => (value - 6) / 55 * 100;
5214
+ const getPercent = (value) => (value - 5) / 55 * 100;
5149
5215
  return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsxs(Accordion.Item, { value: "advanced-settings", children: [
5150
5216
  /* @__PURE__ */ jsx(Accordion.Header, { children: /* @__PURE__ */ jsx(
5151
5217
  Accordion.Trigger,
@@ -5156,7 +5222,7 @@ function AdvancedSettings({
5156
5222
  }
5157
5223
  ) }),
5158
5224
  /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 6, width: "100%", alignItems: "flex-start", children: [
5159
- /* @__PURE__ */ jsxs(Box, { maxWidth: "60%", children: [
5225
+ /* @__PURE__ */ jsxs(Box, { maxWidth: "60%", paddingLeft: 4, children: [
5160
5226
  /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Request timeout" }),
5161
5227
  /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
5162
5228
  "The request timeout is ",
@@ -5209,7 +5275,7 @@ function AdvancedSettings({
5209
5275
  value
5210
5276
  )) })
5211
5277
  ] }),
5212
- /* @__PURE__ */ jsxs(Box, { children: [
5278
+ /* @__PURE__ */ jsxs(Box, { paddingLeft: 6, children: [
5213
5279
  /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
5214
5280
  /* @__PURE__ */ jsx(
5215
5281
  Switch,
@@ -5220,12 +5286,12 @@ function AdvancedSettings({
5220
5286
  }
5221
5287
  }
5222
5288
  ),
5223
- /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Follow redirection" })
5289
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Follow redirection" })
5224
5290
  ] }),
5225
5291
  /* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "If disabled, we return redirection HTTP codes (3xx)." }) })
5226
5292
  ] }),
5227
- /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
5228
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", fontWeight: "bold", children: "Healthcheck settings" }),
5293
+ /* @__PURE__ */ jsxs(Box, { width: "100%", paddingLeft: 5, children: [
5294
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Healthcheck settings" }),
5229
5295
  /* @__PURE__ */ jsx(Box, { paddingTop: 4, children: /* @__PURE__ */ jsxs(Flex, { gap: 6, wrap: "wrap", direction: { initial: "column", medium: "row" }, children: [
5230
5296
  /* @__PURE__ */ jsx(Box, { width: { initial: "100%", medium: "48%" }, children: /* @__PURE__ */ jsx(
5231
5297
  HealthcheckServiceBlock,
@@ -5526,67 +5592,51 @@ function NotificationChannelsIntegration({
5526
5592
  ] }) }) })
5527
5593
  ] }) }) });
5528
5594
  }
5529
- const RegionsMultiSelect = ({
5530
- selectedRegionIds,
5531
- onRegionsChange,
5532
- placeholder = "Select regions...",
5533
- primaryRegionId,
5534
- onPrimaryRegionChange
5595
+ const TagMultiSelect = ({
5596
+ selectedTagIds,
5597
+ onTagsChange,
5598
+ placeholder = "Select or create tags...",
5599
+ apiEndpoint = "/tags"
5535
5600
  }) => {
5536
5601
  const [isOpen, setIsOpen] = useState(false);
5537
5602
  const [searchInput, setSearchInput] = useState("");
5538
- const [availableRegions, setAvailableRegions] = useState([]);
5603
+ const [availableTags, setAvailableTags] = useState([]);
5539
5604
  const [isLoading, setIsLoading] = useState(false);
5540
- const [isTrialUser, setIsTrialUser] = useState(false);
5605
+ const [isCreating, setIsCreating] = useState(false);
5541
5606
  const dropdownRef = useRef(null);
5542
5607
  const inputRef = useRef(null);
5543
5608
  useEffect(() => {
5544
- fetchRegions();
5609
+ fetchTags(setIsLoading, setAvailableTags);
5545
5610
  }, []);
5546
- const fetchRegions = async () => {
5547
- setIsLoading(true);
5611
+ const createTag = async (tagName) => {
5612
+ setIsCreating(true);
5548
5613
  try {
5549
- let userDetails = await getUserDetailsCached();
5550
- if (!userDetails) {
5551
- userDetails = await getUserDetails();
5552
- }
5553
- const isTrial = userDetails?.user?.subscription_type === PLAN_TYPES.TRIAL;
5554
- setIsTrialUser(isTrial);
5555
- const result = await request("/regions", {
5556
- method: "GET"
5614
+ const result = await request(apiEndpoint, {
5615
+ method: "POST",
5616
+ data: {
5617
+ name: tagName,
5618
+ color: generateRandomColor()
5619
+ }
5557
5620
  });
5558
- if (!result) return;
5559
- if (!result) {
5560
- throw new Error("Failed to fetch regions");
5561
- }
5562
- const regions = result.regionsData.data.slice();
5563
- const defaultIndex = regions.findIndex((r) => r.id === DEFAULT_REGION.id);
5564
- if (defaultIndex > 0) {
5565
- const [defaultRegion] = regions.splice(defaultIndex, 1);
5566
- regions.unshift(defaultRegion);
5567
- }
5568
- setAvailableRegions(regions);
5621
+ if (!result?.tagsData) return null;
5622
+ const newTag = result?.tagsData?.data;
5623
+ setAvailableTags((prev) => [...prev, newTag]);
5624
+ return newTag;
5569
5625
  } catch (error) {
5570
- console.error("Error fetching regions:", error);
5626
+ console.error("Error creating tag:", error);
5627
+ return null;
5571
5628
  } finally {
5572
- setIsLoading(false);
5629
+ setIsCreating(false);
5573
5630
  }
5574
5631
  };
5575
- const selectedRegions = availableRegions.filter(
5576
- (region) => selectedRegionIds.includes(String(region.id))
5632
+ const selectedTags = availableTags.filter((tag) => selectedTagIds.includes(String(tag.id)));
5633
+ const filteredTags = availableTags.filter(
5634
+ (tag) => tag.name.toLowerCase().includes(searchInput.toLowerCase())
5577
5635
  );
5578
- const filteredRegions = availableRegions.filter(
5579
- (region) => region.name.toLowerCase().includes(searchInput.toLowerCase())
5636
+ const exactMatch = availableTags.find(
5637
+ (tag) => tag.name.toLowerCase() === searchInput.toLowerCase()
5580
5638
  );
5581
- const handleSetPrimary = (regionId) => {
5582
- if (isTrialUser && regionId !== DEFAULT_REGION.id) {
5583
- return;
5584
- }
5585
- if (!selectedRegionIds.includes(regionId)) {
5586
- onRegionsChange([...selectedRegionIds, regionId]);
5587
- }
5588
- onPrimaryRegionChange?.(regionId);
5589
- };
5639
+ const showCreateOption = searchInput.trim() && !exactMatch;
5590
5640
  useEffect(() => {
5591
5641
  const handleClickOutside = (event) => {
5592
5642
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -5597,41 +5647,46 @@ const RegionsMultiSelect = ({
5597
5647
  document.addEventListener("mousedown", handleClickOutside);
5598
5648
  return () => document.removeEventListener("mousedown", handleClickOutside);
5599
5649
  }, []);
5600
- const handleToggleRegion = (regionId) => {
5601
- if (isTrialUser && regionId !== DEFAULT_REGION.id) {
5602
- return;
5603
- }
5604
- if (selectedRegionIds.includes(regionId)) {
5605
- const updated = selectedRegionIds.filter((id) => id !== regionId);
5606
- onRegionsChange(updated);
5607
- if (primaryRegionId === regionId) {
5608
- onPrimaryRegionChange?.(updated[0] ?? null);
5609
- }
5650
+ const handleToggleTag = (tagId) => {
5651
+ const idStr = String(tagId);
5652
+ if (selectedTagIds.includes(idStr)) {
5653
+ onTagsChange(selectedTagIds.filter((id) => id !== idStr));
5610
5654
  } else {
5611
- onRegionsChange([...selectedRegionIds, regionId]);
5655
+ onTagsChange([...selectedTagIds, idStr]);
5612
5656
  }
5613
5657
  };
5614
- const handleRemoveRegion = (regionId, e) => {
5658
+ const handleRemoveTag = (tagId, e) => {
5615
5659
  e?.stopPropagation();
5616
- const updated = selectedRegionIds.filter((id) => id !== regionId);
5617
- onRegionsChange(updated);
5618
- if (primaryRegionId === regionId) {
5619
- onPrimaryRegionChange?.(updated[0] ?? null);
5660
+ const idStr = String(tagId);
5661
+ onTagsChange(selectedTagIds.filter((id) => id !== idStr));
5662
+ };
5663
+ const handleCreateTag = async () => {
5664
+ if (!searchInput.trim() || isCreating) return;
5665
+ const newTag = await createTag(searchInput.trim());
5666
+ if (newTag) {
5667
+ onTagsChange([...selectedTagIds, String(newTag.id)]);
5668
+ setSearchInput("");
5669
+ inputRef.current?.focus();
5620
5670
  }
5621
5671
  };
5622
5672
  const handleKeyDown = (e) => {
5623
- if (e.key === "Enter" && filteredRegions.length === 1) {
5624
- handleToggleRegion(filteredRegions[0].id);
5625
- setSearchInput("");
5626
- } else if (e.key === "Backspace" && !searchInput && selectedRegions.length > 0) {
5627
- handleRemoveRegion(selectedRegions[selectedRegions.length - 1].id);
5673
+ if (e.key === "Enter") {
5674
+ e.preventDefault();
5675
+ if (showCreateOption) {
5676
+ handleCreateTag();
5677
+ } else if (filteredTags.length === 1) {
5678
+ handleToggleTag(filteredTags[0].id);
5679
+ setSearchInput("");
5680
+ }
5681
+ } else if (e.key === "Backspace" && !searchInput && selectedTags.length > 0) {
5682
+ handleRemoveTag(selectedTags[selectedTags.length - 1].id);
5628
5683
  }
5629
5684
  };
5630
5685
  return /* @__PURE__ */ jsxs(Box, { position: "relative", ref: dropdownRef, width: "100%", children: [
5631
5686
  /* @__PURE__ */ jsx(
5632
5687
  Box,
5633
5688
  {
5634
- padding: 3,
5689
+ padding: 2,
5635
5690
  borderColor: isOpen ? "primary200" : "neutral200",
5636
5691
  background: "neutral0",
5637
5692
  hasRadius: true,
@@ -5643,39 +5698,291 @@ const RegionsMultiSelect = ({
5643
5698
  width: "100%",
5644
5699
  children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [
5645
5700
  /* @__PURE__ */ jsxs(Flex, { wrap: "wrap", gap: 2, flex: "1", width: "100%", children: [
5646
- selectedRegions.map((region) => {
5647
- const isPrimary = primaryRegionId === region.id;
5648
- return /* @__PURE__ */ jsxs(
5649
- Flex,
5650
- {
5651
- gap: 1,
5652
- padding: 1,
5653
- background: "primary100",
5654
- borderColor: "primary200",
5655
- hasRadius: true,
5656
- alignItems: "center",
5657
- children: [
5658
- /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "primary700", children: region.name || region.id }),
5659
- isPrimary && /* @__PURE__ */ jsx(Badge, { background: "warning100", textColor: "warning700", children: "Primary" }),
5660
- /* @__PURE__ */ jsx(
5661
- IconButton,
5662
- {
5663
- label: "Remove region",
5664
- onClick: (e) => handleRemoveRegion(region.id, e),
5665
- size: "S",
5666
- variant: "ghost",
5667
- children: /* @__PURE__ */ jsx(Cross, {})
5668
- }
5669
- )
5670
- ]
5671
- },
5672
- region.id
5673
- );
5674
- }),
5675
- isOpen && /* @__PURE__ */ jsx(Box, { width: "70%", children: /* @__PURE__ */ jsx(
5676
- TextInput,
5701
+ selectedTags.map((tag) => /* @__PURE__ */ jsxs(
5702
+ Flex,
5677
5703
  {
5678
- ref: inputRef,
5704
+ gap: 1,
5705
+ padding: 1,
5706
+ hasRadius: true,
5707
+ alignItems: "center",
5708
+ style: {
5709
+ backgroundColor: `${tag.color}20`,
5710
+ border: `1px solid ${tag.color}40`
5711
+ },
5712
+ children: [
5713
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", style: { color: tag.color }, children: formatTitleToUppercase(tag.name) }),
5714
+ /* @__PURE__ */ jsx(
5715
+ IconButton,
5716
+ {
5717
+ label: "Remove tag",
5718
+ onClick: (e) => handleRemoveTag(tag.id, e),
5719
+ size: "S",
5720
+ variant: "ghost",
5721
+ children: /* @__PURE__ */ jsx(Cross, {})
5722
+ }
5723
+ )
5724
+ ]
5725
+ },
5726
+ tag.id
5727
+ )),
5728
+ isOpen && /* @__PURE__ */ jsx(Box, { width: "70%", children: /* @__PURE__ */ jsx(
5729
+ TextInput,
5730
+ {
5731
+ ref: inputRef,
5732
+ value: searchInput,
5733
+ onChange: (e) => setSearchInput(e.target.value),
5734
+ onKeyDown: handleKeyDown,
5735
+ onFocus: () => setIsOpen(true),
5736
+ placeholder: selectedTags.length === 0 ? placeholder : "",
5737
+ disabled: isLoading,
5738
+ startAction: /* @__PURE__ */ jsx(Search, {}),
5739
+ size: "M"
5740
+ }
5741
+ ) })
5742
+ ] }),
5743
+ /* @__PURE__ */ jsx(
5744
+ IconButton,
5745
+ {
5746
+ label: "Toggle dropdown",
5747
+ onClick: (e) => {
5748
+ e.stopPropagation();
5749
+ setIsOpen(!isOpen);
5750
+ },
5751
+ variant: "ghost",
5752
+ children: /* @__PURE__ */ jsx(ChevronDown, {})
5753
+ }
5754
+ )
5755
+ ] })
5756
+ }
5757
+ ),
5758
+ isOpen && /* @__PURE__ */ jsx(
5759
+ Box,
5760
+ {
5761
+ position: "absolute",
5762
+ zIndex: 2,
5763
+ width: "100%",
5764
+ marginTop: 2,
5765
+ background: "neutral0",
5766
+ borderColor: "neutral200",
5767
+ hasRadius: true,
5768
+ shadow: "tableShadow",
5769
+ maxHeight: "240px",
5770
+ overflow: "auto",
5771
+ children: isLoading ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "Loading tags…" }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5772
+ filteredTags.length > 0 ? filteredTags.map((tag) => {
5773
+ const isSelected = selectedTagIds.includes(String(tag.id));
5774
+ return /* @__PURE__ */ jsxs(
5775
+ Flex,
5776
+ {
5777
+ padding: 3,
5778
+ gap: 3,
5779
+ alignItems: "center",
5780
+ background: isSelected ? "primary100" : "neutral0",
5781
+ style: { cursor: "pointer" },
5782
+ onClick: () => handleToggleTag(tag.id),
5783
+ children: [
5784
+ /* @__PURE__ */ jsx(
5785
+ Checkbox,
5786
+ {
5787
+ checked: isSelected,
5788
+ onCheckedChange: () => handleToggleTag(tag.id)
5789
+ }
5790
+ ),
5791
+ /* @__PURE__ */ jsx(
5792
+ "div",
5793
+ {
5794
+ style: {
5795
+ width: "12px",
5796
+ height: "12px",
5797
+ borderRadius: "50%",
5798
+ backgroundColor: tag.color
5799
+ }
5800
+ }
5801
+ ),
5802
+ /* @__PURE__ */ jsx(Typography, { flex: "1", children: formatTitleToUppercase(tag.name) })
5803
+ ]
5804
+ },
5805
+ tag.id
5806
+ );
5807
+ }) : searchInput ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "No tags found" }) }) : null,
5808
+ showCreateOption && /* @__PURE__ */ jsx(
5809
+ Box,
5810
+ {
5811
+ style: {
5812
+ borderTop: "1px solid #D0D3E0"
5813
+ },
5814
+ children: /* @__PURE__ */ jsx(
5815
+ Button,
5816
+ {
5817
+ variant: "ghost",
5818
+ fullWidth: true,
5819
+ onClick: handleCreateTag,
5820
+ disabled: isCreating,
5821
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
5822
+ style: {
5823
+ justifyContent: "flex-start",
5824
+ padding: "12px 16px"
5825
+ },
5826
+ children: isCreating ? "Creating..." : `Create "${searchInput}"`
5827
+ }
5828
+ )
5829
+ }
5830
+ )
5831
+ ] })
5832
+ }
5833
+ )
5834
+ ] });
5835
+ };
5836
+ const RegionsMultiSelect = ({
5837
+ selectedRegionIds,
5838
+ onRegionsChange,
5839
+ placeholder = "Select regions...",
5840
+ primaryRegionId,
5841
+ onPrimaryRegionChange
5842
+ }) => {
5843
+ const [isOpen, setIsOpen] = useState(false);
5844
+ const [searchInput, setSearchInput] = useState("");
5845
+ const [availableRegions, setAvailableRegions] = useState([]);
5846
+ const [isLoading, setIsLoading] = useState(false);
5847
+ const [isTrialUser, setIsTrialUser] = useState(false);
5848
+ const dropdownRef = useRef(null);
5849
+ const inputRef = useRef(null);
5850
+ useEffect(() => {
5851
+ fetchRegions();
5852
+ }, []);
5853
+ const fetchRegions = async () => {
5854
+ setIsLoading(true);
5855
+ try {
5856
+ let userDetails = await getUserDetailsCached();
5857
+ if (!userDetails) {
5858
+ userDetails = await getUserDetails();
5859
+ }
5860
+ const isTrial = userDetails?.user?.subscription_type === PLAN_TYPES.TRIAL;
5861
+ setIsTrialUser(isTrial);
5862
+ const result = await request("/regions", {
5863
+ method: "GET"
5864
+ });
5865
+ if (!result) return;
5866
+ if (!result) {
5867
+ throw new Error("Failed to fetch regions");
5868
+ }
5869
+ const regions = result.regionsData.data.slice();
5870
+ const defaultIndex = regions.findIndex((r) => r.id === DEFAULT_REGION.id);
5871
+ if (defaultIndex > 0) {
5872
+ const [defaultRegion] = regions.splice(defaultIndex, 1);
5873
+ regions.unshift(defaultRegion);
5874
+ }
5875
+ setAvailableRegions(regions);
5876
+ } catch (error) {
5877
+ console.error("Error fetching regions:", error);
5878
+ } finally {
5879
+ setIsLoading(false);
5880
+ }
5881
+ };
5882
+ const selectedRegions = availableRegions.filter(
5883
+ (region) => selectedRegionIds.includes(String(region.id))
5884
+ );
5885
+ const filteredRegions = availableRegions.filter(
5886
+ (region) => region.name.toLowerCase().includes(searchInput.toLowerCase())
5887
+ );
5888
+ const handleSetPrimary = (regionId) => {
5889
+ if (isTrialUser && regionId !== DEFAULT_REGION.id) {
5890
+ return;
5891
+ }
5892
+ if (!selectedRegionIds.includes(regionId)) {
5893
+ onRegionsChange([...selectedRegionIds, regionId]);
5894
+ }
5895
+ onPrimaryRegionChange?.(regionId);
5896
+ };
5897
+ useEffect(() => {
5898
+ const handleClickOutside = (event) => {
5899
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
5900
+ setIsOpen(false);
5901
+ setSearchInput("");
5902
+ }
5903
+ };
5904
+ document.addEventListener("mousedown", handleClickOutside);
5905
+ return () => document.removeEventListener("mousedown", handleClickOutside);
5906
+ }, []);
5907
+ const handleToggleRegion = (regionId) => {
5908
+ if (isTrialUser && regionId !== DEFAULT_REGION.id) {
5909
+ return;
5910
+ }
5911
+ if (selectedRegionIds.includes(regionId)) {
5912
+ const updated = selectedRegionIds.filter((id) => id !== regionId);
5913
+ onRegionsChange(updated);
5914
+ if (primaryRegionId === regionId) {
5915
+ onPrimaryRegionChange?.(updated[0] ?? null);
5916
+ }
5917
+ } else {
5918
+ onRegionsChange([...selectedRegionIds, regionId]);
5919
+ }
5920
+ };
5921
+ const handleRemoveRegion = (regionId, e) => {
5922
+ e?.stopPropagation();
5923
+ const updated = selectedRegionIds.filter((id) => id !== regionId);
5924
+ onRegionsChange(updated);
5925
+ if (primaryRegionId === regionId) {
5926
+ onPrimaryRegionChange?.(updated[0] ?? null);
5927
+ }
5928
+ };
5929
+ const handleKeyDown = (e) => {
5930
+ if (e.key === "Enter" && filteredRegions.length === 1) {
5931
+ handleToggleRegion(filteredRegions[0].id);
5932
+ setSearchInput("");
5933
+ } else if (e.key === "Backspace" && !searchInput && selectedRegions.length > 0) {
5934
+ handleRemoveRegion(selectedRegions[selectedRegions.length - 1].id);
5935
+ }
5936
+ };
5937
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", ref: dropdownRef, width: "100%", children: [
5938
+ /* @__PURE__ */ jsx(
5939
+ Box,
5940
+ {
5941
+ padding: 3,
5942
+ borderColor: isOpen ? "primary200" : "neutral200",
5943
+ background: "neutral0",
5944
+ hasRadius: true,
5945
+ style: { cursor: "text" },
5946
+ onClick: () => {
5947
+ setIsOpen(true);
5948
+ inputRef.current?.focus();
5949
+ },
5950
+ width: "100%",
5951
+ children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [
5952
+ /* @__PURE__ */ jsxs(Flex, { wrap: "wrap", gap: 2, flex: "1", width: "100%", children: [
5953
+ selectedRegions.map((region) => {
5954
+ const isPrimary = primaryRegionId === region.id;
5955
+ return /* @__PURE__ */ jsxs(
5956
+ Flex,
5957
+ {
5958
+ gap: 1,
5959
+ padding: 1,
5960
+ background: "primary100",
5961
+ borderColor: "primary200",
5962
+ hasRadius: true,
5963
+ alignItems: "center",
5964
+ children: [
5965
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "primary700", children: region.name || region.id }),
5966
+ isPrimary && /* @__PURE__ */ jsx(Badge, { background: "warning100", textColor: "warning700", children: "Primary" }),
5967
+ /* @__PURE__ */ jsx(
5968
+ IconButton,
5969
+ {
5970
+ label: "Remove region",
5971
+ onClick: (e) => handleRemoveRegion(region.id, e),
5972
+ size: "S",
5973
+ variant: "ghost",
5974
+ children: /* @__PURE__ */ jsx(Cross, {})
5975
+ }
5976
+ )
5977
+ ]
5978
+ },
5979
+ region.id
5980
+ );
5981
+ }),
5982
+ isOpen && /* @__PURE__ */ jsx(Box, { width: "70%", children: /* @__PURE__ */ jsx(
5983
+ TextInput,
5984
+ {
5985
+ ref: inputRef,
5679
5986
  value: searchInput,
5680
5987
  onChange: (e) => setSearchInput(e.target.value),
5681
5988
  onKeyDown: handleKeyDown,
@@ -5685,98 +5992,524 @@ const RegionsMultiSelect = ({
5685
5992
  startAction: /* @__PURE__ */ jsx(Search, {}),
5686
5993
  size: "M"
5687
5994
  }
5688
- ) })
5689
- ] }),
5690
- /* @__PURE__ */ jsx(
5691
- IconButton,
5692
- {
5693
- label: "Toggle dropdown",
5694
- onClick: (e) => {
5695
- e.stopPropagation();
5696
- setIsOpen(!isOpen);
5697
- },
5698
- variant: "ghost",
5699
- children: /* @__PURE__ */ jsx(ChevronDown, {})
5700
- }
5701
- )
5702
- ] })
5995
+ ) })
5996
+ ] }),
5997
+ /* @__PURE__ */ jsx(
5998
+ IconButton,
5999
+ {
6000
+ label: "Toggle dropdown",
6001
+ onClick: (e) => {
6002
+ e.stopPropagation();
6003
+ setIsOpen(!isOpen);
6004
+ },
6005
+ variant: "ghost",
6006
+ children: /* @__PURE__ */ jsx(ChevronDown, {})
6007
+ }
6008
+ )
6009
+ ] })
6010
+ }
6011
+ ),
6012
+ isOpen && /* @__PURE__ */ jsx(
6013
+ Box,
6014
+ {
6015
+ position: "absolute",
6016
+ zIndex: 2,
6017
+ width: "100%",
6018
+ marginTop: 2,
6019
+ background: "neutral0",
6020
+ borderColor: "neutral200",
6021
+ hasRadius: true,
6022
+ shadow: "tableShadow",
6023
+ maxHeight: "240px",
6024
+ overflow: "auto",
6025
+ children: isLoading ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "Loading regions…" }) }) : /* @__PURE__ */ jsx(Fragment, { children: filteredRegions.length > 0 ? filteredRegions.map((region) => {
6026
+ const isSelected = selectedRegionIds.includes(String(region.id));
6027
+ const isPrimary = primaryRegionId === region.id;
6028
+ const isDisabled = isTrialUser && region.id !== DEFAULT_REGION.id;
6029
+ return isDisabled ? /* @__PURE__ */ jsx(
6030
+ Tooltip,
6031
+ {
6032
+ description: "Upgrade to a paid plan to enable global monitoring.",
6033
+ children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(
6034
+ Flex,
6035
+ {
6036
+ padding: 3,
6037
+ gap: 3,
6038
+ alignItems: "center",
6039
+ background: isSelected ? "primary100" : "neutral0",
6040
+ style: {
6041
+ cursor: "not-allowed",
6042
+ opacity: 0.5
6043
+ },
6044
+ children: [
6045
+ /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, disabled: true }),
6046
+ /* @__PURE__ */ jsx(Typography, { flex: "1", children: region.name || region.id }),
6047
+ /* @__PURE__ */ jsx(Checkbox, { checked: isPrimary, disabled: true, children: "Primary" })
6048
+ ]
6049
+ }
6050
+ ) })
6051
+ },
6052
+ region.id
6053
+ ) : /* @__PURE__ */ jsxs(
6054
+ Flex,
6055
+ {
6056
+ padding: 3,
6057
+ gap: 3,
6058
+ alignItems: "center",
6059
+ background: isSelected ? "primary100" : "neutral0",
6060
+ style: { cursor: "pointer" },
6061
+ children: [
6062
+ /* @__PURE__ */ jsx(
6063
+ Checkbox,
6064
+ {
6065
+ checked: isSelected,
6066
+ onChange: () => handleToggleRegion(region.id)
6067
+ }
6068
+ ),
6069
+ /* @__PURE__ */ jsx(Typography, { flex: "1", children: region.name || region.id }),
6070
+ /* @__PURE__ */ jsx(Checkbox, { checked: isPrimary, onChange: () => handleSetPrimary(region.id), children: "Primary" })
6071
+ ]
6072
+ },
6073
+ region.id
6074
+ );
6075
+ }) : searchInput ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "No regions found" }) }) : null })
6076
+ }
6077
+ )
6078
+ ] });
6079
+ };
6080
+ function PortAdvancedSettings({
6081
+ timeout,
6082
+ onTimeoutChange,
6083
+ monitorInterval,
6084
+ onMonitorIntervalChange
6085
+ }) {
6086
+ const min = 5;
6087
+ const max = 60;
6088
+ const [minMonitoringInterval, setMinMonitoringInterval] = useState(60);
6089
+ const [userPlan, setUserPlan] = useState(PLAN_TYPES.TRIAL);
6090
+ useEffect(() => {
6091
+ async function fetchUser() {
6092
+ try {
6093
+ const details = await getUserDetailsCached(true);
6094
+ const userMinMonitoringIntervalInMins = details?.plan_limits?.min_monitoring_interval;
6095
+ setMinMonitoringInterval(
6096
+ userMinMonitoringIntervalInMins ? userMinMonitoringIntervalInMins * 60 : 60
6097
+ );
6098
+ setUserPlan(details?.user?.subscription_type || PLAN_TYPES.TRIAL);
6099
+ } catch (error) {
6100
+ console.error("Failed to fetch user details in PortAdvancedSettings", error);
6101
+ }
6102
+ }
6103
+ fetchUser();
6104
+ }, []);
6105
+ const getPercent = (value) => (value - min) / (max - min) * 100;
6106
+ return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsxs(Accordion.Item, { value: "port-advanced-settings", children: [
6107
+ /* @__PURE__ */ jsx(Accordion.Header, { children: /* @__PURE__ */ jsx(
6108
+ Accordion.Trigger,
6109
+ {
6110
+ caretPosition: "right",
6111
+ description: "Configure monitor interval and connection timeout",
6112
+ children: "Advanced settings"
6113
+ }
6114
+ ) }),
6115
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(
6116
+ Flex,
6117
+ {
6118
+ paddingLeft: 6,
6119
+ paddingTop: 4,
6120
+ paddingBottom: 8,
6121
+ direction: "column",
6122
+ gap: 6,
6123
+ width: "100%",
6124
+ alignItems: "flex-start",
6125
+ children: /* @__PURE__ */ jsxs(Flex, { direction: { initial: "column", medium: "row" }, gap: 6, width: "100%", children: [
6126
+ /* @__PURE__ */ jsx(Box, { width: { initial: "100%", medium: "48%" }, children: /* @__PURE__ */ jsx(
6127
+ MonitorIntervalSlider,
6128
+ {
6129
+ value: monitorInterval,
6130
+ onChange: onMonitorIntervalChange,
6131
+ minSeconds: 60,
6132
+ maxSeconds: 86400,
6133
+ minMonitoringInterval,
6134
+ userPlan
6135
+ }
6136
+ ) }),
6137
+ /* @__PURE__ */ jsxs(Box, { width: { initial: "100%", medium: "48%" }, children: [
6138
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Connection timeout" }),
6139
+ /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
6140
+ "The connection timeout is ",
6141
+ /* @__PURE__ */ jsxs("strong", { children: [
6142
+ timeout,
6143
+ " seconds"
6144
+ ] }),
6145
+ "."
6146
+ ] }) }),
6147
+ /* @__PURE__ */ jsx(
6148
+ "input",
6149
+ {
6150
+ type: "range",
6151
+ min,
6152
+ max,
6153
+ step: "1",
6154
+ value: timeout,
6155
+ onChange: (e) => onTimeoutChange(parseInt(e.target.value)),
6156
+ style: {
6157
+ width: "100%",
6158
+ height: 6,
6159
+ borderRadius: 4,
6160
+ appearance: "none",
6161
+ cursor: "pointer",
6162
+ background: `linear-gradient(
6163
+ to right,
6164
+ #4945FF 0%,
6165
+ #4945FF ${getPercent(timeout)}%,
6166
+ #EAEAEA ${getPercent(timeout)}%,
6167
+ #EAEAEA 100%
6168
+ )`
6169
+ }
6170
+ }
6171
+ ),
6172
+ /* @__PURE__ */ jsx(Box, { position: "relative", paddingTop: 3, height: 20, children: [5, 15, 30, 45, 60].map((value) => /* @__PURE__ */ jsxs(
6173
+ Box,
6174
+ {
6175
+ position: "absolute",
6176
+ style: {
6177
+ left: `${getPercent(value)}%`,
6178
+ transform: "translateX(-50%)",
6179
+ fontSize: 10,
6180
+ color: "#666687"
6181
+ },
6182
+ children: [
6183
+ value,
6184
+ "s"
6185
+ ]
6186
+ },
6187
+ value
6188
+ )) })
6189
+ ] })
6190
+ ] })
6191
+ }
6192
+ ) })
6193
+ ] }) }) });
6194
+ }
6195
+ function KeywordInput({
6196
+ keywords,
6197
+ onKeywordsChange,
6198
+ error,
6199
+ matchAll,
6200
+ onMatchAllChange
6201
+ }) {
6202
+ const [keywordInput, setKeywordInput] = useState("");
6203
+ const handleAddKeyword = () => {
6204
+ const trimmedInput = keywordInput.trim();
6205
+ if (!trimmedInput) return;
6206
+ const newKeyword = {
6207
+ text: trimmedInput,
6208
+ type: "must_contain",
6209
+ case_sensitive: false,
6210
+ is_regex: false
6211
+ };
6212
+ onKeywordsChange([...keywords, newKeyword]);
6213
+ setKeywordInput("");
6214
+ };
6215
+ const handleRemoveKeyword = (indexToRemove) => {
6216
+ onKeywordsChange(keywords.filter((_, index) => index !== indexToRemove));
6217
+ };
6218
+ const handleKeywordChange = (index, field, value) => {
6219
+ const updatedKeywords = [...keywords];
6220
+ updatedKeywords[index] = {
6221
+ ...updatedKeywords[index],
6222
+ [field]: value
6223
+ };
6224
+ onKeywordsChange(updatedKeywords);
6225
+ };
6226
+ const handleKeyPress = (e) => {
6227
+ if (e.key === "Enter") {
6228
+ e.preventDefault();
6229
+ handleAddKeyword();
6230
+ }
6231
+ };
6232
+ return /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
6233
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 4, children: [
6234
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", justifyContent: "space-between", marginBottom: 2, children: [
6235
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Keywords / Text" }),
6236
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
6237
+ /* @__PURE__ */ jsx(
6238
+ Switch,
6239
+ {
6240
+ checked: matchAll,
6241
+ onCheckedChange: (checked) => onMatchAllChange(checked)
6242
+ }
6243
+ ),
6244
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "500", children: "Match All Keywords" })
6245
+ ] })
6246
+ ] }),
6247
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
6248
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(
6249
+ TextInput,
6250
+ {
6251
+ type: "text",
6252
+ placeholder: "Enter keyword",
6253
+ value: keywordInput,
6254
+ onChange: (e) => setKeywordInput(e.target.value),
6255
+ onKeyDown: handleKeyPress
6256
+ }
6257
+ ) }),
6258
+ /* @__PURE__ */ jsx(Button, { disabled: !keywordInput.trim(), onClick: handleAddKeyword, children: "Add" })
6259
+ ] }),
6260
+ error && /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "danger600", children: error }) })
6261
+ ] }),
6262
+ keywords.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
6263
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "beta", fontWeight: "bold", marginBottom: 3, children: [
6264
+ "Added Keywords (",
6265
+ keywords.length,
6266
+ ")"
6267
+ ] }) }),
6268
+ /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, width: "800px", children: keywords.map((keyword, index) => /* @__PURE__ */ jsxs(
6269
+ Box,
6270
+ {
6271
+ padding: 4,
6272
+ borderColor: "neutral200",
6273
+ hasRadius: true,
6274
+ borderRadius: 2,
6275
+ width: "800px",
6276
+ children: [
6277
+ /* @__PURE__ */ jsxs(
6278
+ Flex,
6279
+ {
6280
+ alignItems: "flex-start",
6281
+ justifyContent: "space-between",
6282
+ gap: 3,
6283
+ marginBottom: 4,
6284
+ children: [
6285
+ /* @__PURE__ */ jsxs(Box, { children: [
6286
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", marginBottom: 1, children: "Keyword" }) }),
6287
+ /* @__PURE__ */ jsx(
6288
+ Box,
6289
+ {
6290
+ style: {
6291
+ fontFamily: "monospace",
6292
+ fontSize: "14px",
6293
+ backgroundColor: "#F2F4F7",
6294
+ padding: "6px 12px",
6295
+ borderRadius: "4px",
6296
+ color: "#32324D",
6297
+ wordBreak: "break-all"
6298
+ },
6299
+ children: keyword.text
6300
+ }
6301
+ )
6302
+ ] }),
6303
+ /* @__PURE__ */ jsx(
6304
+ Button,
6305
+ {
6306
+ style: {
6307
+ padding: "0",
6308
+ minWidth: "32px",
6309
+ width: "32px",
6310
+ height: "32px"
6311
+ },
6312
+ variant: "tertiary",
6313
+ onClick: () => handleRemoveKeyword(index),
6314
+ title: "Remove keyword",
6315
+ children: /* @__PURE__ */ jsx(Trash, {})
6316
+ }
6317
+ )
6318
+ ]
6319
+ }
6320
+ ),
6321
+ /* @__PURE__ */ jsxs(
6322
+ Flex,
6323
+ {
6324
+ direction: { initial: "column", medium: "row" },
6325
+ gap: 5,
6326
+ alignItems: "flex-end",
6327
+ children: [
6328
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsxs(
6329
+ SingleSelect,
6330
+ {
6331
+ value: keyword.type,
6332
+ onChange: (value) => {
6333
+ handleKeywordChange(
6334
+ index,
6335
+ "type",
6336
+ value
6337
+ );
6338
+ },
6339
+ children: [
6340
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "must_contain", children: "Start incident when keyword exists" }),
6341
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "must_not_contain", children: "Start incident when keyword does not exist" })
6342
+ ]
6343
+ }
6344
+ ) }),
6345
+ /* @__PURE__ */ jsxs(Box, { flex: 1, children: [
6346
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, marginBottom: 2, children: [
6347
+ /* @__PURE__ */ jsx(
6348
+ Switch,
6349
+ {
6350
+ checked: keyword.is_regex,
6351
+ onCheckedChange: (checked) => handleKeywordChange(index, "is_regex", checked)
6352
+ }
6353
+ ),
6354
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "500", children: "Regex" })
6355
+ ] }),
6356
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Use regular expression matching" })
6357
+ ] }),
6358
+ /* @__PURE__ */ jsxs(Box, { flex: 1, children: [
6359
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, marginBottom: 2, children: [
6360
+ /* @__PURE__ */ jsx(
6361
+ Switch,
6362
+ {
6363
+ checked: keyword.case_sensitive,
6364
+ onCheckedChange: (checked) => handleKeywordChange(index, "case_sensitive", checked)
6365
+ }
6366
+ ),
6367
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "500", children: "Case Sensitive" })
6368
+ ] }),
6369
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Match exact letter case" })
6370
+ ] })
6371
+ ]
6372
+ }
6373
+ )
6374
+ ]
6375
+ },
6376
+ index
6377
+ )) })
6378
+ ] })
6379
+ ] });
6380
+ }
6381
+ function KeywordAdvancedSettings({
6382
+ timeout,
6383
+ onTimeoutChange,
6384
+ followRedirects,
6385
+ onFollowRedirectsChange,
6386
+ monitorInterval,
6387
+ onMonitorIntervalChange
6388
+ }) {
6389
+ const min = 5;
6390
+ const max = 60;
6391
+ const [minMonitoringInterval, setMinMonitoringInterval] = useState(60);
6392
+ const [userPlan, setUserPlan] = useState(PLAN_TYPES.TRIAL);
6393
+ useEffect(() => {
6394
+ async function fetchUser() {
6395
+ try {
6396
+ const details = await getUserDetailsCached(true);
6397
+ const userMinMonitoringIntervalInMins = details?.plan_limits?.min_monitoring_interval;
6398
+ setMinMonitoringInterval(
6399
+ userMinMonitoringIntervalInMins ? userMinMonitoringIntervalInMins * 60 : 60
6400
+ );
6401
+ setUserPlan(details?.user?.subscription_type || PLAN_TYPES.TRIAL);
6402
+ } catch (error) {
6403
+ console.error("Failed to fetch user details in KeywordAdvancedSettings", error);
5703
6404
  }
5704
- ),
5705
- isOpen && /* @__PURE__ */ jsx(
5706
- Box,
6405
+ }
6406
+ fetchUser();
6407
+ }, []);
6408
+ const getPercent = (value) => (value - min) / (max - min) * 100;
6409
+ return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsxs(Accordion.Item, { value: "keyword-advanced-settings", children: [
6410
+ /* @__PURE__ */ jsx(Accordion.Header, { children: /* @__PURE__ */ jsx(
6411
+ Accordion.Trigger,
5707
6412
  {
5708
- position: "absolute",
5709
- zIndex: 2,
6413
+ caretPosition: "right",
6414
+ description: "Configure monitor interval and request timeout",
6415
+ children: "Advanced settings"
6416
+ }
6417
+ ) }),
6418
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(
6419
+ Flex,
6420
+ {
6421
+ paddingLeft: 6,
6422
+ paddingBottom: 8,
6423
+ paddingTop: 4,
6424
+ direction: "column",
6425
+ gap: 6,
5710
6426
  width: "100%",
5711
- marginTop: 2,
5712
- background: "neutral0",
5713
- borderColor: "neutral200",
5714
- hasRadius: true,
5715
- shadow: "tableShadow",
5716
- maxHeight: "240px",
5717
- overflow: "auto",
5718
- children: isLoading ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "Loading regions…" }) }) : /* @__PURE__ */ jsx(Fragment, { children: filteredRegions.length > 0 ? filteredRegions.map((region) => {
5719
- const isSelected = selectedRegionIds.includes(String(region.id));
5720
- const isPrimary = primaryRegionId === region.id;
5721
- const isDisabled = isTrialUser && region.id !== DEFAULT_REGION.id;
5722
- return isDisabled ? /* @__PURE__ */ jsx(
5723
- Tooltip,
5724
- {
5725
- description: "Upgrade to a paid plan to enable global monitoring.",
5726
- children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(
5727
- Flex,
6427
+ alignItems: "flex-start",
6428
+ children: [
6429
+ /* @__PURE__ */ jsxs(Flex, { direction: { initial: "column", medium: "row" }, gap: 6, width: "100%", children: [
6430
+ /* @__PURE__ */ jsx(Box, { width: { initial: "100%", medium: "48%" }, children: /* @__PURE__ */ jsx(
6431
+ MonitorIntervalSlider,
6432
+ {
6433
+ value: monitorInterval,
6434
+ onChange: onMonitorIntervalChange,
6435
+ minSeconds: 60,
6436
+ maxSeconds: 86400,
6437
+ minMonitoringInterval,
6438
+ userPlan
6439
+ }
6440
+ ) }),
6441
+ /* @__PURE__ */ jsxs(Box, { width: { initial: "100%", medium: "48%" }, children: [
6442
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Request timeout" }),
6443
+ /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 3, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
6444
+ "The request timeout is ",
6445
+ /* @__PURE__ */ jsxs("strong", { children: [
6446
+ timeout,
6447
+ " seconds"
6448
+ ] }),
6449
+ "."
6450
+ ] }) }),
6451
+ /* @__PURE__ */ jsx(
6452
+ "input",
5728
6453
  {
5729
- padding: 3,
5730
- gap: 3,
5731
- alignItems: "center",
5732
- background: isSelected ? "primary100" : "neutral0",
6454
+ type: "range",
6455
+ min,
6456
+ max,
6457
+ step: "1",
6458
+ value: timeout,
6459
+ onChange: (e) => onTimeoutChange(parseInt(e.target.value)),
5733
6460
  style: {
5734
- cursor: "not-allowed",
5735
- opacity: 0.5
6461
+ width: "100%",
6462
+ height: 6,
6463
+ borderRadius: 4,
6464
+ appearance: "none",
6465
+ cursor: "pointer",
6466
+ background: `linear-gradient(
6467
+ to right,
6468
+ #4945FF 0%,
6469
+ #4945FF ${getPercent(timeout)}%,
6470
+ #EAEAEA ${getPercent(timeout)}%,
6471
+ #EAEAEA 100%
6472
+ )`
6473
+ }
6474
+ }
6475
+ ),
6476
+ /* @__PURE__ */ jsx(Box, { position: "relative", paddingTop: 3, height: 20, children: [5, 15, 30, 45, 60].map((value) => /* @__PURE__ */ jsxs(
6477
+ Box,
6478
+ {
6479
+ position: "absolute",
6480
+ style: {
6481
+ left: `${getPercent(value)}%`,
6482
+ transform: "translateX(-50%)",
6483
+ fontSize: 10,
6484
+ color: "#666687"
5736
6485
  },
5737
6486
  children: [
5738
- /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, disabled: true }),
5739
- /* @__PURE__ */ jsx(Typography, { flex: "1", children: region.name || region.id }),
5740
- /* @__PURE__ */ jsx(Checkbox, { checked: isPrimary, disabled: true, children: "Primary" })
6487
+ value,
6488
+ "s"
5741
6489
  ]
6490
+ },
6491
+ value
6492
+ )) })
6493
+ ] })
6494
+ ] }),
6495
+ /* @__PURE__ */ jsxs(Box, { children: [
6496
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, marginBottom: 2, children: [
6497
+ /* @__PURE__ */ jsx(
6498
+ Switch,
6499
+ {
6500
+ checked: followRedirects,
6501
+ onCheckedChange: (checked) => onFollowRedirectsChange(checked)
5742
6502
  }
5743
- ) })
5744
- },
5745
- region.id
5746
- ) : /* @__PURE__ */ jsxs(
5747
- Flex,
5748
- {
5749
- padding: 3,
5750
- gap: 3,
5751
- alignItems: "center",
5752
- background: isSelected ? "primary100" : "neutral0",
5753
- style: { cursor: "pointer" },
5754
- children: [
5755
- /* @__PURE__ */ jsx(
5756
- Checkbox,
5757
- {
5758
- checked: isSelected,
5759
- onChange: () => handleToggleRegion(region.id)
5760
- }
5761
- ),
5762
- /* @__PURE__ */ jsx(Typography, { flex: "1", children: region.name || region.id }),
5763
- /* @__PURE__ */ jsx(
5764
- Checkbox,
5765
- {
5766
- checked: isPrimary,
5767
- onChange: () => handleSetPrimary(region.id),
5768
- children: "Primary"
5769
- }
5770
- )
5771
- ]
5772
- },
5773
- region.id
5774
- );
5775
- }) : searchInput ? /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { textAlign: "center", textColor: "neutral500", children: "No regions found" }) }) : null })
6503
+ ),
6504
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Follow redirects" })
6505
+ ] }),
6506
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "Automatically follow HTTP redirects when checking the URL." })
6507
+ ] })
6508
+ ]
5776
6509
  }
5777
- )
5778
- ] });
5779
- };
6510
+ ) })
6511
+ ] }) }) });
6512
+ }
5780
6513
  function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
5781
6514
  const [monitorType, setMonitorType] = useState(MONITOR_TYPE.WEBSITE);
5782
6515
  const navigate = useNavigate();
@@ -6015,6 +6748,8 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6015
6748
  setIsSubmitting(true);
6016
6749
  try {
6017
6750
  let result;
6751
+ let url = mode === "create" ? "/monitors" : `/monitors/${monitor?.id}`;
6752
+ let method = mode === "create" ? "POST" : "PUT";
6018
6753
  if (monitorType === MONITOR_TYPE.PORT) {
6019
6754
  const portNumber = parseInt(portFormData.port, 10);
6020
6755
  const fieldErrors = {};
@@ -6057,8 +6792,8 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6057
6792
  tag_ids: selectedTagIds,
6058
6793
  ...mode === "create" ? { is_enabled: true } : { id: monitor?.id }
6059
6794
  };
6060
- result = await request("/monitors", {
6061
- method: mode === "create" ? "POST" : "PATCH",
6795
+ result = await request(url, {
6796
+ method,
6062
6797
  data: payload
6063
6798
  });
6064
6799
  } else if (monitorType === MONITOR_TYPE.KEYWORD) {
@@ -6105,8 +6840,8 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6105
6840
  tag_ids: selectedTagIds,
6106
6841
  ...mode === "create" ? { is_enabled: true } : { id: monitor?.id }
6107
6842
  };
6108
- result = await request("/monitors", {
6109
- method: mode === "create" ? "POST" : "PUT",
6843
+ result = await request(url, {
6844
+ method,
6110
6845
  data: payload
6111
6846
  });
6112
6847
  } else {
@@ -6128,8 +6863,8 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6128
6863
  regions: buildRegionsPayload(),
6129
6864
  is_enabled: true
6130
6865
  };
6131
- result = await request("/monitors", {
6132
- method: "POST",
6866
+ result = await request(url, {
6867
+ method,
6133
6868
  data: payload
6134
6869
  });
6135
6870
  } else {
@@ -6148,8 +6883,8 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6148
6883
  tag_ids: selectedTagIds,
6149
6884
  regions: buildRegionsPayload()
6150
6885
  };
6151
- result = await request(`/monitors/${monitor?.id}`, {
6152
- method: "PUT",
6886
+ result = await request(url, {
6887
+ method,
6153
6888
  data: payload
6154
6889
  });
6155
6890
  }
@@ -6232,6 +6967,21 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6232
6967
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6233
6968
  /* @__PURE__ */ jsx(Typography, { variant: "beta", marginBottom: 4, marginTop: 2, children: mode === "create" ? "Create Monitor" : "Edit Monitor" }),
6234
6969
  /* @__PURE__ */ jsx(Card, { marginTop: 3, children: /* @__PURE__ */ jsx(CardBody, { width: "100%", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 6, width: "100%", children: [
6970
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { children: [
6971
+ /* @__PURE__ */ jsx(Field.Label, { children: "Monitor Type" }),
6972
+ /* @__PURE__ */ jsx(
6973
+ SingleSelect,
6974
+ {
6975
+ value: monitorType,
6976
+ onChange: (value) => {
6977
+ setMonitorType(value);
6978
+ setErrors({});
6979
+ },
6980
+ disabled: mode === "edit",
6981
+ children: MONITOR_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsx(SingleSelectOption, { value: option.value, children: option.label }, option.value))
6982
+ }
6983
+ )
6984
+ ] }) }),
6235
6985
  monitorType === MONITOR_TYPE.WEBSITE && /* @__PURE__ */ jsxs(Fragment, { children: [
6236
6986
  /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, width: "100%", children: [
6237
6987
  /* @__PURE__ */ jsxs(
@@ -6309,53 +7059,362 @@ function MonitorForm({ monitor, mode, handleCancelEdit, load }) {
6309
7059
  }
6310
7060
  }
6311
7061
  }
6312
- ),
6313
- /* @__PURE__ */ jsx(Field.Error, {})
6314
- ] }) })
6315
- ]
7062
+ ),
7063
+ /* @__PURE__ */ jsx(Field.Error, {})
7064
+ ] }) })
7065
+ ]
7066
+ }
7067
+ ),
7068
+ /* @__PURE__ */ jsx(Flex, { width: "100%", children: /* @__PURE__ */ jsxs(Box, { paddingTop: 4, width: "100%", children: [
7069
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, marginBottom: 2, alignItems: "start", children: [
7070
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Monitoring regions" }),
7071
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "pi", children: "Choose the regions where this monitor should be active" })
7072
+ ] }),
7073
+ /* @__PURE__ */ jsx(
7074
+ RegionsMultiSelect,
7075
+ {
7076
+ selectedRegionIds,
7077
+ onRegionsChange: setSelectedRegionIds,
7078
+ primaryRegionId,
7079
+ onPrimaryRegionChange: handlePrimaryRegionChange
7080
+ }
7081
+ ),
7082
+ errors.primaryRegion && /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "pi", children: errors.primaryRegion })
7083
+ ] }) }),
7084
+ /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
7085
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, marginBottom: 2, alignItems: "start", children: [
7086
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Add tags" }),
7087
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "pi", children: "Tags will enable you to organize your monitors in a better way" })
7088
+ ] }),
7089
+ /* @__PURE__ */ jsx(
7090
+ TagMultiSelect,
7091
+ {
7092
+ selectedTagIds,
7093
+ onTagsChange: setSelectedTagIds
7094
+ }
7095
+ )
7096
+ ] }),
7097
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7098
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Notifications" }),
7099
+ /* @__PURE__ */ jsx(
7100
+ NotificationChannelsIntegration,
7101
+ {
7102
+ value: formData.channel_ids,
7103
+ onChange: (ids) => updateNotificationChannels(ids)
7104
+ }
7105
+ )
7106
+ ] }),
7107
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7108
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Advanced settings" }),
7109
+ /* @__PURE__ */ jsx(
7110
+ AdvancedSettings,
7111
+ {
7112
+ services: formData.config.services,
7113
+ onServiceChange: updateService,
7114
+ meta: formData.config.meta,
7115
+ updateMeta
7116
+ }
7117
+ )
7118
+ ] })
7119
+ ] }),
7120
+ /* @__PURE__ */ jsx("div", { className: "tw-mt-6" })
7121
+ ] }),
7122
+ monitorType === MONITOR_TYPE.PORT && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, width: "100%", children: [
7123
+ /* @__PURE__ */ jsxs(
7124
+ Flex,
7125
+ {
7126
+ direction: { initial: "column", medium: "row" },
7127
+ gap: 5,
7128
+ marginBottom: 3,
7129
+ width: "100%",
7130
+ children: [
7131
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { error: errors.name, children: [
7132
+ /* @__PURE__ */ jsx(Field.Label, { children: "Monitor name" }),
7133
+ /* @__PURE__ */ jsx(
7134
+ Field.Input,
7135
+ {
7136
+ type: "text",
7137
+ size: "M",
7138
+ name: "portName",
7139
+ placeholder: "Monitor name",
7140
+ value: portFormData.name,
7141
+ onChange: (e) => {
7142
+ setPortFormData((prev) => ({
7143
+ ...prev,
7144
+ name: e.target.value
7145
+ }));
7146
+ if (errors.name) {
7147
+ setErrors((prev) => ({
7148
+ ...prev,
7149
+ name: void 0
7150
+ }));
7151
+ }
7152
+ }
7153
+ }
7154
+ ),
7155
+ /* @__PURE__ */ jsx(Field.Error, {})
7156
+ ] }) }),
7157
+ /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
7158
+ /* @__PURE__ */ jsxs(Field.Root, { error: errors.host, children: [
7159
+ /* @__PURE__ */ jsx(Field.Label, { children: "Host / Address" }),
7160
+ /* @__PURE__ */ jsx(
7161
+ Field.Input,
7162
+ {
7163
+ type: "text",
7164
+ size: "M",
7165
+ name: "host",
7166
+ placeholder: "example.com or 192.168.1.1",
7167
+ value: portFormData.host,
7168
+ onChange: (e) => {
7169
+ setPortFormData((prev) => ({
7170
+ ...prev,
7171
+ host: e.target.value.trim()
7172
+ }));
7173
+ if (errors.host) {
7174
+ setErrors((prev) => ({
7175
+ ...prev,
7176
+ host: void 0
7177
+ }));
7178
+ }
7179
+ }
7180
+ }
7181
+ ),
7182
+ /* @__PURE__ */ jsx(Field.Error, {})
7183
+ ] }),
7184
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginTop: 1, children: "Enter domain or IP only (no protocol or paths)" })
7185
+ ] })
7186
+ ]
7187
+ }
7188
+ ),
7189
+ /* @__PURE__ */ jsxs(
7190
+ Flex,
7191
+ {
7192
+ direction: { initial: "column", medium: "row" },
7193
+ gap: 5,
7194
+ marginBottom: 3,
7195
+ width: "100%",
7196
+ children: [
7197
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { error: errors.port, children: [
7198
+ /* @__PURE__ */ jsx(Field.Label, { children: "Port" }),
7199
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 2, children: "The network port to monitor (e.g. 80, 443, 3306). Port range: 1-65535" }),
7200
+ /* @__PURE__ */ jsx(
7201
+ Field.Input,
7202
+ {
7203
+ type: "number",
7204
+ size: "M",
7205
+ name: "port",
7206
+ min: 1,
7207
+ max: 65535,
7208
+ placeholder: "Port",
7209
+ value: portFormData.port,
7210
+ onChange: (e) => {
7211
+ setPortFormData((prev) => ({
7212
+ ...prev,
7213
+ port: e.target.value
7214
+ }));
7215
+ if (errors.port) {
7216
+ setErrors((prev) => ({
7217
+ ...prev,
7218
+ port: void 0
7219
+ }));
7220
+ }
7221
+ }
7222
+ }
7223
+ ),
7224
+ /* @__PURE__ */ jsx(Field.Error, {})
7225
+ ] }) }),
7226
+ /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
7227
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, marginBottom: 2, alignItems: "start", children: [
7228
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Add tags" }),
7229
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "pi", children: "Tags will enable you to organize your monitors in a better way" })
7230
+ ] }),
7231
+ /* @__PURE__ */ jsx(
7232
+ TagMultiSelect,
7233
+ {
7234
+ selectedTagIds,
7235
+ onTagsChange: setSelectedTagIds
7236
+ }
7237
+ )
7238
+ ] })
7239
+ ]
7240
+ }
7241
+ ),
7242
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7243
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Notifications" }),
7244
+ /* @__PURE__ */ jsx(
7245
+ NotificationChannelsIntegration,
7246
+ {
7247
+ value: formData.channel_ids,
7248
+ onChange: (ids) => updateNotificationChannels(ids)
6316
7249
  }
6317
- ),
6318
- /* @__PURE__ */ jsx(Flex, { width: "100%", children: /* @__PURE__ */ jsxs(Box, { paddingTop: 4, width: "100%", children: [
6319
- /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, marginBottom: 2, alignItems: "start", children: [
6320
- /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Monitoring regions" }),
6321
- /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "pi", children: "Choose the regions where this monitor should be active" })
6322
- ] }),
6323
- /* @__PURE__ */ jsx(
6324
- RegionsMultiSelect,
6325
- {
6326
- selectedRegionIds,
6327
- onRegionsChange: setSelectedRegionIds,
6328
- primaryRegionId,
6329
- onPrimaryRegionChange: handlePrimaryRegionChange
6330
- }
6331
- ),
6332
- errors.primaryRegion && /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "pi", children: errors.primaryRegion })
6333
- ] }) }),
6334
- /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
6335
- /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Notifications" }),
6336
- /* @__PURE__ */ jsx(
6337
- NotificationChannelsIntegration,
6338
- {
6339
- value: formData.channel_ids,
6340
- onChange: (ids) => updateNotificationChannels(ids)
7250
+ )
7251
+ ] }),
7252
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7253
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Advanced settings" }),
7254
+ /* @__PURE__ */ jsx(
7255
+ PortAdvancedSettings,
7256
+ {
7257
+ timeout: portFormData.timeout,
7258
+ onTimeoutChange: (value) => {
7259
+ setPortFormData((prev) => ({
7260
+ ...prev,
7261
+ timeout: value
7262
+ }));
7263
+ },
7264
+ monitorInterval: portFormData.monitor_interval,
7265
+ onMonitorIntervalChange: (value) => {
7266
+ setPortFormData((prev) => ({
7267
+ ...prev,
7268
+ monitor_interval: value
7269
+ }));
6341
7270
  }
6342
- )
7271
+ }
7272
+ )
7273
+ ] })
7274
+ ] }) }),
7275
+ monitorType === MONITOR_TYPE.KEYWORD && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, width: "100%", children: [
7276
+ /* @__PURE__ */ jsxs(
7277
+ Flex,
7278
+ {
7279
+ direction: { initial: "column", medium: "row" },
7280
+ gap: 5,
7281
+ marginBottom: 3,
7282
+ width: "100%",
7283
+ children: [
7284
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { error: errors.name, children: [
7285
+ /* @__PURE__ */ jsx(Field.Label, { children: "Monitor name" }),
7286
+ /* @__PURE__ */ jsx(
7287
+ Field.Input,
7288
+ {
7289
+ type: "text",
7290
+ size: "M",
7291
+ name: "keywordName",
7292
+ placeholder: "Monitor name",
7293
+ value: keywordFormData.name,
7294
+ onChange: (e) => {
7295
+ setKeywordFormData((prev) => ({
7296
+ ...prev,
7297
+ name: e.target.value
7298
+ }));
7299
+ if (errors.name) {
7300
+ setErrors((prev) => ({
7301
+ ...prev,
7302
+ name: void 0
7303
+ }));
7304
+ }
7305
+ }
7306
+ }
7307
+ ),
7308
+ /* @__PURE__ */ jsx(Field.Error, {})
7309
+ ] }) }),
7310
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { error: errors.url, children: [
7311
+ /* @__PURE__ */ jsx(Field.Label, { children: "URL" }),
7312
+ /* @__PURE__ */ jsx(
7313
+ Field.Input,
7314
+ {
7315
+ type: "text",
7316
+ size: "M",
7317
+ name: "keywordUrl",
7318
+ placeholder: "https://example.com",
7319
+ value: keywordFormData.url,
7320
+ onChange: (e) => {
7321
+ setKeywordFormData((prev) => ({
7322
+ ...prev,
7323
+ url: e.target.value
7324
+ }));
7325
+ if (errors.url) {
7326
+ setErrors((prev) => ({
7327
+ ...prev,
7328
+ url: void 0
7329
+ }));
7330
+ }
7331
+ }
7332
+ }
7333
+ ),
7334
+ /* @__PURE__ */ jsx(Field.Error, {})
7335
+ ] }) })
7336
+ ]
7337
+ }
7338
+ ),
7339
+ /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
7340
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, marginBottom: 2, alignItems: "start", children: [
7341
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Add tags" }),
7342
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "pi", children: "Tags will enable you to organize your monitors in a better way" })
6343
7343
  ] }),
6344
- /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
6345
- /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Advanced settings" }),
6346
- /* @__PURE__ */ jsx(
6347
- AdvancedSettings,
6348
- {
6349
- services: formData.config.services,
6350
- onServiceChange: updateService,
6351
- meta: formData.config.meta,
6352
- updateMeta
7344
+ /* @__PURE__ */ jsx(
7345
+ TagMultiSelect,
7346
+ {
7347
+ selectedTagIds,
7348
+ onTagsChange: setSelectedTagIds
7349
+ }
7350
+ )
7351
+ ] }),
7352
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
7353
+ KeywordInput,
7354
+ {
7355
+ keywords: keywordFormData.keywords,
7356
+ onKeywordsChange: (keywords) => {
7357
+ setKeywordFormData((prev) => ({
7358
+ ...prev,
7359
+ keywords
7360
+ }));
7361
+ if (errors.keywords) {
7362
+ setErrors((prev) => ({
7363
+ ...prev,
7364
+ keywords: void 0
7365
+ }));
6353
7366
  }
6354
- )
6355
- ] })
7367
+ },
7368
+ error: errors.keywords,
7369
+ matchAll: keywordFormData.matchAll,
7370
+ onMatchAllChange: (value) => {
7371
+ setKeywordFormData((prev) => ({
7372
+ ...prev,
7373
+ matchAll: value
7374
+ }));
7375
+ }
7376
+ }
7377
+ ) }),
7378
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7379
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Notifications" }),
7380
+ /* @__PURE__ */ jsx(
7381
+ NotificationChannelsIntegration,
7382
+ {
7383
+ value: formData.channel_ids,
7384
+ onChange: (ids) => updateNotificationChannels(ids)
7385
+ }
7386
+ )
6356
7387
  ] }),
6357
- /* @__PURE__ */ jsx("div", { className: "tw-mt-6" })
6358
- ] }),
7388
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, alignItems: "start", children: [
7389
+ /* @__PURE__ */ jsx(Typography, { variant: "epsilon", children: "Advanced settings" }),
7390
+ /* @__PURE__ */ jsx(
7391
+ KeywordAdvancedSettings,
7392
+ {
7393
+ timeout: keywordFormData.timeout,
7394
+ onTimeoutChange: (value) => {
7395
+ setKeywordFormData((prev) => ({
7396
+ ...prev,
7397
+ timeout: value
7398
+ }));
7399
+ },
7400
+ followRedirects: keywordFormData.followRedirects,
7401
+ onFollowRedirectsChange: (value) => {
7402
+ setKeywordFormData((prev) => ({
7403
+ ...prev,
7404
+ followRedirects: value
7405
+ }));
7406
+ },
7407
+ monitorInterval: keywordFormData.monitor_interval,
7408
+ onMonitorIntervalChange: (value) => {
7409
+ setKeywordFormData((prev) => ({
7410
+ ...prev,
7411
+ monitor_interval: value
7412
+ }));
7413
+ }
7414
+ }
7415
+ )
7416
+ ] })
7417
+ ] }) }),
6359
7418
  /* @__PURE__ */ jsxs(Flex, { justifyContent: "flex-end", gap: 3, marginTop: 2, width: "100%", marginBottom: 4, children: [
6360
7419
  /* @__PURE__ */ jsx(Button, { variant: "danger-light", size: "M", onClick: () => handleCancel(), children: "Cancel" }),
6361
7420
  /* @__PURE__ */ jsx(Button, { disabled: isSubmitting, size: "M", onClick: handleSubmit, children: isSubmitting ? "Saving..." : mode === "create" ? "Create Monitor" : "Update Monitor" })
@@ -6618,8 +7677,8 @@ const setNestedValue = (obj, path, value) => {
6618
7677
  const keys = path.split(".");
6619
7678
  const result = { ...obj };
6620
7679
  let current = result;
6621
- for (let i = 0; i < keys.length - 1; i++) {
6622
- const key = keys[i];
7680
+ for (let index = 0; index < keys.length - 1; index++) {
7681
+ const key = keys[index];
6623
7682
  current[key] = current[key] ? { ...current[key] } : {};
6624
7683
  current = current[key];
6625
7684
  }
@@ -6657,11 +7716,11 @@ function IntegrationFormModal({
6657
7716
  } else {
6658
7717
  const keys = field.name.split(".");
6659
7718
  let current = initialData;
6660
- for (let i = 0; i < keys.length - 1; i++) {
6661
- if (!current[keys[i]]) {
6662
- current[keys[i]] = {};
7719
+ for (let index = 0; index < keys.length - 1; index++) {
7720
+ if (!current[keys[index]]) {
7721
+ current[keys[index]] = {};
6663
7722
  }
6664
- current = current[keys[i]];
7723
+ current = current[keys[index]];
6665
7724
  }
6666
7725
  current[keys[keys.length - 1]] = "";
6667
7726
  }
@@ -6685,11 +7744,11 @@ function IntegrationFormModal({
6685
7744
  if (value !== void 0) {
6686
7745
  const keys = field.name.split(".");
6687
7746
  let current = populatedData;
6688
- for (let i = 0; i < keys.length - 1; i++) {
6689
- if (!current[keys[i]]) {
6690
- current[keys[i]] = {};
7747
+ for (let index = 0; index < keys.length - 1; index++) {
7748
+ if (!current[keys[index]]) {
7749
+ current[keys[index]] = {};
6691
7750
  }
6692
- current = current[keys[i]];
7751
+ current = current[keys[index]];
6693
7752
  }
6694
7753
  current[keys[keys.length - 1]] = value;
6695
7754
  }
@@ -6771,11 +7830,11 @@ function IntegrationFormModal({
6771
7830
  if (value !== void 0 && value !== "") {
6772
7831
  const keys = field.name.split(".");
6773
7832
  let current = config2;
6774
- for (let i = 0; i < keys.length - 1; i++) {
6775
- if (!current[keys[i]]) {
6776
- current[keys[i]] = {};
7833
+ for (let index = 0; index < keys.length - 1; index++) {
7834
+ if (!current[keys[index]]) {
7835
+ current[keys[index]] = {};
6777
7836
  }
6778
- current = current[keys[i]];
7837
+ current = current[keys[index]];
6779
7838
  }
6780
7839
  current[keys[keys.length - 1]] = value;
6781
7840
  }
@@ -6921,43 +7980,52 @@ function IntegrationFormModal({
6921
7980
  channel.config_schema.fields.map((field) => {
6922
7981
  const isDisabled = isFieldDisabled(field);
6923
7982
  const isPassword = field.type === "password";
6924
- return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(Field.Root, { name: field.name, error: errors[field.name], hint: field.description && !errors[field.name] ? field.description : void 0, children: [
6925
- /* @__PURE__ */ jsx(Field.Label, { children: field.label }),
6926
- /* @__PURE__ */ jsxs(Box, { position: "relative", children: [
6927
- /* @__PURE__ */ jsx(
6928
- Field.Input,
6929
- {
6930
- type: getInputType(field.type, field.name),
6931
- placeholder: field.placeholder,
6932
- value: getDisplayValue(field),
6933
- disabled: isDisabled,
6934
- onChange: (e) => {
6935
- if (!isDisabled) {
6936
- updateFieldValue(field.name, e.target.value);
7983
+ return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(
7984
+ Field.Root,
7985
+ {
7986
+ name: field.name,
7987
+ error: errors[field.name],
7988
+ hint: field.description && !errors[field.name] ? field.description : void 0,
7989
+ children: [
7990
+ /* @__PURE__ */ jsx(Field.Label, { children: field.label }),
7991
+ /* @__PURE__ */ jsxs(Box, { position: "relative", children: [
7992
+ /* @__PURE__ */ jsx(
7993
+ Field.Input,
7994
+ {
7995
+ type: getInputType(field.type, field.name),
7996
+ placeholder: field.placeholder,
7997
+ value: getDisplayValue(field),
7998
+ disabled: isDisabled,
7999
+ onChange: (e) => {
8000
+ if (!isDisabled) {
8001
+ updateFieldValue(field.name, e.target.value);
8002
+ }
8003
+ }
6937
8004
  }
6938
- }
6939
- }
6940
- ),
6941
- isPassword && /* @__PURE__ */ jsx(
6942
- Button,
6943
- {
6944
- variant: "ghost",
6945
- size: "S",
6946
- onClick: () => togglePasswordVisibility(field.name),
6947
- style: {
6948
- position: "absolute",
6949
- right: 8,
6950
- top: "50%",
6951
- transform: "translateY(-50%)"
6952
- },
6953
- "aria-label": showPassword[field.name] ? "Hide password" : "Show password",
6954
- children: showPassword[field.name] ? /* @__PURE__ */ jsx(EyeStriked, {}) : /* @__PURE__ */ jsx(Eye, {})
6955
- }
6956
- )
6957
- ] }),
6958
- field.description && !errors[field.name] && /* @__PURE__ */ jsx(Field.Hint, {}),
6959
- errors[field.name] && /* @__PURE__ */ jsx(Field.Error, {})
6960
- ] }, field.name) });
8005
+ ),
8006
+ isPassword && /* @__PURE__ */ jsx(
8007
+ Button,
8008
+ {
8009
+ variant: "ghost",
8010
+ size: "S",
8011
+ onClick: () => togglePasswordVisibility(field.name),
8012
+ style: {
8013
+ position: "absolute",
8014
+ right: 8,
8015
+ top: "50%",
8016
+ transform: "translateY(-50%)"
8017
+ },
8018
+ "aria-label": showPassword[field.name] ? "Hide password" : "Show password",
8019
+ children: showPassword[field.name] ? /* @__PURE__ */ jsx(EyeStriked, {}) : /* @__PURE__ */ jsx(Eye, {})
8020
+ }
8021
+ )
8022
+ ] }),
8023
+ field.description && !errors[field.name] && /* @__PURE__ */ jsx(Field.Hint, {}),
8024
+ errors[field.name] && /* @__PURE__ */ jsx(Field.Error, {})
8025
+ ]
8026
+ },
8027
+ field.name
8028
+ ) });
6961
8029
  })
6962
8030
  ] }) }),
6963
8031
  /* @__PURE__ */ jsxs(Modal.Footer, { children: [
@@ -7288,153 +8356,187 @@ const IntegrationsPage = () => {
7288
8356
  }
7289
8357
  };
7290
8358
  return /* @__PURE__ */ jsxs(Box, { padding: 2, children: [
7291
- /* @__PURE__ */ jsxs(Flex, { direction: { initial: "column", medium: "row" }, alignItems: "stretch", gap: 4, height: "100%", children: [
7292
- /* @__PURE__ */ jsx(Box, { background: "neutral0", padding: 4, borderRadius: "8px", width: { initial: "100%", medium: "260px" }, children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "stretch", children: filterCategories.map((filter) => /* @__PURE__ */ jsx(
7293
- Button,
7294
- {
7295
- variant: activeFilter === filter.id ? "secondary" : "tertiary",
7296
- disabled: !filter.enabled,
7297
- justifyContent: "flex-start",
7298
- onClick: () => filter.enabled && setActiveFilter(filter.id),
7299
- children: /* @__PURE__ */ jsx(Typography, { variant: "pi", children: filter.name })
7300
- },
7301
- filter.id
7302
- )) }) }),
7303
- /* @__PURE__ */ jsx(Box, { background: "neutral0", padding: 4, borderRadius: "8px", flex: "1", overflow: "auto", children: /* @__PURE__ */ jsxs(Box, { maxWidth: { initial: "100%", medium: "900px" }, margin: "auto", children: [
7304
- /* @__PURE__ */ jsxs(
7305
- Flex,
7306
- {
7307
- direction: { initial: "column", medium: "row" },
7308
- justifyContent: "space-between",
7309
- alignItems: { initial: "stretch", medium: "center" },
7310
- gap: 4,
7311
- marginBottom: 6,
7312
- children: [
7313
- /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
7314
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: "Integrations" }),
7315
- planLimits && /* @__PURE__ */ jsx(
7316
- Box,
7317
- {
7318
- background: "neutral100",
7319
- paddingLeft: 3,
7320
- paddingRight: 3,
7321
- paddingTop: 1,
7322
- paddingBottom: 1,
7323
- borderRadius: "20px",
7324
- children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
7325
- planLimits.used_integrations,
7326
- "/",
7327
- planLimits.max_integrations,
7328
- " used"
7329
- ] })
7330
- }
7331
- )
7332
- ] }),
7333
- /* @__PURE__ */ jsx(Box, { width: { initial: "100%", medium: "280px" }, children: /* @__PURE__ */ jsx(
7334
- TextInput,
8359
+ /* @__PURE__ */ jsxs(
8360
+ Flex,
8361
+ {
8362
+ direction: { initial: "column", medium: "row" },
8363
+ alignItems: "stretch",
8364
+ gap: 4,
8365
+ height: "100%",
8366
+ children: [
8367
+ /* @__PURE__ */ jsx(
8368
+ Box,
8369
+ {
8370
+ background: "neutral0",
8371
+ padding: 4,
8372
+ borderRadius: "8px",
8373
+ width: { initial: "100%", medium: "260px" },
8374
+ children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "stretch", children: filterCategories.map((filter) => /* @__PURE__ */ jsx(
8375
+ Button,
7335
8376
  {
7336
- placeholder: "Search by integration type…",
7337
- value: searchQuery,
7338
- onChange: (e) => setSearchQuery(e.target.value),
7339
- startAction: /* @__PURE__ */ jsx(Search, {})
7340
- }
7341
- ) })
7342
- ]
7343
- }
7344
- ),
7345
- channelsLoading ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", children: "Loading integrations…" }) }) : activeFilter === "my" ? integrations.length === 0 ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", width: "100%", children: /* @__PURE__ */ jsxs(
7346
- Flex,
7347
- {
7348
- direction: "column",
7349
- alignItems: "center",
7350
- gap: 3,
7351
- marginBottom: 4,
7352
- width: "100%",
7353
- children: [
7354
- /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations found" }),
7355
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Please add an integration to get started" })
7356
- ]
7357
- }
7358
- ) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 3, width: "100%", children: integrations.map((integration) => /* @__PURE__ */ jsx(
7359
- IntegrationCard,
7360
- {
7361
- integration,
7362
- onEdit: handleEdit,
7363
- onDelete: handleDelete,
7364
- onTest: handleTest,
7365
- onToggle: handleToggleIntegration
7366
- },
7367
- integration.id
7368
- )) }) : filteredChannels.length === 0 ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, marginBottom: 4, width: "100%", children: [
7369
- /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations available" }),
7370
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: searchQuery ? "Try a different search term" : "No integrations match this filter" })
7371
- ] }) }) : (
7372
- /* CATEGORY ACCORDIONS */
7373
- /* @__PURE__ */ jsx(Accordion.Root, { children: filteredChannels.map((channel) => {
7374
- const channelIntegrations = getIntegrationsByChannelType(channel.type);
7375
- return /* @__PURE__ */ jsxs(Accordion.Item, { value: channel.type, children: [
7376
- /* @__PURE__ */ jsx(Accordion.Header, { children: /* @__PURE__ */ jsx(Accordion.Trigger, { caretPosition: "left", description: channel.description, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, width: { initial: "100%", medium: "542px" }, children: [
7377
- /* @__PURE__ */ jsx(Box, { children: getIntegrationIcon(channel.icon) }),
7378
- /* @__PURE__ */ jsxs(Flex, { width: { initial: "100%", medium: "542px" }, gap: 3, justifyContent: "space-between", children: [
7379
- /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: channel.label }),
7380
- /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: !planLimits?.can_add_more ? /* @__PURE__ */ jsx(Tooltip, { label: "Max integrations limit reached for your plan.", children: /* @__PURE__ */ jsx(
7381
- Button,
8377
+ variant: activeFilter === filter.id ? "secondary" : "tertiary",
8378
+ disabled: !filter.enabled,
8379
+ justifyContent: "flex-start",
8380
+ onClick: () => filter.enabled && setActiveFilter(filter.id),
8381
+ children: /* @__PURE__ */ jsx(Typography, { variant: "pi", children: filter.name })
8382
+ },
8383
+ filter.id
8384
+ )) })
8385
+ }
8386
+ ),
8387
+ /* @__PURE__ */ jsx(Box, { background: "neutral0", padding: 4, borderRadius: "8px", flex: "1", overflow: "auto", children: /* @__PURE__ */ jsxs(Box, { maxWidth: { initial: "100%", medium: "900px" }, margin: "auto", children: [
8388
+ /* @__PURE__ */ jsxs(
8389
+ Flex,
8390
+ {
8391
+ direction: { initial: "column", medium: "row" },
8392
+ justifyContent: "space-between",
8393
+ alignItems: { initial: "stretch", medium: "center" },
8394
+ gap: 4,
8395
+ marginBottom: 6,
8396
+ children: [
8397
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
8398
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: "Integrations" }),
8399
+ planLimits && /* @__PURE__ */ jsx(
8400
+ Box,
8401
+ {
8402
+ background: "neutral100",
8403
+ paddingLeft: 3,
8404
+ paddingRight: 3,
8405
+ paddingTop: 1,
8406
+ paddingBottom: 1,
8407
+ borderRadius: "20px",
8408
+ children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
8409
+ planLimits.used_integrations,
8410
+ "/",
8411
+ planLimits.max_integrations,
8412
+ " used"
8413
+ ] })
8414
+ }
8415
+ )
8416
+ ] }),
8417
+ /* @__PURE__ */ jsx(Box, { width: { initial: "100%", medium: "280px" }, children: /* @__PURE__ */ jsx(
8418
+ TextInput,
7382
8419
  {
7383
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
7384
- disabled: !planLimits?.can_add_more,
7385
- onClick: (e) => {
7386
- e.stopPropagation();
7387
- handleAddClick(channel);
7388
- },
7389
- style: { cursor: "not-allowed" },
7390
- children: "Add"
8420
+ placeholder: "Search by integration type…",
8421
+ value: searchQuery,
8422
+ onChange: (e) => setSearchQuery(e.target.value),
8423
+ startAction: /* @__PURE__ */ jsx(Search, {})
7391
8424
  }
7392
- ) }) : /* @__PURE__ */ jsx(
7393
- Button,
8425
+ ) })
8426
+ ]
8427
+ }
8428
+ ),
8429
+ channelsLoading ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", children: "Loading integrations…" }) }) : activeFilter === "my" ? integrations.length === 0 ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", width: "100%", children: /* @__PURE__ */ jsxs(
8430
+ Flex,
8431
+ {
8432
+ direction: "column",
8433
+ alignItems: "center",
8434
+ gap: 3,
8435
+ marginBottom: 4,
8436
+ width: "100%",
8437
+ children: [
8438
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations found" }),
8439
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Please add an integration to get started" })
8440
+ ]
8441
+ }
8442
+ ) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 3, width: "100%", children: integrations.map((integration) => /* @__PURE__ */ jsx(
8443
+ IntegrationCard,
8444
+ {
8445
+ integration,
8446
+ onEdit: handleEdit,
8447
+ onDelete: handleDelete,
8448
+ onTest: handleTest,
8449
+ onToggle: handleToggleIntegration
8450
+ },
8451
+ integration.id
8452
+ )) }) : filteredChannels.length === 0 ? /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, marginBottom: 4, width: "100%", children: [
8453
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations available" }),
8454
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: searchQuery ? "Try a different search term" : "No integrations match this filter" })
8455
+ ] }) }) : (
8456
+ /* CATEGORY ACCORDIONS */
8457
+ /* @__PURE__ */ jsx(Accordion.Root, { children: filteredChannels.map((channel) => {
8458
+ const channelIntegrations = getIntegrationsByChannelType(channel.type);
8459
+ return /* @__PURE__ */ jsxs(Accordion.Item, { value: channel.type, children: [
8460
+ /* @__PURE__ */ jsx(Accordion.Header, { children: /* @__PURE__ */ jsx(Accordion.Trigger, { caretPosition: "left", description: channel.description, children: /* @__PURE__ */ jsxs(
8461
+ Flex,
7394
8462
  {
7395
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
7396
- disabled: !planLimits?.can_add_more,
7397
- onClick: (e) => {
7398
- e.stopPropagation();
7399
- handleAddClick(channel);
7400
- },
7401
- children: "Add"
8463
+ alignItems: "center",
8464
+ gap: 3,
8465
+ width: { initial: "100%", medium: "542px" },
8466
+ children: [
8467
+ /* @__PURE__ */ jsx(Box, { children: getIntegrationIcon(channel.icon) }),
8468
+ /* @__PURE__ */ jsxs(
8469
+ Flex,
8470
+ {
8471
+ width: { initial: "100%", medium: "542px" },
8472
+ gap: 3,
8473
+ justifyContent: "space-between",
8474
+ children: [
8475
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: channel.label }),
8476
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: !planLimits?.can_add_more ? /* @__PURE__ */ jsx(Tooltip, { label: "Max integrations limit reached for your plan.", children: /* @__PURE__ */ jsx(
8477
+ Button,
8478
+ {
8479
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
8480
+ disabled: !planLimits?.can_add_more,
8481
+ onClick: (e) => {
8482
+ e.stopPropagation();
8483
+ handleAddClick(channel);
8484
+ },
8485
+ style: { cursor: "not-allowed" },
8486
+ children: "Add"
8487
+ }
8488
+ ) }) : /* @__PURE__ */ jsx(
8489
+ Button,
8490
+ {
8491
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
8492
+ disabled: !planLimits?.can_add_more,
8493
+ onClick: (e) => {
8494
+ e.stopPropagation();
8495
+ handleAddClick(channel);
8496
+ },
8497
+ children: "Add"
8498
+ }
8499
+ ) })
8500
+ ]
8501
+ }
8502
+ )
8503
+ ]
7402
8504
  }
7403
- ) })
7404
- ] })
7405
- ] }) }) }),
7406
- /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, paddingTop: 4, children: [
7407
- channelIntegrations.length === 0 && /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsxs(
7408
- Flex,
7409
- {
7410
- direction: "column",
7411
- alignItems: "center",
7412
- gap: 3,
7413
- marginBottom: 4,
7414
- width: "100%",
7415
- children: [
7416
- /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations found" }),
7417
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: 'No integrations for this channel yet. Click "Add" to create one.' })
7418
- ]
7419
- }
7420
- ) }),
7421
- channelIntegrations.map((integration) => /* @__PURE__ */ jsx(
7422
- IntegrationCard,
7423
- {
7424
- integration,
7425
- onEdit: handleEdit,
7426
- onDelete: handleDelete,
7427
- onTest: handleTest,
7428
- onToggle: handleToggleIntegration
7429
- },
7430
- integration.id
7431
- ))
7432
- ] }) })
7433
- ] }, channel.type);
7434
- }) })
7435
- )
7436
- ] }) })
7437
- ] }),
8505
+ ) }) }),
8506
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, paddingTop: 4, children: [
8507
+ channelIntegrations.length === 0 && /* @__PURE__ */ jsx(Box, { padding: { initial: 2, medium: 8 }, textAlign: "center", children: /* @__PURE__ */ jsxs(
8508
+ Flex,
8509
+ {
8510
+ direction: "column",
8511
+ alignItems: "center",
8512
+ gap: 3,
8513
+ marginBottom: 4,
8514
+ width: "100%",
8515
+ children: [
8516
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", children: "No integrations found" }),
8517
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: 'No integrations for this channel yet. Click "Add" to create one.' })
8518
+ ]
8519
+ }
8520
+ ) }),
8521
+ channelIntegrations.map((integration) => /* @__PURE__ */ jsx(
8522
+ IntegrationCard,
8523
+ {
8524
+ integration,
8525
+ onEdit: handleEdit,
8526
+ onDelete: handleDelete,
8527
+ onTest: handleTest,
8528
+ onToggle: handleToggleIntegration
8529
+ },
8530
+ integration.id
8531
+ ))
8532
+ ] }) })
8533
+ ] }, channel.type);
8534
+ }) })
8535
+ )
8536
+ ] }) })
8537
+ ]
8538
+ }
8539
+ ),
7438
8540
  /* @__PURE__ */ jsx(
7439
8541
  IntegrationFormModal,
7440
8542
  {
@@ -8907,7 +10009,7 @@ function Dashboard() {
8907
10009
  ]
8908
10010
  }
8909
10011
  ) }),
8910
- /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(HealthCards, { monitorData, isLoading }) })
10012
+ monitorData?.monitor?.service_type === "website" && /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(HealthCards, { monitorData, isLoading }) })
8911
10013
  ]
8912
10014
  }
8913
10015
  ),
@@ -11101,7 +12203,7 @@ const fetchIncidentsFromBackend = async (params, timeout = 1e4) => {
11101
12203
  return null;
11102
12204
  }
11103
12205
  if (!result?.incidentsData) {
11104
- console.error("Failed to fetch incidents:", result.status);
12206
+ console.error("Failed to fetch incidents: incidentsData missing in response", result);
11105
12207
  return null;
11106
12208
  }
11107
12209
  if (result?.incidentsData?.status === "success") {