@checkstack/slo-frontend 0.4.7 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +103 -0
- package/package.json +16 -16
- package/src/components/SloSignalsFiller.tsx +78 -0
- package/src/components/SystemSloBadge.tsx +5 -4
- package/src/index.tsx +29 -13
- package/src/components/SloMenuItems.tsx +0 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,108 @@
|
|
|
1
1
|
# @checkstack/slo-frontend
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9dcc848: Redesign the dashboard as an extensible "needs attention" overview, and normalize system state badges.
|
|
8
|
+
|
|
9
|
+
The dashboard now surfaces ONLY systems that need attention (degraded, unhealthy, breaching/at-risk SLO, under an incident or active maintenance, anomalous, or with a dependency problem) and hides everything healthy. A compact header summarises fleet health and filters by severity; each problem renders as an elevated card with one row per issue that deep-links to where the issue originates. A calm "all clear" state shows when nothing needs attention, a live "recent activity" feed sits below, and a "View catalog" link replaces the duplicated system list.
|
|
10
|
+
|
|
11
|
+
New platform contract `SystemSignalsSlot` (`@checkstack/catalog-common`): a headless, render-once slot where any plugin bulk-fetches and reports structured `SystemSignal[]` per system via `onSignals(sourceId, map)`. The dashboard aggregates every source agnostic to which plugins contribute; each core reliability plugin (healthcheck, incident, SLO, maintenance, anomaly, dependency) ships a filler, and third-party plugins add new per-system state the same way with no dashboard change. Signals carry an `iconName` rendered via `DynamicIcon` so the contract stays React-free. The dashboard's old summary tiles and overview sheets are removed, so it no longer depends on those plugins' packages. The group "subscribe" control moved onto the catalog browse page's group headers.
|
|
12
|
+
|
|
13
|
+
System state badges are normalized into one icon-only `@checkstack/ui` `StatusBadge` primitive - a small tinted icon chip with the full label on hover/focus (and via `aria-label`). Each signal uses its feature's navbar icon (health = Activity, incident = AlertTriangle, SLO = Target, maintenance = Wrench, dependency = GitBranch; anomaly = ChartSpline). Badges self-sort by severity via CSS `order` (error -> warn -> info), tooltips are scoped to a named group, and in catalog browse rows the cluster moved to the right edge.
|
|
14
|
+
|
|
15
|
+
This is a beta minor.
|
|
16
|
+
|
|
17
|
+
- 9dcc848: Cut initial-load JS: lazy plugin contributions, a hardened lazy-by-default contribution contract, on-demand Monaco, and a lighter icon/chart load.
|
|
18
|
+
|
|
19
|
+
- Lazy plugin route pages: each plugin's route `element` references a `React.lazy`-wrapped page rendered inside a shared `<Suspense>` boundary. Plugins still register synchronously, so nav, slots, commands, API factories, and `foreignSignals` are available on first paint. This moves ~37 route-page chunks (~600 KB) out of the entry; the entry chunk drops from ~2.4 MB to ~190 KB. Auth flow pages stay eager. The `@checkstack/scripts` scaffold template generates lazy route pages too.
|
|
20
|
+
- Hardened contribution contract (BREAKING, frontend plugin contract): plugins declare contributions lazily and let the framework own code-splitting, Suspense, and per-plugin error isolation. Routes use `load: () => import("./Page").then((m) => ({ default: m.Page }))` instead of `element: <Page />` (`element` is still accepted for the rare page that must paint without a chunk fetch; provide exactly one). Slot extensions accept either an eager `component` or a lazy `load`; new `getLazyContribution` + `ExtensionComponent` exports from `@checkstack/frontend-api` render either kind. This also fixes runtime-installed plugins: `ExtensionSlot` subscribes to the plugin registry, and the API registry rebuilds when the plugin set changes (`getPlugins()` returns an immutable snapshot via `useSyncExternalStore`). A per-plugin error boundary contains a bad contribution.
|
|
21
|
+
- On-demand Monaco: the `@checkstack/ui` barrel no longer pulls the `@codingame/*` / `monaco-languageclient` stack into the initial load. `CodeEditor` lazy-loads its Monaco-backed editor behind `React.lazy` + Suspense, `validateTypeScriptSources` imports the editor API via in-body `await import(...)`, and the "vscode services ready" signal moved to a Monaco-free module. The ~10 MB editor body loads only when a `CodeEditor` mounts. A `react-vendor` `manualChunks` split was added for stable vendor caching.
|
|
22
|
+
- lucide-react 1.x + lighter icons/charts (BREAKING for icon consumers): lucide-react unified from three drifting ranges to `^1.17.0`. lucide v1 removed brand icons, so the GitHub/GitLab marks are vendored in `@checkstack/ui` (`GithubIcon`, `GitlabIcon`, `brandIcons`); a new `IconName` type (`LucideIconName | BrandIconName`) in `@checkstack/common` is canonical, accepted by `AuthStrategy.icon` and the card components, so data-driven brand names keep working. `DynamicIcon` no longer eagerly imports lucide's ~1600-icon map (~1 MB) - it lives in a `React.lazy` `iconRegistry` chunk fetched on first data-driven render, while statically named-imported icons tree-shake normally. The recharts-backed health-check charts (~300 KB) and the `HealthCheckSystemOverview` drawer leave the initial load.
|
|
23
|
+
|
|
24
|
+
BREAKING CHANGES:
|
|
25
|
+
|
|
26
|
+
- Frontend plugin contract: routes/slot contributions are lazy-by-default (`load` instead of `element`/eager elements) as described above.
|
|
27
|
+
- Any external consumer importing a brand icon from `lucide-react` (e.g. `import { Github } from "lucide-react"`) must switch to the vendored `@checkstack/ui` brand icons or a custom SVG.
|
|
28
|
+
|
|
29
|
+
This is a beta minor.
|
|
30
|
+
|
|
31
|
+
- 9dcc848: Align workspace dependency versions and migrate React Router to v7.
|
|
32
|
+
|
|
33
|
+
BREAKING CHANGES (React Router v7): All frontend packages now depend on `react-router-dom@^7.16.0`. Previously the workspace declared four divergent ranges (`^6.20.0`, `^6.22.0`, `^7.1.1`, `^7.14.2`), which resolved both `react-router@6` and `react-router@7` into a single bundle. Everything is now unified on v7. The public imports the app uses (`BrowserRouter`, `Routes`, `Route`, `Link`, `NavLink`, `MemoryRouter`, `useNavigate`, `useParams`, `useSearchParams`, `useLocation`) are unchanged between v6 and v7, so no source rewrites were required - but any out-of-tree plugin still on react-router v6 should upgrade to v7 (see the React Router v6 -> v7 upgrade guide) to share the host's single router instance via the import map.
|
|
34
|
+
|
|
35
|
+
Other unified ranges (no API change): `react` -> `^18.3.1`, the `@orpc/*` family (`contract`, `server`, `client`, `tanstack-query`, `openapi`, `zod`) -> `^1.14.4`, and `better-auth` -> `^1.6.13`.
|
|
36
|
+
|
|
37
|
+
Removed the pre-rename `@orpc/react-query` leftover from `@checkstack/frontend-api`; its `createRouterUtils` / `RouterUtils` / `ProcedureUtils` now come from `@orpc/tanstack-query` (the package already in use).
|
|
38
|
+
|
|
39
|
+
Stale in-range runtime deps pulled up to current published versions: `hono` `^4.12.23`, `@tanstack/react-query` (+devtools) `^5.100.14`, `date-fns` `^4.4.0`, `jose` `^6.2.3`, `tar` `^7.5.16`, `semver` `^7.8.1`, `@xyflow/react` `^12.11.0`.
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 9dcc848: Move primary navigation into a left sidebar, and serve the user guide in-app.
|
|
44
|
+
|
|
45
|
+
Feature navigation (a ~20-item user-menu dropdown) now lives in a persistent left sidebar (a slide-over drawer on mobile), grouped by section with the active route highlighted; the user menu keeps only account actions. A route opts into the sidebar with new `nav` metadata (`{ group, icon, label?, order?, accessRule? }`) on its registration, co-located with path + access + title. The sidebar filters entries with the same access check as page guards. `@checkstack/common` gains `isAccessRuleSatisfied` and a centralized set of in-app doc slugs (`APP_DOC_SLUGS` + `docsPath`, with a test asserting each resolves to a real docs page); `@checkstack/auth-frontend` exports `useAccessRules`.
|
|
46
|
+
|
|
47
|
+
The backend now serves the Astro Starlight docs build same-origin at `/checkstack/*` (the same artifact deployed to GitHub Pages), so the user guide is available inside the app including for self-hosted / air-gapped installs (served verbatim, no rebuild, no link rewriting; from `CHECKSTACK_DOCS_DIST`, before the SPA catch-all, degrading gracefully when absent; the Docker image builds and ships `docs/dist`; Vite proxies `/checkstack` in dev). The "Docs" link is a shell-owned external sidebar entry under the Documentation group (book icon), opening `/checkstack/user-guide/` in a new tab; the group renders even when no plugin route contributes to it.
|
|
48
|
+
|
|
49
|
+
BREAKING (plugin authors): `UserMenuItemsSlot` is no longer the way to add navigation - registering a top user-menu item no longer surfaces it anywhere. Add `nav` to the page's route instead. `UserMenuItemsBottomSlot` (account items) is unchanged. All bundled plugins have been migrated.
|
|
50
|
+
|
|
51
|
+
This is a beta minor.
|
|
52
|
+
|
|
53
|
+
- Updated dependencies [9dcc848]
|
|
54
|
+
- Updated dependencies [9dcc848]
|
|
55
|
+
- Updated dependencies [9dcc848]
|
|
56
|
+
- Updated dependencies [9dcc848]
|
|
57
|
+
- Updated dependencies [9dcc848]
|
|
58
|
+
- Updated dependencies [9dcc848]
|
|
59
|
+
- Updated dependencies [9dcc848]
|
|
60
|
+
- Updated dependencies [9dcc848]
|
|
61
|
+
- Updated dependencies [9dcc848]
|
|
62
|
+
- Updated dependencies [9dcc848]
|
|
63
|
+
- Updated dependencies [9dcc848]
|
|
64
|
+
- Updated dependencies [9dcc848]
|
|
65
|
+
- Updated dependencies [9dcc848]
|
|
66
|
+
- Updated dependencies [9dcc848]
|
|
67
|
+
- @checkstack/ui@1.13.0
|
|
68
|
+
- @checkstack/healthcheck-common@1.5.0
|
|
69
|
+
- @checkstack/catalog-common@2.3.0
|
|
70
|
+
- @checkstack/common@0.13.0
|
|
71
|
+
- @checkstack/dashboard-frontend@0.8.0
|
|
72
|
+
- @checkstack/frontend-api@0.7.0
|
|
73
|
+
- @checkstack/tips-frontend@0.3.0
|
|
74
|
+
- @checkstack/slo-common@0.5.0
|
|
75
|
+
- @checkstack/dependency-common@1.2.0
|
|
76
|
+
- @checkstack/signal-frontend@0.2.0
|
|
77
|
+
|
|
78
|
+
## 0.4.8
|
|
79
|
+
|
|
80
|
+
### Patch Changes
|
|
81
|
+
|
|
82
|
+
- Updated dependencies [b995afb]
|
|
83
|
+
- Updated dependencies [270ef29]
|
|
84
|
+
- Updated dependencies [270ef29]
|
|
85
|
+
- Updated dependencies [270ef29]
|
|
86
|
+
- Updated dependencies [270ef29]
|
|
87
|
+
- Updated dependencies [b995afb]
|
|
88
|
+
- Updated dependencies [b995afb]
|
|
89
|
+
- Updated dependencies [b995afb]
|
|
90
|
+
- Updated dependencies [b995afb]
|
|
91
|
+
- Updated dependencies [b995afb]
|
|
92
|
+
- Updated dependencies [b995afb]
|
|
93
|
+
- Updated dependencies [270ef29]
|
|
94
|
+
- Updated dependencies [270ef29]
|
|
95
|
+
- Updated dependencies [b995afb]
|
|
96
|
+
- Updated dependencies [b995afb]
|
|
97
|
+
- Updated dependencies [b995afb]
|
|
98
|
+
- Updated dependencies [270ef29]
|
|
99
|
+
- Updated dependencies [b995afb]
|
|
100
|
+
- Updated dependencies [270ef29]
|
|
101
|
+
- @checkstack/ui@1.12.0
|
|
102
|
+
- @checkstack/healthcheck-common@1.4.0
|
|
103
|
+
- @checkstack/dashboard-frontend@0.7.8
|
|
104
|
+
- @checkstack/tips-frontend@0.2.7
|
|
105
|
+
|
|
3
106
|
## 0.4.7
|
|
4
107
|
|
|
5
108
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/slo-frontend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.tsx",
|
|
@@ -13,26 +13,26 @@
|
|
|
13
13
|
"lint:code": "eslint . --max-warnings 0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@checkstack/catalog-common": "2.2.
|
|
17
|
-
"@checkstack/common": "0.
|
|
18
|
-
"@checkstack/dashboard-frontend": "0.7.
|
|
19
|
-
"@checkstack/dependency-common": "1.1.
|
|
20
|
-
"@checkstack/frontend-api": "0.
|
|
21
|
-
"@checkstack/healthcheck-common": "1.
|
|
22
|
-
"@checkstack/signal-frontend": "0.1.
|
|
23
|
-
"@checkstack/slo-common": "0.4.
|
|
24
|
-
"@checkstack/tips-frontend": "0.2.
|
|
25
|
-
"@checkstack/ui": "1.
|
|
26
|
-
"date-fns": "^4.
|
|
27
|
-
"lucide-react": "^
|
|
28
|
-
"react": "^18.
|
|
29
|
-
"react-router-dom": "^
|
|
16
|
+
"@checkstack/catalog-common": "2.2.3",
|
|
17
|
+
"@checkstack/common": "0.12.0",
|
|
18
|
+
"@checkstack/dashboard-frontend": "0.7.8",
|
|
19
|
+
"@checkstack/dependency-common": "1.1.3",
|
|
20
|
+
"@checkstack/frontend-api": "0.6.0",
|
|
21
|
+
"@checkstack/healthcheck-common": "1.4.0",
|
|
22
|
+
"@checkstack/signal-frontend": "0.1.5",
|
|
23
|
+
"@checkstack/slo-common": "0.4.2",
|
|
24
|
+
"@checkstack/tips-frontend": "0.2.7",
|
|
25
|
+
"@checkstack/ui": "1.12.0",
|
|
26
|
+
"date-fns": "^4.4.0",
|
|
27
|
+
"lucide-react": "^1.17.0",
|
|
28
|
+
"react": "^18.3.1",
|
|
29
|
+
"react-router-dom": "^7.16.0",
|
|
30
30
|
"recharts": "^3.8.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "^5.0.0",
|
|
34
34
|
"@types/react": "^18.2.0",
|
|
35
35
|
"@checkstack/tsconfig": "0.0.7",
|
|
36
|
-
"@checkstack/scripts": "0.3.
|
|
36
|
+
"@checkstack/scripts": "0.3.4"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { useEffect, useMemo } from "react";
|
|
2
|
+
import { usePluginClient, type SlotContext } from "@checkstack/frontend-api";
|
|
3
|
+
import { resolveRoute } from "@checkstack/common";
|
|
4
|
+
import {
|
|
5
|
+
SystemSignalsSlot,
|
|
6
|
+
type SystemSignal,
|
|
7
|
+
type SystemSignalsMap,
|
|
8
|
+
} from "@checkstack/catalog-common";
|
|
9
|
+
import { SloApi, sloRoutes } from "@checkstack/slo-common";
|
|
10
|
+
|
|
11
|
+
type Props = SlotContext<typeof SystemSignalsSlot>;
|
|
12
|
+
|
|
13
|
+
const SOURCE_ID = "slo";
|
|
14
|
+
const AT_RISK_BUDGET_PERCENT = 20;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reports breaching, degraded, and at-risk SLOs as dashboard signals.
|
|
18
|
+
* Bulk-fetches objectives for all overview systems and emits one signal per
|
|
19
|
+
* objective that needs attention, deep-linking to that objective's detail page.
|
|
20
|
+
* Headless filler for {@link SystemSignalsSlot}.
|
|
21
|
+
*/
|
|
22
|
+
export const SloSignalsFiller: React.FC<Props> = ({ systemIds, onSignals }) => {
|
|
23
|
+
const sloClient = usePluginClient(SloApi);
|
|
24
|
+
|
|
25
|
+
const { data } = sloClient.getBulkObjectivesForSystems.useQuery(
|
|
26
|
+
{ systemIds },
|
|
27
|
+
{ enabled: systemIds.length > 0, staleTime: 30_000 },
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const signals = useMemo<SystemSignalsMap>(() => {
|
|
31
|
+
const result: SystemSignalsMap = {};
|
|
32
|
+
if (!data) return result;
|
|
33
|
+
|
|
34
|
+
for (const systemId of systemIds) {
|
|
35
|
+
const objectives = data.systems[systemId] ?? [];
|
|
36
|
+
const systemSignals: SystemSignal[] = [];
|
|
37
|
+
|
|
38
|
+
for (const { objective, status } of objectives) {
|
|
39
|
+
let tone: SystemSignal["tone"];
|
|
40
|
+
let label: string;
|
|
41
|
+
if (status.isBreaching) {
|
|
42
|
+
tone = "error";
|
|
43
|
+
label = "SLO breaching";
|
|
44
|
+
} else if (status.hasOpenDowntime) {
|
|
45
|
+
tone = "warn";
|
|
46
|
+
label = "SLO degraded";
|
|
47
|
+
} else if (
|
|
48
|
+
status.errorBudgetRemainingPercent <= AT_RISK_BUDGET_PERCENT
|
|
49
|
+
) {
|
|
50
|
+
tone = "warn";
|
|
51
|
+
label = "SLO at risk";
|
|
52
|
+
} else {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
systemSignals.push({
|
|
57
|
+
source: SOURCE_ID,
|
|
58
|
+
tone,
|
|
59
|
+
label,
|
|
60
|
+
detail: `${objective.target}% target over ${objective.windowDays}d`,
|
|
61
|
+
href: resolveRoute(sloRoutes.routes.detail, {
|
|
62
|
+
sloId: objective.id,
|
|
63
|
+
}),
|
|
64
|
+
iconName: "Target",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (systemSignals.length > 0) result[systemId] = systemSignals;
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}, [data, systemIds]);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
onSignals(SOURCE_ID, signals);
|
|
75
|
+
}, [signals, onSignals]);
|
|
76
|
+
|
|
77
|
+
return null;
|
|
78
|
+
};
|
|
@@ -2,7 +2,8 @@ import React from "react";
|
|
|
2
2
|
import { usePluginClient, type SlotContext } from "@checkstack/frontend-api";
|
|
3
3
|
import { SystemStateBadgesSlot } from "@checkstack/catalog-common";
|
|
4
4
|
import { SloApi } from "../api";
|
|
5
|
-
import {
|
|
5
|
+
import { StatusBadge } from "@checkstack/ui";
|
|
6
|
+
import { Target } from "lucide-react";
|
|
6
7
|
|
|
7
8
|
type Props = SlotContext<typeof SystemStateBadgesSlot>;
|
|
8
9
|
|
|
@@ -30,15 +31,15 @@ export const SystemSloBadge: React.FC<Props> = ({ system }) => {
|
|
|
30
31
|
);
|
|
31
32
|
|
|
32
33
|
if (hasBreaching) {
|
|
33
|
-
return <
|
|
34
|
+
return <StatusBadge tone="error" icon={Target} label="SLO breaching" />;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
if (hasDegraded) {
|
|
37
|
-
return <
|
|
38
|
+
return <StatusBadge tone="warn" icon={Target} label="SLO degraded" />;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
if (hasAtRisk) {
|
|
41
|
-
return <
|
|
42
|
+
return <StatusBadge tone="warn" icon={Target} label="SLO at risk" />;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
return;
|
package/src/index.tsx
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createFrontendPlugin,
|
|
3
3
|
createSlotExtension,
|
|
4
|
-
UserMenuItemsSlot,
|
|
5
4
|
} from "@checkstack/frontend-api";
|
|
5
|
+
import { Target, Settings } from "lucide-react";
|
|
6
6
|
import { sloRoutes, pluginMetadata, sloAccess } from "@checkstack/slo-common";
|
|
7
|
-
import { SloOverviewPage } from "./pages/SloOverviewPage";
|
|
8
|
-
import { SloConfigPage } from "./pages/SloConfigPage";
|
|
9
|
-
import { SloDetailPage } from "./pages/SloDetailPage";
|
|
10
7
|
import { SystemSloPanel } from "./components/SystemSloPanel";
|
|
11
8
|
import { SystemSloBadge } from "./components/SystemSloBadge";
|
|
12
|
-
import { SloMenuItems } from "./components/SloMenuItems";
|
|
13
9
|
import {
|
|
14
10
|
SystemDetailsTopSlot,
|
|
15
11
|
SystemStateBadgesSlot,
|
|
12
|
+
SystemSignalsSlot,
|
|
16
13
|
} from "@checkstack/catalog-common";
|
|
17
14
|
|
|
18
15
|
export default createFrontendPlugin({
|
|
@@ -20,28 +17,40 @@ export default createFrontendPlugin({
|
|
|
20
17
|
routes: [
|
|
21
18
|
{
|
|
22
19
|
route: sloRoutes.routes.overview,
|
|
23
|
-
|
|
20
|
+
load: () =>
|
|
21
|
+
import("./pages/SloOverviewPage").then((m) => ({
|
|
22
|
+
default: m.SloOverviewPage,
|
|
23
|
+
})),
|
|
24
24
|
title: "SLO Dashboard",
|
|
25
|
+
nav: {
|
|
26
|
+
group: "Reliability",
|
|
27
|
+
icon: Target,
|
|
28
|
+
},
|
|
25
29
|
},
|
|
26
30
|
{
|
|
27
31
|
route: sloRoutes.routes.config,
|
|
28
|
-
|
|
32
|
+
load: () =>
|
|
33
|
+
import("./pages/SloConfigPage").then((m) => ({
|
|
34
|
+
default: m.SloConfigPage,
|
|
35
|
+
})),
|
|
29
36
|
title: "SLO Management",
|
|
30
37
|
accessRule: sloAccess.slo.manage,
|
|
38
|
+
nav: {
|
|
39
|
+
group: "Reliability",
|
|
40
|
+
icon: Settings,
|
|
41
|
+
},
|
|
31
42
|
},
|
|
32
43
|
{
|
|
33
44
|
route: sloRoutes.routes.detail,
|
|
34
|
-
|
|
45
|
+
load: () =>
|
|
46
|
+
import("./pages/SloDetailPage").then((m) => ({
|
|
47
|
+
default: m.SloDetailPage,
|
|
48
|
+
})),
|
|
35
49
|
title: "SLO Detail",
|
|
36
50
|
},
|
|
37
51
|
],
|
|
38
52
|
apis: [],
|
|
39
53
|
extensions: [
|
|
40
|
-
createSlotExtension(UserMenuItemsSlot, {
|
|
41
|
-
id: "slo.user-menu.items",
|
|
42
|
-
component: SloMenuItems,
|
|
43
|
-
metadata: { group: "Reliability" },
|
|
44
|
-
}),
|
|
45
54
|
createSlotExtension(SystemStateBadgesSlot, {
|
|
46
55
|
id: "slo.system-state-badge",
|
|
47
56
|
component: SystemSloBadge,
|
|
@@ -50,5 +59,12 @@ export default createFrontendPlugin({
|
|
|
50
59
|
id: "slo.system-details-top.panel",
|
|
51
60
|
component: SystemSloPanel,
|
|
52
61
|
}),
|
|
62
|
+
createSlotExtension(SystemSignalsSlot, {
|
|
63
|
+
id: "slo.dashboard.signals",
|
|
64
|
+
load: () =>
|
|
65
|
+
import("./components/SloSignalsFiller").then((m) => ({
|
|
66
|
+
default: m.SloSignalsFiller,
|
|
67
|
+
})),
|
|
68
|
+
}),
|
|
53
69
|
],
|
|
54
70
|
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Link } from "react-router-dom";
|
|
2
|
-
import { Target, Settings } from "lucide-react";
|
|
3
|
-
import type { UserMenuItemsContext } from "@checkstack/frontend-api";
|
|
4
|
-
import { DropdownMenuItem } from "@checkstack/ui";
|
|
5
|
-
import { resolveRoute } from "@checkstack/common";
|
|
6
|
-
import { sloRoutes, sloAccess, pluginMetadata } from "@checkstack/slo-common";
|
|
7
|
-
|
|
8
|
-
export const SloMenuItems = ({
|
|
9
|
-
accessRules: userPerms,
|
|
10
|
-
}: UserMenuItemsContext) => {
|
|
11
|
-
const qualifiedId = `${pluginMetadata.pluginId}.${sloAccess.slo.manage.id}`;
|
|
12
|
-
const canManage = userPerms.includes("*") || userPerms.includes(qualifiedId);
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<>
|
|
16
|
-
<Link to={resolveRoute(sloRoutes.routes.overview)}>
|
|
17
|
-
<DropdownMenuItem icon={<Target className="w-4 h-4" />}>
|
|
18
|
-
SLO Dashboard
|
|
19
|
-
</DropdownMenuItem>
|
|
20
|
-
</Link>
|
|
21
|
-
{canManage && (
|
|
22
|
-
<Link to={resolveRoute(sloRoutes.routes.config)}>
|
|
23
|
-
<DropdownMenuItem icon={<Settings className="w-4 h-4" />}>
|
|
24
|
-
SLO Management
|
|
25
|
-
</DropdownMenuItem>
|
|
26
|
-
</Link>
|
|
27
|
-
)}
|
|
28
|
-
</>
|
|
29
|
-
);
|
|
30
|
-
};
|