refactor: Update site configuration documentation and enhance global …#608
refactor: Update site configuration documentation and enhance global …#608rajnandan1 merged 5 commits intomainfrom
Conversation
…page visibility settings - Revise site configuration documentation to clarify page visibility behavior. - Introduce global page visibility settings with detailed descriptions and functionality. - Modify API server to dynamically select the correct specification path based on environment. - Streamline event fetching logic in event pages to improve performance and maintainability. - Remove unused vault secret management code from the manage API. - Enhance customizations page to support global page visibility settings. - Create new guides for adding custom fonts and custom JavaScript/CSS. - Implement server-side logic for handling events by month with improved date validation.
There was a problem hiding this comment.
Pull request overview
This PR refactors site configuration and page-scoped behavior by introducing global page visibility settings (including exclusivity), updating public navigation/events to respect those settings, and expanding/clarifying the documentation and docs tooling accordingly.
Changes:
- Add
globalPageVisibilitySettingsto site data, expose it in manage UI, and consume it in public UI (page switcher / brand link / calendar link). - Update events-by-month flow to optionally filter incidents/maintenances by page monitors (while still including
is_global=YESevents). - Improve docs: site configuration behavior, custom CSS injection, and add guides for custom fonts + custom JS/CSS; plus docs indexing updates.
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/routes/(manage)/manage/app/site-configurations/+page.svelte | Adds UI + persistence for globalPageVisibilitySettings; removes “Home Path” from Site Information. |
| src/routes/(manage)/manage/app/customizations/+page.svelte | Fixes docs links to use clientResolver (and corrects broken URLs). |
| src/routes/(manage)/manage/api/+server.ts | Removes vault secret management actions/imports. |
| src/routes/(kener)/events/[MMMM]-[YYYY]/+page.svelte | Refactors month parsing/navigation and passes page_path to events-by-month API. |
| src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.svelte | New page-scoped events UI (but currently links navigate out of page scope). |
| src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.server.ts | New SSR month validation/timestamps for page-scoped events. |
| src/routes/(docs)/docs/spec/v4/spec.json/+server.ts | Dynamically selects spec path for dev vs prod builds. |
| src/routes/(docs)/docs/content/v4/setup/site-configuration.md | Documents global page visibility settings + runtime effects. |
| src/routes/(docs)/docs/content/v4/setup/customizations.md | Updates Custom CSS behavior to “injected into <head>”. |
| src/routes/(docs)/docs/content/v4/guides/custom-js-css-guide.md | Adds a guide for adding custom JS/CSS via static files or inline CSS. |
| src/routes/(docs)/docs/content/v4/guides/custom-fonts.md | Adds a guide for hosted fonts and self-hosted fonts via @font-face. |
| src/routes/(docs)/docs/content/v4/getting-started/introduction.md | Updates upgrade pointer to v4 changelogs. |
| src/routes/(docs)/docs/content/v4/getting-started/basic-setup.md | Removes “Home Path” from docs. |
| src/routes/(docs)/docs/content/v4/changelogs/v4.0.0.md | Adds “Known migration issues” and expands upgrade checklist. |
| src/routes/(docs)/docs/content/v3/monitors-*.md | Updates eval examples (currently introduces invalid JS syntax in snippets). |
| src/routes/(docs)/docs.json | Adds the new guides to the v4 navigation. |
| src/lib/types/site.ts | Introduces GlobalPageVisibilitySettings type. |
| src/lib/server/db/seedSiteData.ts | Adds default globalPageVisibilitySettings. |
| src/lib/server/db/repositories/incidents.ts | Adds optional monitor-tag filtering (OR global events). |
| src/lib/server/db/repositories/maintenances.ts | Adds optional monitor-tag filtering (OR global events). |
| src/lib/server/api-server/events-by-month/post.ts | Accepts page_path and filters events by page monitors when applicable. |
| src/lib/server/controllers/siteDataKeys.ts | Registers globalPageVisibilitySettings as a site data key (JSON). |
| src/lib/server/controllers/siteDataController.ts | Adds typing for globalPageVisibilitySettings. |
| src/lib/server/controllers/layoutController.ts | Exposes globalPageVisibilitySettings to all layouts. |
| src/lib/components/ThemePlus.svelte | Hides PageSelector when exclusivity is forced / switcher hidden. |
| src/lib/components/NotificationsPopover.svelte | Makes calendar link page-scoped when exclusivity is forced. |
| src/lib/components/KenerNav.svelte | Makes brand/logo link page-scoped when exclusivity is forced. |
| scripts/index-docs.ts | Indexes docs pages from all tabs’ sidebars. |
| migrations/20260219165446_add_global_colum_incidents.ts | Makes maintenances-table guard more robust (but down migration still needs column guard). |
| migrations/20260128120000_redesign_subscription_system.ts | Makes index/constraint/foreign-key creation idempotent via guarded alter attempts. |
| migrations/20260123110239_maintenace_monitor_status.ts | Adds table-existence guards. |
| migrations/20260109120000_add_maintenances_tables.ts | Adds is_global and default monitor_impact columns. |
| src/lib/server/db/repositories/vault.ts | Removes unused vault repository. |
| src/lib/server/controllers/vaultController.ts | Removes unused vault controller. |
| src/lib/server/db/dbimpl.ts | Removes vault repository bindings. |
| AGENTS.md / .github/copilot-instructions.md / .claude/skills/code-context/SKILL.md / .codearch/* | Updates/renames architecture-doc skill and removes old .codearch docs. |
Comments suppressed due to low confidence (1)
src/routes/(docs)/docs/content/v3/monitors-tcp.md:37
- This eval snippet uses
async function (arrayOfPings) { ... }without a function name, which is invalid JavaScript syntax. Use a function expression (wrapped) or a named function so the documentation example is runnable as-is.
```javascript
async function (arrayOfPings) {
let latencyTotal = arrayOfPings.reduce((acc, ping) => {
return acc + ping.latency
}, 0)
| <div class="flex justify-between"> | ||
| {#if showPrevButton} | ||
| <Button | ||
| variant="outline" | ||
| rel="external" | ||
| class="rounded-full shadow-none" | ||
| href={clientResolver(resolve, `/events/${prevMonthPath}`)} | ||
| > | ||
| <ArrowLeft class="mr-2 h-4 w-4" /> | ||
| {$formatDate(prevMonth, "MMMM yyyy")} | ||
| </Button> | ||
| {:else} | ||
| <div></div> | ||
| {/if} | ||
| {#if showNextButton} | ||
| <Button | ||
| variant="outline" | ||
| rel="external" | ||
| class="rounded-full shadow-none" | ||
| href={clientResolver(resolve, `/events/${nextMonthPath}`)} | ||
| > | ||
| {$formatDate(nextMonth, "MMMM yyyy")} | ||
| <ArrowRight class="ml-2 h-4 w-4" /> | ||
| </Button> |
There was a problem hiding this comment.
The bottom navigation links also point to /events/... (global route) instead of staying within /{page_path}/events/.... This breaks page-scoped navigation when browsing months from a page-specific events view.
| import { GetPageByPathWithMonitors } from "$lib/server/controllers/controller.js"; | ||
|
|
||
| const MIN_YEAR = 2023; | ||
|
|
||
| export const load: PageServerLoad = async ({ params, parent }) => { | ||
| const parentData = await parent(); | ||
|
|
There was a problem hiding this comment.
This load function currently has unused imports/variables (GetPageByPathWithMonitors, parentData), which will fail typecheck/lint in many TS configs. Also, unlike /(kener)/[page_path]/+page.server.ts, it never validates that params.page_path exists; consider using GetPageByPathWithMonitors (or db.getPageByPath) to 404 early for invalid page paths so the events page doesn't render and then fail later during client fetch.
|
|
||
| <div class="theme-plus-bar scrollbar-hidden sticky top-18 z-20 flex w-full items-center gap-2 rounded py-2"> | ||
| <PageSelector /> | ||
| {#if !!!page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} |
There was a problem hiding this comment.
Using !!! here is redundant and makes the condition harder to read. !page.data.globalPageVisibilitySettings.forceExclusivity is equivalent and clearer (and you may also want optional chaining if this data can ever be absent during hydration).
| {#if !!!page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} | |
| {#if !page.data.globalPageVisibilitySettings?.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} |
| ```javascript | ||
| ;(async function (statusCode, responseTime, responseRaw, modules) { | ||
| async function (statusCode, responseTime, responseRaw, modules) { | ||
| let status = "DOWN" | ||
|
|
There was a problem hiding this comment.
These eval examples use async function (statusCode, ...) { ... } without a function name, which is invalid JavaScript syntax for a function declaration. To keep the snippet copy/pasteable, use an async function expression (wrap in parentheses) or provide a named function (or an arrow function) consistently across the examples.
| if (await knex.schema.hasTable("maintenances")) { | ||
| await knex.schema.table("maintenances", (table) => { | ||
| table.dropColumn("is_global"); | ||
| }); | ||
| } |
There was a problem hiding this comment.
In the down migration, the maintenances table existence is checked but the is_global column existence is not. If the column was never created (or was already removed), dropColumn("is_global") can throw. Consider adding a hasColumn("maintenances", "is_global") guard similar to the up migration.
| <Button | ||
| rel="external" | ||
| variant="outline" | ||
| class="size-8 rounded-full p-0 shadow-none" | ||
| href={clientResolver(resolve, `/events/${prevMonthPath}`)} | ||
| > | ||
| <ICONS.CHEVRON_LEFT class="size-5" /> | ||
| </Button> | ||
| <p class="text-2xl">{$formatDate(parsedDate, "MMMM yyyy")}</p> | ||
| <Button | ||
| rel="external" | ||
| href={clientResolver(resolve, `/events/${nextMonthPath}`)} | ||
| variant="outline" | ||
| class="size-8 rounded-full p-0 shadow-none" | ||
| > | ||
| <ICONS.CHEVRON_RIGHT class="size-5" /> |
There was a problem hiding this comment.
The prev/next month links here point to /events/... and will navigate out of the current /{page_path}/events/... scope. For page-scoped events this should include the current page_path segment so navigation stays on the same page (e.g., /${page.params.page_path}/events/...).
| // get site data | ||
| const siteData = await GetAllSiteData(); | ||
| const { globalPageVisibilitySettings } = siteData; | ||
| const isExclusivePageEnabled = !!globalPageVisibilitySettings?.forceExclusivity; | ||
|
|
||
| if (isExclusivePageEnabled && !pagePath) { | ||
| pagePath = ""; | ||
| } |
There was a problem hiding this comment.
This endpoint fetches all site data from the DB on every request just to check globalPageVisibilitySettings.forceExclusivity. For better performance, fetch only the needed key (e.g. GetSiteDataByKey("globalPageVisibilitySettings")) and fall back to the default when missing.
|
|
||
| ```javascript | ||
| ;(async function (arrayOfPings) { | ||
| async function (arrayOfPings) { |
There was a problem hiding this comment.
This code block starts with async function (arrayOfPings) { ... } (no name), which is not valid JavaScript for a function declaration. Since this section is intended to be copy/pasteable eval code, please switch to a valid anonymous function expression (e.g., wrap in parentheses) or give the function a name.
| async function (arrayOfPings) { | |
| async (arrayOfPings) => { |
| ```javascript | ||
| ;(async function (responseTime, responseRaw) { | ||
| async function (responseTime, responseRaw) { | ||
| return { | ||
| status: "UP", | ||
| latency: responseTime |
There was a problem hiding this comment.
This snippet uses async function (responseTime, responseRaw) { ... } without a function name, which is invalid JavaScript unless it's a function expression. Please update the example to a valid form (named function, arrow function, or wrapped function expression) so readers can copy/paste it.
| import { requestMonitorBar } from "$lib/client/monitor-bar-client"; | ||
| import type { MonitorBarResponse } from "$lib/server/api-server/monitor-bar/get"; | ||
| import { SveltePurify } from "@humanspeak/svelte-purify"; | ||
| import { page } from "$app/state"; |
There was a problem hiding this comment.
The import page from $app/state on line 17 is not used anywhere in this component. This unused import should be removed to keep the codebase clean.
| const DEV_PATH = join(process.cwd(), "static", "api-references", "v4.json"); | ||
| const PROD_PATH = join(process.cwd(), "build", "client", "api-references", "v4.json"); | ||
| const SPEC_PATH = existsSync(PROD_PATH) ? PROD_PATH : DEV_PATH; |
There was a problem hiding this comment.
The path selection logic evaluates SPEC_PATH at module load time (line 8), which means the path is determined once when the server starts and cannot adapt if the file system changes during runtime.
This is generally fine for production deployments where the build output is static. However, during development transitions (e.g., switching between dev and production builds without restarting), the cached path value could point to a stale or missing file.
Consider wrapping the existsSync check inside the GET handler to ensure fresh evaluation on each request, or document this as a known limitation that requires a server restart when switching build modes.
| const response = await fetch( | ||
| clientResolver(resolve, "/dashboard-apis/events-by-month") + `?page_path=${page.params.page_path}`, | ||
| { |
There was a problem hiding this comment.
The query parameter page_path is being appended to the URL even when it's undefined in the base events route (without page_path in the URL). This will send ?page_path=undefined to the API, which is handled by the sanitization logic on lines 23-25, but it would be cleaner to conditionally add the query parameter only when page.params.page_path is defined.
Consider using a conditional to build the URL:
const url = clientResolver(resolve, "/dashboard-apis/events-by-month");
const queryParam = page.params.page_path ? `?page_path=${page.params.page_path}` : "";
const response = await fetch(url + queryParam, { ... });|
|
||
| <div class="theme-plus-bar scrollbar-hidden sticky top-18 z-20 flex w-full items-center gap-2 rounded py-2"> | ||
| <PageSelector /> | ||
| {#if !!!page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} |
There was a problem hiding this comment.
The logic on line 81 uses triple negation (!!!) which makes the condition harder to read and reason about. The expression evaluates to false when forceExclusivity is truthy, but the triple negation is unnecessarily complex.
Simplify to:
{#if !page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher}This directly expresses "show the page selector when forceExclusivity is NOT enabled AND showSwitcher is enabled", which is clearer.
| {#if !!!page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} | |
| {#if !page.data.globalPageVisibilitySettings.forceExclusivity && page.data.globalPageVisibilitySettings.showSwitcher} |
…page visibility settings