diff --git a/apps/docs/astro.config.mjs b/apps/docs/astro.config.mjs index bec61616..efa4d106 100644 --- a/apps/docs/astro.config.mjs +++ b/apps/docs/astro.config.mjs @@ -50,8 +50,6 @@ export default defineConfig({ components: { SiteTitle: "./src/components/SiteTitle.astro", Head: "./src/components/Head.astro", - Hero: "./src/components/Hero.astro", - Footer: "./src/components/Footer.astro", Header: "./src/components/Header.astro", }, editLink: { @@ -68,6 +66,10 @@ export default defineConfig({ { label: "Concepts", items: [ + { + label: "Overview", + slug: "concept/getting-started", + }, { label: "About Uptime monitoring", slug: "concept/uptime-monitoring", @@ -93,6 +95,10 @@ export default defineConfig({ { label: "Tutorials", items: [ + { + label: "Overview", + slug: "tutorial/getting-started", + }, { label: "How to create a monitor", slug: "tutorial/how-to-create-monitor", @@ -135,6 +141,10 @@ export default defineConfig({ { label: "Guides", items: [ + { + label: "Overview", + slug: "guides/getting-started", + }, { label: "Monitor your MCP Server", slug: "guides/how-to-monitor-mcp-server", @@ -167,6 +177,10 @@ export default defineConfig({ label: "Self host Status Page only", slug: "guides/self-host-status-page-only", }, + { + label: "Deploy a status page on Cloudflare Pages", + slug: "guides/how-deploy-status-page-cf-pages", + }, { label: "How to translate your status page", slug: "guides/how-to-translate-status-page", @@ -189,6 +203,7 @@ export default defineConfig({ }, { label: "Reference", + collapsed: true, items: [ { label: "API Reference V1 - Deprecated", @@ -254,6 +269,10 @@ export default defineConfig({ label: "Status Report", slug: "reference/status-report", }, + { + label: "Maintenance", + slug: "reference/maintenance", + }, { label: "Subscriber", slug: "reference/subscriber", @@ -264,6 +283,16 @@ export default defineConfig({ }, ], }, + { + label: "Help", + collapsed: true, + items: [ + { + label: "Need help?", + slug: "help/support", + }, + ], + }, ], plugins: [ starlightLinksValidator({ diff --git a/apps/docs/src/components/Head.astro b/apps/docs/src/components/Head.astro index 7a19a53d..3ed2c57d 100644 --- a/apps/docs/src/components/Head.astro +++ b/apps/docs/src/components/Head.astro @@ -3,10 +3,10 @@ import { NEXT_PUBLIC_OPENPANEL_CLIENT_ID } from "astro:env/client"; import Default from "@astrojs/starlight/components/Head.astro"; import { OpenPanelComponent } from "@openpanel/astro"; -const title = Astro.locals.starlightRoute.entry.data.title; -const { siteTitle } = Astro.locals.starlightRoute; +const title = Astro.locals.starlightRoute.entry.data.title ?? "openstatus docs"; +const description = Astro.locals.starlightRoute.entry.data.description ?? ""; -const url = `https://openstatus.dev/api/og?title=${encodeURIComponent(siteTitle)}&description=${encodeURIComponent(title)}`; +const url = `https://openstatus.dev/api/og?title=${encodeURIComponent(title)}&description=${encodeURIComponent(description)}&category=documentation&footer=docs.openstatus.dev`; --- diff --git a/apps/docs/src/components/Header.astro b/apps/docs/src/components/Header.astro index d12e28da..1aff6603 100644 --- a/apps/docs/src/components/Header.astro +++ b/apps/docs/src/components/Header.astro @@ -1,99 +1,99 @@ --- -import Search from "@astrojs/starlight/components/Search.astro"; -import config from "virtual:starlight/user-config"; -import SiteTitle from "./SiteTitle.astro"; +import config from 'virtual:starlight/user-config'; + +import LanguageSelect from 'virtual:starlight/components/LanguageSelect'; +import Search from 'virtual:starlight/components/Search'; +import SiteTitle from 'virtual:starlight/components/SiteTitle'; +import SocialIcons from 'virtual:starlight/components/SocialIcons'; +import ThemeSelect from 'virtual:starlight/components/ThemeSelect'; +import { LinkButton } from '@astrojs/starlight/components'; + +/** + * Render the `Search` component if Pagefind is enabled or the default search component has been overridden. + */ +const shouldRenderSearch = + config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro'; ---
-
- -
-
- {config.pagefind && } -
-
- - Get started - -
+
+ +
+
+ {shouldRenderSearch && } +
+
+ + Get Started + + + + +
diff --git a/apps/docs/src/components/Hero.astro b/apps/docs/src/components/Hero.astro deleted file mode 100644 index b8c40a96..00000000 --- a/apps/docs/src/components/Hero.astro +++ /dev/null @@ -1,45 +0,0 @@ ---- -const { data } = Astro.locals.starlightRoute.entry; -const { title = data.title, tagline, actions = [] } = data.hero || {}; - -import { LinkButton } from "@astrojs/starlight/components"; ---- - -
-
-

- { - tagline && ( -

- ) - } -

-
- -
- { - actions.length > 0 && ( -
- {actions.map( - ({ attrs: { class: className, ...attrs } = {}, icon, link: href, text, variant }) => ( - - {text} - {icon?.html && } - - ) - )} -
- ) - } -
-
-
diff --git a/apps/docs/src/components/SiteTitle.astro b/apps/docs/src/components/SiteTitle.astro index e5725442..2f606882 100644 --- a/apps/docs/src/components/SiteTitle.astro +++ b/apps/docs/src/components/SiteTitle.astro @@ -4,7 +4,7 @@ import logo from "../assets/icon.png"; // Image is 1600x900 --- - + openstatus - - - - -## How it works - -We send a request to your specified endpoint on a regular schedule and record the response. If your website or API is down, timing out, or doesn't return the expected response, we'll alert you right away. - -## What is a monitor? - -A **monitor** is a job that runs periodically to check the status of a service. This could be a website, an API, or any other service that can be automatically checked. Each monitor you create runs a request to your endpoint and records the results for you to review. - -## Creating a Monitor - -You can create a new monitor in one of four ways: - -- Dashboard: Use our intuitive dashboard to quickly set up and manage your monitors. -- API: Integrate monitor creation into your workflow using our [API](https://api.openstatus.dev/v1#tag/monitor/POST/monitor). -- CLI: Use our command-line interface to create and manage monitors with [YAML configuration files](https://github.com/openstatusHQ/cli-template). -- Terraform: Automate the process with our [Terraform provider](/reference/terraform/). - -### Monitor types - -- **HTTP**: Check the availability and performance of your web services by sending HTTP requests and analyzing the responses. -- **TCP**: Verify that your servers are accepting connections on specific ports, ensuring that critical -- **DNS**: Monitor the health of your DNS records by performing lookups and validating responses. - -## Getting started - -Ready to start monitoring? Follow these guides: - -1. **[Create Your First Monitor](/tutorial/how-to-create-monitor)** - Step-by-step tutorial - -## Learn more - -- **[Understanding Uptime Monitoring](/concept/uptime-monitoring)** - Core concepts explained diff --git a/apps/docs/src/content/docs/reference/cli-reference.mdx b/apps/docs/src/content/docs/reference/cli-reference.mdx index 7e9bc081..0e1fa291 100644 --- a/apps/docs/src/content/docs/reference/cli-reference.mdx +++ b/apps/docs/src/content/docs/reference/cli-reference.mdx @@ -1,5 +1,6 @@ --- title: CLI Reference +description: Complete reference for the openstatus CLI — manage status pages, monitors, and incidents from your terminal. --- ## CLI interface - openstatus diff --git a/apps/docs/src/content/docs/reference/maintenance.mdx b/apps/docs/src/content/docs/reference/maintenance.mdx new file mode 100644 index 00000000..1f5c2314 --- /dev/null +++ b/apps/docs/src/content/docs/reference/maintenance.mdx @@ -0,0 +1,90 @@ +--- +title: Maintenance Reference +description: Technical specification for scheduled maintenance windows in openstatus. +--- + +## Overview + +A maintenance window is a scheduled period during which you expect planned disruption to one or more services — a database upgrade, a deployment, or infrastructure work. Announcing it ahead of time lets you communicate the disruption to your users instead of letting your status page register it as an unexpected outage. + +A maintenance belongs to a single status page and targets one or more of that page's components — monitor-linked or static. + +## Behavior + +While a maintenance window is active (the current time is between `from` and `to`): + +- The affected components display the **Under Maintenance** (info) status on the status page. +- A higher-priority event overrides it: an active incident (error) or an unresolved status report (degraded) takes precedence, so the component shows that status instead. Maintenance only outranks the default operational status. +- The maintenance is reflected in the historical status bars for the days it overlaps. + +Maintenance windows **do not** exclude downtime from uptime calculations. The uptime percentage is computed from raw check results and is unaffected by maintenance windows; only the displayed status changes. + +When a maintenance is created, status page subscribers can be notified that it has been scheduled (see [Notify](#notify)). Updating a maintenance never re-notifies. + +## Configuration and Properties + +### Title + +**Type:** String (required) +**Length:** 1–256 characters + +A short, human-readable name for the maintenance window. + +**Example:** `"Database Upgrade"` + +### Message + +**Type:** String (required) + +A description of the maintenance shown to users, explaining what is happening and the expected impact. + +**Example:** `"Upgrading our database to improve performance. Brief interruptions may occur."` + +### From + +**Type:** Datetime (required) +**Format:** RFC 3339 / ISO 8601 (e.g., `2026-01-20T02:00:00Z`) + +When the maintenance window starts. + +### To + +**Type:** Datetime (required) +**Format:** RFC 3339 / ISO 8601 (e.g., `2026-01-20T04:00:00Z`) + +When the maintenance window ends. Must be later than `from`. + +### Status Page + +**Type:** Integer (required) + +The id of the status page this maintenance belongs to. A maintenance is scoped to exactly one status page. + +### Affected Components + +**Type:** Array of integers (optional) +**Default:** `[]` + +The ids of the page components that should display the Under Maintenance status during the window. Each component must belong to the status page referenced above, and can be either a monitor-linked or a static component. + +In the v1 REST API these are passed as `monitorIds`, which accepts monitor components only and is retained for backward compatibility. Static components can be targeted through the dashboard. + +### Notify + +**Type:** Boolean (optional) +**Default:** `false` + +A one-time flag evaluated at creation time — it is **not** stored on the maintenance record and cannot be read back. When set, status page subscribers are notified that the maintenance has been scheduled. + +The v1 REST API does not expose this flag; it notifies subscribers automatically when a maintenance is created on a page whose workspace has subscribers enabled. + +## Relationships + +- **Status page** — a maintenance is tied to a single page. Deleting the page deletes its maintenance windows. +- **Page components** — a maintenance can affect multiple components (monitor-linked or static), and a component can be covered by multiple (including overlapping) maintenance windows. + +## Related resources + +- **[Status Page Reference](/reference/status-page)** - How maintenance windows surface on the public status page. +- **[Page Components](/reference/page-components)** - The monitor and static components a maintenance window can target. +- **[Status Report Reference](/reference/status-report)** - Communicate unplanned incidents, as opposed to scheduled maintenance. diff --git a/apps/docs/src/custom.css b/apps/docs/src/custom.css index ec322f23..6643e04f 100644 --- a/apps/docs/src/custom.css +++ b/apps/docs/src/custom.css @@ -1,9 +1,9 @@ @layer my-reset, starlight; .page > header.header { - background-color: hsl(var(--card)); - border-bottom: 1px solid hsl(var(--border)); - color: hsl(var(--card-foreground)); + background-color: var(--card); + border-bottom: 1px solid var(--border); + color: var(--card-foreground); } .page > header.header .title-wrapper > a { diff --git a/apps/docs/src/global.css b/apps/docs/src/global.css index d8753e46..3cbf46f3 100644 --- a/apps/docs/src/global.css +++ b/apps/docs/src/global.css @@ -55,43 +55,42 @@ :root[data-theme='light'] { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; + --destructive: oklch(0.577 0.245 27.325); - --ring: 215 20.2% 65.1%; + --ring: oklch(0.708 0 0); - --radius: 0.5rem; + --radius: 0; /** Chart Colors */ - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); /* Status Tracker Colors - Radix Color */ --status-degraded: 50 100% 52%; /* Amber 10 */ @@ -101,41 +100,40 @@ } :root { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 85.7% 97.3%; + --destructive: oklch(0.704 0.191 22.216); - --ring: 217.2 32.6% 17.5%; + --ring: oklch(0.556 0 0); /* Chart Colors */ - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); /* Status Tracker Colors - Radix Color */ --status-degraded: 50 100% 52%; /* Amber 10 */ @@ -150,31 +148,31 @@ /* Dark mode colors. */ :root { - --sl-color-accent-low: #020817; - --sl-color-accent: #f8fafc; - --sl-color-accent-high: #f1f5f9; - --sl-color-white: #f8fafc; - --sl-color-gray-1: #f1f5f9; - --sl-color-gray-2: #94a3b8; - --sl-color-gray-3: #64748b; - --sl-color-gray-4: #475569; - --sl-color-gray-5: #1e293b; - --sl-color-gray-6: #0f172a; - --sl-color-black: #020817; + --sl-color-accent-low: oklch(0.205 0 0); + --sl-color-accent: oklch(0.985 0 0); + --sl-color-accent-high: oklch(0.97 0 0); + --sl-color-white: oklch(0.985 0 0); + --sl-color-gray-1: oklch(0.97 0 0); + --sl-color-gray-2: oklch(0.708 0 0); + --sl-color-gray-3: oklch(0.556 0 0); + --sl-color-gray-4: oklch(0.439 0 0); + --sl-color-gray-5: oklch(0.269 0 0); + --sl-color-gray-6: oklch(0.205 0 0); + --sl-color-black: oklch(0.145 0 0); } /* Light mode colors. */ :root[data-theme='light'] { - --sl-color-accent-low: #f8fafc; - --sl-color-accent: #020817; - --sl-color-accent-high: #0f172a; - --sl-color-white: #020817; - --sl-color-gray-1: #0f172a; - --sl-color-gray-2: #1e293b; - --sl-color-gray-3: #475569; - --sl-color-gray-4: #64748b; - --sl-color-gray-5: #94a3b8; - --sl-color-gray-6: #f1f5f9; - --sl-color-gray-7: #f8fafc; - --sl-color-black: #ffffff; + --sl-color-accent-low: oklch(0.97 0 0); + --sl-color-accent: oklch(0.205 0 0); + --sl-color-accent-high: oklch(0.145 0 0); + --sl-color-white: oklch(0.145 0 0); + --sl-color-gray-1: oklch(0.205 0 0); + --sl-color-gray-2: oklch(0.439 0 0); + --sl-color-gray-3: oklch(0.556 0 0); + --sl-color-gray-4: oklch(0.708 0 0); + --sl-color-gray-5: oklch(0.87 0 0); + --sl-color-gray-6: oklch(0.97 0 0); + --sl-color-gray-7: oklch(0.985 0 0); + --sl-color-black: oklch(1 0 0); } diff --git a/apps/docs/src/starlight-component-overrides.d.ts b/apps/docs/src/starlight-component-overrides.d.ts new file mode 100644 index 00000000..79493f59 --- /dev/null +++ b/apps/docs/src/starlight-component-overrides.d.ts @@ -0,0 +1,5 @@ +// Copied Starlight component overrides (Header.astro) import the per-component +// `virtual:starlight/components/*` modules, whose types live in Starlight's +// internal declarations rather than its public `virtual.d.ts`. Pull them into +// scope so `astro check` and the editor can resolve the imports. +///