Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: display values toggle #1047

Merged
merged 10 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default async function AppLayout({
if (workspaces.find((w) => w.slug === workspaceSlug) === undefined)
return notFound();

// TODO: create a WorkspaceContext to store the `Workspace` object including the `slug` and `plan.limits`
return (
<div className="container relative mx-auto flex min-h-screen w-full flex-col items-center justify-center gap-6 p-4">
<AppHeader />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default async function MonitorPage({
defaultColumnFilters={[
{ id: "tags", value: search.tags },
{ id: "public", value: search.public },
].filter((v) => v.value !== undefined || v.value !== null)}
].filter((v) => v.value !== null)}
columns={columns}
data={monitorsWithData}
tags={tags}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { allPlans } from "@openstatus/db/src/schema/plan/config";
import type { WorkspacePlan } from "@openstatus/db/src/schema/workspaces/validation";

import { ThemeToggle } from "@/components/theme-toggle";
import { ThemeToggle } from "@/components/theme/theme-toggle";

interface Props {
plan: WorkspacePlan;
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/app/status-page/[domain]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default async function Page({ params }: Props) {
statusReports={page.statusReports}
incidents={page.incidents}
maintenances={page.maintenances}
showMonitorValues={!!page.showMonitorValues}
/>
) : (
<EmptyState
Expand Down
19 changes: 13 additions & 6 deletions apps/web/src/components/billing/pro-banner.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { ArrowRight, Rocket, X } from "lucide-react";
import { ArrowRight, ChevronRight, Rocket, X } from "lucide-react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useEffect, useState } from "react";
Expand Down Expand Up @@ -43,21 +43,28 @@ export function ProBanner() {
if (hidden) return null;

return (
<div className="grid gap-2 rounded-md border border-border p-2">
<div className="grid gap-2 rounded-md border border-border p-3">
<div className="flex items-center justify-between">
<p className="inline-flex items-center font-medium text-sm">
OpenStatus Pro <Rocket className="ml-2 h-4 w-4" />
</p>
<Button variant="ghost" size="icon" onClick={onClick}>
<Button
variant="ghost"
size="icon"
onClick={onClick}
className="w-7 h-7"
>
<X className="h-4 w-4" />
</Button>
</div>
<p className="text-muted-foreground text-xs">
<p className="text-muted-foreground text-sm">
Unlock custom domains, teams, 1 min. checks and more.
</p>
<Button variant="secondary" size="sm" asChild>
<Link href={`/app/${workspaceSlug}/settings/billing`}>
Upgrade <ArrowRight className="ml-2 h-4 w-4" />
<Link href={`/app/${workspaceSlug}/settings/billing`} className="group">
<span className="mr-0.5">Upgrade</span>{" "}
<ArrowRight className="relative inline h-4 w-0 transition-all group-hover:w-4" />
<ChevronRight className="relative inline h-4 w-4 transition-all group-hover:w-0" />
</Link>
</Button>
</div>
Expand Down
13 changes: 7 additions & 6 deletions apps/web/src/components/billing/pro-feature-hover-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useState } from "react";
import { workspacePlanHierarchy } from "@openstatus/db/src/schema";
import type { WorkspacePlan } from "@openstatus/db/src/schema/workspaces/validation";
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@openstatus/ui";
import { ArrowUpRight } from "lucide-react";
import Link from "next/link";

function upgradePlan(current: WorkspacePlan, required: WorkspacePlan) {
return workspacePlanHierarchy[current] < workspacePlanHierarchy[required];
Expand Down Expand Up @@ -33,7 +35,7 @@ export function ProFeatureHoverCard({
<HoverCard openDelay={0} open={open} onOpenChange={setOpen}>
<HoverCardTrigger
onClick={() => setOpen(true)}
className="opacity-70"
className="opacity-70 cursor-not-allowed"
asChild
>
{children}
Expand All @@ -45,15 +47,14 @@ export function ProFeatureHoverCard({
plan.
</p>
<p className="text-sm">
<a
<Link
href={`/app/${workspaceSlug}/settings/billing`}
target="_blank"
className="inline-flex items-center font-medium text-foreground underline underline-offset-4 hover:no-underline"
rel="noreferrer"
className="group inline-flex items-center font-medium text-foreground underline underline-offset-4 hover:no-underline"
>
Upgrade now
</a>
.
<ArrowUpRight className="ml-1 h-4 w-4 flex-shrink-0 text-muted-foreground group-hover:text-foreground" />
</Link>
</p>
</HoverCardContent>
</HoverCard>
Expand Down
7 changes: 6 additions & 1 deletion apps/web/src/components/data-table/monitor/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,12 @@ export const columns: ColumnDef<{
return (
<div className="flex w-24 gap-1">
{tracker.days?.map((tracker) => (
<Bar key={tracker.day} className="h-5" {...tracker} />
<Bar
key={tracker.day}
className="h-5"
showValues={true}
{...tracker}
/>
))}
</div>
);
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/forms/status-page/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function StatusPageForm({
icon: defaultValues?.icon || "",
password: defaultValues?.password || "",
passwordProtected: defaultValues?.passwordProtected || false,
showMonitorValues: defaultValues?.showMonitorValues || true,
monitors:
checkAllMonitors && allMonitors
? allMonitors.map(({ id }) => ({ monitorId: id, order: 0 }))
Expand Down
49 changes: 49 additions & 0 deletions apps/web/src/components/forms/status-page/section-advanced.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
AlertDialogHeader,
AlertDialogTitle,
Button,
Checkbox,
FormControl,
FormDescription,
FormField,
Expand All @@ -26,6 +27,8 @@ import {
Input,
} from "@openstatus/ui";

import { BarDescription } from "@/components/tracker/tracker";
import { MousePointer2 } from "lucide-react";
import { SectionHeader } from "../shared/section-header";

interface Props {
Expand Down Expand Up @@ -158,6 +161,52 @@ export function SectionAdvanced({ form }: Props) {
</FormItem>
)}
/>
<div className="grid w-full gap-4 md:grid-rows-2 md:grid-cols-3 md:col-span-full">
<SectionHeader
title="Bar Settings"
description="You can display or hide the amount of scheduled request an entpoint gets per day."
className="md:col-span-2"
/>
<div className="group md:row-span-2 flex flex-col justify-center gap-1 border border-dashed rounded-md p-3">
<div className="flex flex-row gap-2 items-center justify-center text-muted-foreground group-hover:text-foreground">
<MousePointer2 className="h-3 w-3" />
<p className="text-sm">Hover State</p>
</div>
<div className="max-w-[15rem] mx-auto">
<BarDescription
label="Operational"
day={new Date().toISOString()}
count={5600}
ok={5569}
showValues={!!form.getValues("showMonitorValues")}
barClassName="bg-status-operational"
className="md:col-span-1 bg-popover text-popover-foreground rounded-md border p-2 shadow-md"
/>
</div>
</div>
<FormField
control={form.control}
name="showMonitorValues"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0 md:col-span-2">
<FormControl>
<Checkbox
disabled={field.disabled}
checked={field.value ?? false}
onCheckedChange={field.onChange}
/>
</FormControl>
<div className="space-y-1 leading-none">
<FormLabel>Show number of request</FormLabel>
<FormDescription>
Share the total and failed amount of scheduled request to your
endpoint.
</FormDescription>
</div>
</FormItem>
)}
/>
</div>
<AlertDialog open={open} onOpenChange={(value) => setOpen(value)}>
<AlertDialogContent>
<AlertDialogHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export function SectionVisibility({ form, plan, workspaceSlug }: Props) {
</p>
<div className="flex flex-wrap items-center gap-2">
<p className="text-foreground">{link} </p>
{/* TODO: think of building a better shadcn like "CopyToClipboardButton" */}
<CopyToClipboardButton
text={link}
tooltipText="Copy to clipboard"
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/layout/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function AppSidebar({ page }: { page?: Page }) {
if (!page) return null;

return (
<div className="flex h-full flex-col justify-between">
<div className="flex h-full flex-col justify-between gap-2">
<div className="grid gap-2">
<p className="hidden px-3 font-medium text-foreground text-lg lg:block">
{page?.title}
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/components/layout/header/app-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ export function AppHeader() {
</li>
<li className="w-full">
<Button variant="link" asChild>
<Link href="/docs" target="_blank">
<Link href="/docs" target="_blank" className="group">
Docs
<ArrowUpRight className="ml-1 h-4 w-4 flex-shrink-0" />
<ArrowUpRight className="ml-1 h-4 w-4 flex-shrink-0 text-muted-foreground group-hover:text-foreground" />
</Link>
</Button>
</li>
Expand Down
12 changes: 10 additions & 2 deletions apps/web/src/components/layout/header/user-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useTheme } from "next-themes";
import Link from "next/link";
import { useParams } from "next/navigation";

import { ThemeIcon } from "@/components/theme/theme-icon";
import {
Avatar,
AvatarFallback,
Expand Down Expand Up @@ -72,7 +73,13 @@ export function UserNav() {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuSub>
<DropdownMenuSubTrigger>Switch theme</DropdownMenuSubTrigger>
{/* REMINDER: consider using that the data-state styles as default */}
<DropdownMenuSubTrigger className="gap-1 [&_svg]:data-[state=open]:text-foreground [&_svg]:data-[highlighted]:text-foreground [&_svg]:text-muted-foreground">
<div className="w-full flex flex-row items-center justify-between">
<span>Switch theme</span>
<ThemeIcon theme={theme} />
</div>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
Expand All @@ -81,9 +88,10 @@ export function UserNav() {
key={option}
checked={theme === option}
onClick={() => setTheme(option)}
className="capitalize"
className="capitalize justify-between [&_svg]:data-[state=open]:text-foreground [&_svg]:data-[highlighted]:text-foreground [&_svg]:text-muted-foreground"
>
{option}
<ThemeIcon theme={option} />
</DropdownMenuCheckboxItem>
))}
</DropdownMenuSubContent>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/layout/marketing-footer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ArrowUpRight } from "lucide-react";
import Link from "next/link";

import { ThemeToggle } from "@/components/theme/theme-toggle";
import { socialsConfig } from "@/config/socials";
import { cn } from "@/lib/utils";
import { Shell } from "../dashboard/shell";
import { ThemeToggle } from "../theme-toggle";
import { BrandName } from "./brand-name";
import { SocialIconButton } from "./social-icon-button";
import { StatusWidgetContainer } from "./status-widget-suspense";
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/components/status-page/monitor-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ export const MonitorList = ({
statusReports,
incidents,
maintenances,
showMonitorValues,
}: {
monitors: PublicMonitor[];
statusReports: z.infer<typeof selectPublicStatusReportSchemaWithRelation>[];
incidents: Incident[];
maintenances: Maintenance[];
showMonitorValues?: boolean;
}) => {
return (
<div className="grid gap-4">
Expand All @@ -41,6 +43,7 @@ export const MonitorList = ({
statusReports={monitorStatusReport}
incidents={monitorIncidents}
maintenances={monitorMaintenances}
showValues={showMonitorValues}
/>
);
})}
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/components/status-page/monitor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ export const Monitor = async ({
statusReports,
incidents,
maintenances,
showValues,
}: {
monitor: PublicMonitor;
statusReports: z.infer<typeof selectPublicStatusReportSchemaWithRelation>[];
incidents: Incident[];
maintenances: Maintenance[];
showValues?: boolean;
}) => {
const data = await tb.endpointStatusPeriod("45d")({
monitorId: String(monitor.id),
Expand All @@ -38,6 +40,7 @@ export const Monitor = async ({
reports={statusReports}
incidents={incidents}
maintenances={maintenances}
showValues={showValues}
{...monitor}
/>
);
Expand Down
26 changes: 26 additions & 0 deletions apps/web/src/components/theme/theme-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { cn } from "@/lib/utils";
import { type IconProps, Icons, type ValidIcon } from "../icons";

function mapThemeToIconName(theme: string): ValidIcon {
switch (theme) {
case "dark":
return "moon";
case "light":
return "sun";
case "system":
return "laptop";
default:
return "laptop";
}
}

interface ThemeIconProps extends IconProps {
theme?: string;
}

export function ThemeIcon({ theme, className, ...props }: ThemeIconProps) {
if (!theme) return null;

const Icon = Icons[mapThemeToIconName(theme)];
return <Icon className={cn("h-4 w-4", className)} {...props} />;
}
Loading
Loading