submit
This commit is contained in:
1 parent
c1d2041482
commit
a1e6eaa9d0
4 files changed
+154
-25
No files matched your search
@@ -20,9 +20,11 @@ import { useForm, Controller } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useStatusPageForm } from "@/Hooks/useStatusPageForm";
|
||||
import type { StatusPageFormData } from "@/Validation/statusPage";
|
||||
import { useGet } from "@/Hooks/UseApi";
|
||||
import { useGet, usePost } from "@/Hooks/UseApi";
|
||||
import type { Monitor } from "@/Types/Monitor";
|
||||
import timezones from "@/Utils/timezones.json";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
|
||||
interface TimezoneOption {
|
||||
_id: string;
|
||||
@@ -32,8 +34,10 @@ interface TimezoneOption {
|
||||
const CreateStatusPage = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { schema, defaults } = useStatusPageForm();
|
||||
const { post, loading: isSubmitting } = usePost();
|
||||
|
||||
const { data: monitorsResponse } = useGet<Monitor[]>(
|
||||
"/monitors/team?type=http&type=ping&type=port&type=docker"
|
||||
@@ -55,8 +59,39 @@ const CreateStatusPage = () => {
|
||||
console.log(errors);
|
||||
};
|
||||
|
||||
const onSubmit = (data: StatusPageFormData) => {
|
||||
console.log("Form Data Submitted: ", data);
|
||||
const onSubmit = async (data: StatusPageFormData) => {
|
||||
const fd = new FormData();
|
||||
fd.append("type", "uptime");
|
||||
fd.append("isPublished", String(data.isPublished));
|
||||
if (data.companyName) fd.append("companyName", data.companyName);
|
||||
if (data.url) fd.append("url", data.url);
|
||||
if (data.timezone) fd.append("timezone", data.timezone);
|
||||
|
||||
data.monitors.forEach((monitorId) => {
|
||||
fd.append("monitors[]", monitorId);
|
||||
});
|
||||
|
||||
if (data.logo?.data && data.logo.data !== "") {
|
||||
try {
|
||||
const imageResult = await axios.get(data.logo.data, {
|
||||
responseType: "blob",
|
||||
});
|
||||
fd.append("logo", imageResult.data);
|
||||
if (data.logo.data.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(data.logo.data);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error fetching logo blob:", e);
|
||||
}
|
||||
}
|
||||
|
||||
const result = await post("/status-page", fd, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
|
||||
if (result) {
|
||||
navigate(`/status/uptime/${data.url}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -137,10 +172,18 @@ const CreateStatusPage = () => {
|
||||
name="monitors"
|
||||
control={control}
|
||||
render={({ field, fieldState }) => {
|
||||
// Preserve order from field.value (IDs) when building selectedMonitors
|
||||
const selectedMonitors = field.value
|
||||
.map((id: string) => monitors.find((m) => m.id === id))
|
||||
.filter((m): m is Monitor => m !== undefined);
|
||||
.filter(Boolean) as Monitor[];
|
||||
|
||||
const handleDragEnd = (result: DropResult) => {
|
||||
if (!result.destination) return;
|
||||
const reordered = Array.from(field.value);
|
||||
const [removed] = reordered.splice(result.source.index, 1);
|
||||
reordered.splice(result.destination.index, 0, removed);
|
||||
field.onChange(reordered);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack spacing={theme.spacing(4)}>
|
||||
<Autocomplete
|
||||
@@ -151,7 +194,6 @@ const CreateStatusPage = () => {
|
||||
onChange={(_, newValue: Monitor[]) => {
|
||||
field.onChange(newValue.map((m) => m.id));
|
||||
}}
|
||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||
fieldLabel={t(
|
||||
"pages.statusPages.form.monitors.option.monitors.label"
|
||||
)}
|
||||
@@ -165,24 +207,15 @@ const CreateStatusPage = () => {
|
||||
helperText={fieldState.error?.message ?? ""}
|
||||
/>
|
||||
)}
|
||||
renderTags={() => null}
|
||||
/>
|
||||
{selectedMonitors.length > 0 && (
|
||||
<DragDropContext
|
||||
onDragEnd={(result: DropResult) => {
|
||||
if (!result.destination) return;
|
||||
const reordered = Array.from(field.value);
|
||||
const [removed] = reordered.splice(result.source.index, 1);
|
||||
reordered.splice(result.destination.index, 0, removed);
|
||||
field.onChange(reordered);
|
||||
}}
|
||||
>
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<Droppable droppableId="monitors-list">
|
||||
{(provided) => (
|
||||
<Stack
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
flex={1}
|
||||
width="100%"
|
||||
>
|
||||
{selectedMonitors.map((monitor, index) => (
|
||||
<Draggable
|
||||
@@ -301,7 +334,7 @@ const CreateStatusPage = () => {
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
<Button
|
||||
// loading={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { BasePage } from "@/Components/v2/design-elements";
|
||||
import { BasePage, BaseFallback } from "@/Components/v2/design-elements";
|
||||
import { StatusBar } from "@/Pages/StatusPage/Status/Components/StatusBar";
|
||||
import { MonitorsList } from "@/Pages/StatusPage/Status/Components/MonitorsList";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Link } from "react-router-dom";
|
||||
import Stack from "@mui/material/Stack";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -28,6 +30,33 @@ const StatusPageView = () => {
|
||||
|
||||
if (!statusPage) return null;
|
||||
|
||||
if (monitors?.length === 0) {
|
||||
return (
|
||||
<BasePage
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
breadcrumbOverride={isPublic ? [] : undefined}
|
||||
>
|
||||
<Stack alignItems={"center"}>
|
||||
<BaseFallback>
|
||||
<Typography
|
||||
variant="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{t("pages.statusPages.details.empty.title")}
|
||||
</Typography>
|
||||
{isAdmin && (
|
||||
<Link to={`/status/uptime/configure/${url}`}>
|
||||
{t("pages.statusPages.details.empty.addMonitor")}
|
||||
</Link>
|
||||
)}
|
||||
</BaseFallback>
|
||||
</Stack>
|
||||
</BasePage>
|
||||
);
|
||||
}
|
||||
|
||||
let sx: React.CSSProperties = {};
|
||||
if (isPublic) {
|
||||
sx.paddingTop = theme.spacing(20);
|
||||
|
||||
@@ -260,7 +260,13 @@ const Routes = () => {
|
||||
|
||||
<Route
|
||||
path="status/uptime/configure/:url"
|
||||
element={<CreateStatus />}
|
||||
element={
|
||||
<>
|
||||
<ThemeProvider theme={v2theme}>
|
||||
<CreateStatus />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
|
||||
@@ -242,7 +242,8 @@
|
||||
"clickToUpload": "Click to upload",
|
||||
"dragAndDrop": "or drag and drop",
|
||||
"supportedFormats": "Supported formats",
|
||||
"maxSize": "Max size"
|
||||
"maxSize": "Max size",
|
||||
"orDragAndDrop": "or drag and drop"
|
||||
},
|
||||
"errors": {
|
||||
"invalidFileType": "Invalid file type",
|
||||
@@ -861,9 +862,14 @@
|
||||
},
|
||||
"statusPages": {
|
||||
"fallback": {
|
||||
"actionButton": "Create status page",
|
||||
"checks": "No status pages found",
|
||||
"title": "Status pages"
|
||||
"title": "A status page is used to:",
|
||||
"checks": [
|
||||
"Communicate system status to users and stakeholders",
|
||||
"Display real-time uptime information publicly",
|
||||
"Build trust with transparent service monitoring",
|
||||
"Reduce support requests during incidents"
|
||||
],
|
||||
"actionButton": "Let's create your first status page!"
|
||||
},
|
||||
"monitorsList": {
|
||||
"chartTypeHeatmap": "Heatmap",
|
||||
@@ -883,7 +889,62 @@
|
||||
"published": "Published",
|
||||
"unpublished": "Unpublished"
|
||||
},
|
||||
"title": "Status pages"
|
||||
"title": "Status pages",
|
||||
"details": {
|
||||
"empty": {
|
||||
"title": "There's nothing here yet",
|
||||
"addMonitor": "Add a monitor to get started"
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
"access": {
|
||||
"title": "Access",
|
||||
"description": "If your status page is ready, you can mark it as published.",
|
||||
"option": {
|
||||
"published": {
|
||||
"name": "Published and visible to the public"
|
||||
}
|
||||
}
|
||||
},
|
||||
"basicInfo": {
|
||||
"title": "Basic information",
|
||||
"description": "Define company name and the subdomain that your status page points to.",
|
||||
"option": {
|
||||
"name": {
|
||||
"label": "Company name",
|
||||
"placeholder": "Acme Inc."
|
||||
},
|
||||
"url": {
|
||||
"label": "Your status page address",
|
||||
"placeholder": "my-status-page"
|
||||
}
|
||||
}
|
||||
},
|
||||
"monitors": {
|
||||
"title": "Monitors",
|
||||
"description": "Select the monitors to display on your status page.",
|
||||
"noMonitors": "No monitors selected",
|
||||
"option": {
|
||||
"monitors": {
|
||||
"label": "Select monitors",
|
||||
"placeholder": "Search and select monitors..."
|
||||
}
|
||||
}
|
||||
},
|
||||
"timezone": {
|
||||
"title": "Timezone",
|
||||
"description": "Select the timezone that your status page will be displayed in.",
|
||||
"option": {
|
||||
"timezone": {
|
||||
"label": "Timezone"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
"title": "Appearance",
|
||||
"description": "Define the default look and feel of your public status page."
|
||||
}
|
||||
}
|
||||
},
|
||||
"uptime": {
|
||||
"filters": {
|
||||
|
||||
Reference in new issue
Block a user