Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 106 additions & 28 deletions apps/dashboard/src/components/forms/components/form-import.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
} from "@/components/forms/form-card";
import { useTRPC } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { InstatusIcon, StatuspageIcon } from "@openstatus/icons";
import {
BetterstackIcon,
InstatusIcon,
StatuspageIcon,
} from "@openstatus/icons";
import type { ImportSummary } from "@openstatus/importers/types";
import { Badge } from "@openstatus/ui/components/ui/badge";
import { Button } from "@openstatus/ui/components/ui/button";
Expand Down Expand Up @@ -40,10 +44,12 @@ import { toast } from "sonner";
import { z } from "zod";

const schema = z.object({
provider: z.enum(["statuspage", "instatus"]),
provider: z.enum(["statuspage", "betterstack", "instatus"]),
apiKey: z.string().min(1, "API key is required"),
statuspagePageId: z.string().optional(),
betterstackStatusPageId: z.string().optional(),
instatusPageId: z.string().optional(),
includeMonitors: z.boolean(),
includeStatusReports: z.boolean(),
includeSubscribers: z.boolean(),
includeComponents: z.boolean(),
Expand All @@ -56,7 +62,10 @@ function getPhaseCount(preview: ImportSummary, phase: string): number {
}

const PHASE_LABELS: Record<string, string> = {
monitors: "Monitors",
componentGroups: "Component Groups",
monitorGroups: "Monitor Groups",
sections: "Sections",
components: "Components",
incidents: "Status Reports",
maintenances: "Maintenances",
Expand All @@ -76,7 +85,9 @@ export function FormImport({
provider: undefined,
apiKey: "",
statuspagePageId: "",
betterstackStatusPageId: "",
instatusPageId: "",
includeMonitors: true,
includeStatusReports: true,
includeSubscribers: false,
includeComponents: true,
Expand All @@ -87,6 +98,7 @@ export function FormImport({
const watchProvider = form.watch("provider");
const watchApiKey = form.watch("apiKey");
const watchStatuspagePageId = form.watch("statuspagePageId");
const watchBetterstackStatusPageId = form.watch("betterstackStatusPageId");
const watchInstatusPageId = form.watch("instatusPageId");

const previewMutation = useMutation(
Expand Down Expand Up @@ -114,6 +126,10 @@ export function FormImport({
watchProvider === "statuspage"
? watchStatuspagePageId || undefined
: undefined,
betterstackStatusPageId:
watchProvider === "betterstack"
? watchBetterstackStatusPageId || undefined
: undefined,
instatusPageId:
watchProvider === "instatus"
? watchInstatusPageId || undefined
Expand Down Expand Up @@ -188,6 +204,21 @@ export function FormImport({
Atlassian Statuspage
</FormLabel>
</FormItem>
<FormItem className="relative flex cursor-pointer flex-row items-center gap-3 rounded-md border border-input px-2 py-3 text-center shadow-xs outline-none transition-[color,box-shadow] has-data-[state=checked]:border-primary/50 has-focus-visible:border-ring has-focus-visible:ring-[3px] has-focus-visible:ring-ring/50">
<FormControl>
<RadioGroupItem
value="betterstack"
className="sr-only"
/>
</FormControl>
<BetterstackIcon
className="size-4 shrink-0 text-foreground"
aria-hidden="true"
/>
<FormLabel className="cursor-pointer font-medium text-foreground text-xs leading-none after:absolute after:inset-0">
Better Stack
</FormLabel>
</FormItem>
<FormItem className="relative flex cursor-pointer flex-row items-center gap-3 rounded-md border border-input px-2 py-3 text-center shadow-xs outline-none transition-[color,box-shadow] has-data-[state=checked]:border-primary/50 has-focus-visible:border-ring has-focus-visible:ring-[3px] has-focus-visible:ring-ring/50">
<FormControl>
<RadioGroupItem
Expand Down Expand Up @@ -228,18 +259,22 @@ export function FormImport({
<Input
type="password"
placeholder={
watchProvider === "instatus"
? "Bearer API key"
: "OAuth API key"
watchProvider === "betterstack"
? "Bearer token"
: watchProvider === "instatus"
? "Bearer API key"
: "OAuth API key"
}
{...field}
/>
</FormControl>
<FormMessage />
<FormDescription>
{watchProvider === "instatus"
? "Your Instatus API key. Found in your Instatus account under Settings > API."
: "Your Statuspage API key. Found in your Statuspage account under Manage Account > API."}
{watchProvider === "betterstack"
? "Your Better Stack API token. Found in Better Stack \u2192 API tokens."
: watchProvider === "instatus"
? "Your Instatus API key. Found in your Instatus account under Settings > API."
: "Your Statuspage API key. Found in your Statuspage account under Manage Account > API."}
</FormDescription>
</FormItem>
)}
Expand All @@ -262,6 +297,24 @@ export function FormImport({
)}
/>
) : null}
{watchProvider === "betterstack" ? (
<FormField
control={form.control}
name="betterstackStatusPageId"
render={({ field }) => (
<FormItem>
<FormLabel>Status Page ID (optional)</FormLabel>
<FormControl>
<Input placeholder="e.g. 123456789" {...field} />
</FormControl>
<FormDescription>
Import a specific status page. Leave empty to use the
first available.
</FormDescription>
</FormItem>
)}
/>
) : null}
{watchProvider === "instatus" ? (
<FormField
control={form.control}
Expand Down Expand Up @@ -319,6 +372,29 @@ export function FormImport({
</p>
</Note>
) : null}
{watchProvider === "betterstack" ? (
<FormField
control={form.control}
name="includeMonitors"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel>Monitors</FormLabel>
<FormDescription>
Import monitors with their URL, frequency, and
regions.
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
) : null}
<FormField
control={form.control}
name="includeStatusReports"
Expand Down Expand Up @@ -360,26 +436,28 @@ export function FormImport({
</FormItem>
)}
/>
<FormField
control={form.control}
name="includeSubscribers"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel>Subscribers</FormLabel>
<FormDescription>
Import email subscribers.
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{watchProvider !== "betterstack" ? (
<FormField
control={form.control}
name="includeSubscribers"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel>Subscribers</FormLabel>
<FormDescription>
Import email subscribers.
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
) : null}
</FormCardContent>
</>
) : null}
Expand Down
10 changes: 8 additions & 2 deletions apps/dashboard/src/components/forms/components/update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export function FormComponentsUpdate() {
const { data: pageComponents, refetch: refetchComponents } = useQuery(
trpc.pageComponent.list.queryOptions({ pageId: Number.parseInt(id) }),
);
const { data: monitors } = useQuery(trpc.monitor.list.queryOptions());
const { data: monitors, refetch: refetchMonitors } = useQuery(
trpc.monitor.list.queryOptions(),
);
const { data: workspace } = useQuery(trpc.workspace.get.queryOptions());

const updateComponentsMutation = useMutation(
Expand All @@ -40,7 +42,7 @@ export function FormComponentsUpdate() {
const importMutation = useMutation(
trpc.import.run.mutationOptions({
onSuccess: async () => {
await Promise.all([refetch(), refetchComponents()]);
await Promise.all([refetch(), refetchComponents(), refetchMonitors()]);
setFormKey((k) => k + 1);
},
}),
Expand Down Expand Up @@ -137,10 +139,14 @@ export function FormComponentsUpdate() {
apiKey: values.apiKey,
pageId: statusPage.id,
statuspagePageId: values.statuspagePageId ?? undefined,
betterstackStatusPageId:
values.betterstackStatusPageId ?? undefined,
instatusPageId: values.instatusPageId ?? undefined,
options: {
includeStatusReports: values.includeStatusReports,
includeSubscribers: values.includeSubscribers,
includeComponents: values.includeComponents,
includeMonitors: values.includeMonitors,
},
});
}}
Expand Down
11 changes: 9 additions & 2 deletions packages/api/src/router/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ export const importRouter = createTRPCRouter({
preview: protectedProcedure
.input(
z.object({
provider: z.enum(["statuspage", "instatus"]),
provider: z.enum(["statuspage", "betterstack", "instatus"]),
apiKey: z.string().min(1),
statuspagePageId: z.string().nullish(),
betterstackStatusPageId: z.string().nullish(),
instatusPageId: z.string().nullish(),
pageId: z.number().optional(),
}),
Expand All @@ -21,6 +22,8 @@ export const importRouter = createTRPCRouter({
provider: opts.input.provider,
apiKey: opts.input.apiKey,
statuspagePageId: opts.input.statuspagePageId ?? undefined,
betterstackStatusPageId:
opts.input.betterstackStatusPageId ?? undefined,
instatusPageId: opts.input.instatusPageId ?? undefined,
workspaceId: opts.ctx.workspace.id,
pageId: opts.input.pageId,
Expand All @@ -31,16 +34,18 @@ export const importRouter = createTRPCRouter({
run: protectedProcedure
.input(
z.object({
provider: z.enum(["statuspage", "instatus"]),
provider: z.enum(["statuspage", "betterstack", "instatus"]),
apiKey: z.string().min(1),
pageId: z.number().optional(),
statuspagePageId: z.string().nullish(),
betterstackStatusPageId: z.string().nullish(),
instatusPageId: z.string().nullish(),
options: z
.object({
includeStatusReports: z.boolean().default(true),
includeSubscribers: z.boolean().default(false),
includeComponents: z.boolean().default(true),
includeMonitors: z.boolean().default(true),
})
.optional(),
}),
Expand Down Expand Up @@ -71,6 +76,8 @@ export const importRouter = createTRPCRouter({
provider: opts.input.provider,
apiKey: opts.input.apiKey,
statuspagePageId: opts.input.statuspagePageId ?? undefined,
betterstackStatusPageId:
opts.input.betterstackStatusPageId ?? undefined,
instatusPageId: opts.input.instatusPageId ?? undefined,
workspaceId: opts.ctx.workspace.id,
pageId: opts.input.pageId,
Expand Down
Loading
Loading