@hot-updater/console 1.0.0-rc.2 → 1.0.0-rc.3

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.
Files changed (110) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/InsightsErrorAlert-1cg6LDJG.js +1 -0
  3. package/.output/public/assets/InsightsPageHeader-oNIg_lcd.js +1 -0
  4. package/.output/public/assets/InsightsRolloutCard-Zsv9gBjU.js +42 -0
  5. package/.output/public/assets/{api-keys-BzKocqRy.js → api-keys-ChJjsbP2.js} +1 -1
  6. package/.output/public/assets/{api-keys-api-BHcODB7q.js → api-keys-api-LchP65vQ.js} +1 -1
  7. package/.output/public/assets/{card-Dhr_eFYj.js → card-iD7iiy4T.js} +1 -1
  8. package/.output/public/assets/{chart-no-axes-combined-Dy4WJv2U.js → chart-no-axes-combined-C0G0fQ3J.js} +1 -1
  9. package/.output/public/assets/createServerFn-DHc2erub.js +3 -0
  10. package/.output/public/assets/dialog-DX6o8qCL.js +1 -0
  11. package/.output/public/assets/{dist-C_NydL0e.js → dist-BPrb_vuw.js} +1 -1
  12. package/.output/public/assets/index-C6Nb14xG.js +10 -0
  13. package/.output/public/assets/{input-group-cSOG4wh_.js → input-group-Pa3SAbEI.js} +1 -1
  14. package/.output/public/assets/insights-C1uKy3p2.js +1 -0
  15. package/.output/public/assets/installations-Bj5AzZ3T.js +1 -0
  16. package/.output/public/assets/{installations-CE33wgbY.js → installations-DDTw9DSK.js} +2 -2
  17. package/.output/public/assets/{lazyRouteComponent-Ccp3bwBY.js → lazyRouteComponent-BN0MS05o.js} +1 -1
  18. package/.output/public/assets/{link-CI8idAUi.js → link-BG06whwB.js} +1 -1
  19. package/.output/public/assets/{loader-circle-BoxLrsOu.js → loader-circle-Bbp8LGVC.js} +1 -1
  20. package/.output/public/assets/{refresh-cw-Bqc72UZG.js → refresh-cw-DZgiAOMk.js} +1 -1
  21. package/.output/public/assets/routes-9E2okfpG.js +1 -0
  22. package/.output/public/assets/{routes-DGVXdzpw.js → routes-B3JviaDV.js} +2 -2
  23. package/.output/public/assets/{shield-check-uK3MHWJZ.js → shield-check-DoIiaaXU.js} +1 -1
  24. package/.output/public/assets/{signing-CMf4aqDO.js → signing-BKy9fIdB.js} +1 -1
  25. package/.output/public/assets/styles-C5-su40i.css +2 -0
  26. package/.output/public/assets/{table-2vcV89QB.js → table-bpgpQkPz.js} +1 -1
  27. package/.output/public/assets/useOpenInteractionType-4dPacbwb.js +1 -0
  28. package/.output/public/assets/x-Cr_sPM8E.js +1 -0
  29. package/.output/server/{__23tanstack-start-server-fn-resolver-B7ioJhtE.mjs → __23tanstack-start-server-fn-resolver-EMel9KYs.mjs} +36 -32
  30. package/.output/server/_libs/@base-ui/react+[...].mjs +1051 -1051
  31. package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1554 -0
  32. package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
  33. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +1 -1
  34. package/.output/server/_libs/d3-array.mjs +231 -0
  35. package/.output/server/_libs/d3-color.mjs +330 -0
  36. package/.output/server/_libs/d3-format.mjs +252 -0
  37. package/.output/server/_libs/d3-interpolate.mjs +207 -0
  38. package/.output/server/_libs/d3-path.mjs +77 -0
  39. package/.output/server/_libs/d3-scale+[...].mjs +1907 -0
  40. package/.output/server/_libs/d3-shape.mjs +818 -0
  41. package/.output/server/_libs/decimal.js-light.mjs +884 -0
  42. package/.output/server/_libs/es-toolkit.mjs +1159 -0
  43. package/.output/server/_libs/eventemitter3.mjs +236 -0
  44. package/.output/server/_libs/immer.mjs +532 -0
  45. package/.output/server/_libs/lucide-react.mjs +1 -1
  46. package/.output/server/_libs/next-themes.mjs +1 -1
  47. package/.output/server/_libs/react-redux+[...].mjs +205 -0
  48. package/.output/server/_libs/recharts+[...].mjs +14636 -0
  49. package/.output/server/_libs/sonner.mjs +1 -1
  50. package/.output/server/_libs/tanstack__react-query.mjs +1 -1
  51. package/.output/server/_runtime.mjs +10 -1
  52. package/.output/server/_ssr/InsightsErrorAlert-DzDVdfgW.mjs +169 -0
  53. package/.output/server/_ssr/{InsightsPageHeader-Df4Brj8u.mjs → InsightsPageHeader-CZ2AaQGk.mjs} +8 -120
  54. package/.output/server/_ssr/InsightsRolloutCard-DHB2iM4t.mjs +693 -0
  55. package/.output/server/_ssr/{api-keys-CZeTPQys.mjs → api-keys-BBl84_lN.mjs} +7 -7
  56. package/.output/server/_ssr/{api-keys-api-BUPQVSpk.mjs → api-keys-api-KSH04dLB.mjs} +2 -2
  57. package/.output/server/_ssr/{api-keys-rpc-Cs7tS5_j.mjs → api-keys-rpc-DBmgnW5o.mjs} +3 -3
  58. package/.output/server/_ssr/{api-rpc-tAupfGQm.mjs → api-rpc-DX5B6b-L.mjs} +25 -25
  59. package/.output/server/_ssr/{auth-rpc-DUaeOWKK.mjs → auth-rpc-gaibR719.mjs} +4 -4
  60. package/.output/server/_ssr/{auth.server-DW71WzsD.mjs → auth.server-DF_shCeq.mjs} +1 -1
  61. package/.output/server/_ssr/{bundle-signing-rpc-BhnBw0-d.mjs → bundle-signing-rpc-C01EKpb-.mjs} +2 -2
  62. package/.output/server/_ssr/{bundle-signing.server-C4NW5mWx.mjs → bundle-signing.server-Co_zHdJx.mjs} +1 -1
  63. package/.output/server/_ssr/{card-BRiPmi0C.mjs → card-gGh8F6kQ.mjs} +1 -1
  64. package/.output/server/_ssr/{config.server-afDuAwaG.mjs → config.server-NIXXHk-e.mjs} +5 -5
  65. package/.output/server/_ssr/{createSsrRpc-DjWNJ0uc.mjs → createSsrRpc-4rr4IJh3.mjs} +3 -3
  66. package/.output/server/_ssr/{deleteBundle-BTGwBgzx.mjs → deleteBundle-C71v1GBr.mjs} +1 -1
  67. package/.output/server/_ssr/{dialog-DS-nw-pA.mjs → dialog-DNtKYR5K.mjs} +1 -1
  68. package/.output/server/_ssr/{downloadBundle-CNnYxYO2.mjs → downloadBundle-A9zYC2go.mjs} +1 -1
  69. package/.output/server/_ssr/{getBundleChildren-C0vh4ZvE.mjs → getBundleChildren-CMGSGBWv.mjs} +1 -1
  70. package/.output/server/_ssr/{input-group-BpsnmvZw.mjs → input-group-Oj4kUnE4.mjs} +1 -1
  71. package/.output/server/_ssr/{insights-BdS364Xu.mjs → insights-oK2n5WBp.mjs} +13 -67
  72. package/.output/server/_ssr/insights-recovery-DSFM-YTL.mjs +21 -0
  73. package/.output/server/_ssr/insights-recovery-rpc-CgeCAs2K.mjs +16 -0
  74. package/.output/server/_ssr/{insights-rpc-38DujK0G.mjs → insights-rpc-DBf0ouen.mjs} +2 -2
  75. package/.output/server/_ssr/insightsRecovery-DFkXGFjd.mjs +108 -0
  76. package/.output/server/_ssr/{installations-CtA59MQG.mjs → installations-DBmYuVBi.mjs} +2 -2
  77. package/.output/server/_ssr/{installations-DiVKEF5T.mjs → installations-DQyJN-pZ.mjs} +9 -9
  78. package/.output/server/_ssr/{router-B9wG_9f8.mjs → router-C8J4nYEG.mjs} +13 -13
  79. package/.output/server/_ssr/{routes-CKrrS2q2.mjs → routes-C2RIYhyl.mjs} +2 -2
  80. package/.output/server/_ssr/{routes-D7Yh_jfj.mjs → routes-NlTRKPML.mjs} +21 -86
  81. package/.output/server/_ssr/{runtime.server-DacU1TBV.mjs → runtime.server-DLZpzphL.mjs} +1 -1
  82. package/.output/server/_ssr/{server-D_C2rMzf.mjs → server-hgrXpJQY.mjs} +3 -3
  83. package/.output/server/_ssr/{signing-Dz1WkZOf.mjs → signing-bfOvUMSJ.mjs} +3 -3
  84. package/.output/server/_ssr/ssr.mjs +1 -1
  85. package/.output/server/_ssr/{table-CnZmon_Z.mjs → table-QQ9cnWf2.mjs} +3 -3
  86. package/.output/server/_tanstack-start-manifest_v-BAb_a_eC.mjs +97 -0
  87. package/.output/server/index.mjs +152 -152
  88. package/package.json +5 -5
  89. package/src/components/features/insights/InsightsRolloutCard.tsx +505 -0
  90. package/src/components/features/releases/ReleaseEditorSheet.tsx +13 -0
  91. package/src/components/ui/empty.tsx +101 -0
  92. package/src/lib/insights-recovery-rpc.ts +14 -0
  93. package/src/lib/insights-recovery.ts +55 -0
  94. package/src/lib/server/insightsRecovery.ts +157 -0
  95. package/src/routes/insights.tsx +2 -0
  96. package/.output/public/assets/HashValueDisplay-CB0Eskit.js +0 -1
  97. package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +0 -1
  98. package/.output/public/assets/composite-Bp98A0Ld.js +0 -1
  99. package/.output/public/assets/createServerFn-CA8fs7QD.js +0 -3
  100. package/.output/public/assets/dialog-CUTrcPlB.js +0 -1
  101. package/.output/public/assets/index-DdAz-CXv.js +0 -10
  102. package/.output/public/assets/insights-C0PBSZ-n.js +0 -1
  103. package/.output/public/assets/installations-CStZja8x.js +0 -1
  104. package/.output/public/assets/routes-DTlwOr8I.js +0 -1
  105. package/.output/public/assets/styles-BCvbtKsm.css +0 -2
  106. package/.output/public/assets/useCompositeListItem-CHLITE_4.js +0 -1
  107. package/.output/public/assets/x-DCd0j8c6.js +0 -1
  108. package/.output/server/_ssr/HashValueDisplay-DwpGLfrl.mjs +0 -55
  109. package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +0 -97
  110. /package/.output/public/assets/{preload-helper-CQ36nxok.js → preload-helper-B_l5jfgx.js} +0 -0
@@ -0,0 +1,693 @@
1
+ import { i as __toESM } from "../_runtime.mjs";
2
+ import { c as createServerFn } from "./createServerFn-B2hcXoPM.mjs";
3
+ import { C as SelectRoot, J as require_react, S as SelectTrigger$1, _ as SelectPopup, b as SelectIcon, c as ToggleGroup, d as SelectScrollUpArrow, f as SelectScrollDownArrow, g as SelectList, h as SelectItem$1, l as Toggle, m as SelectItemIndicator, p as SelectItemText, q as require_jsx_runtime, u as SelectGroup$1, v as SelectPositioner, x as SelectValue$1, y as SelectPortal } from "../_libs/@base-ui/react+[...].mjs";
4
+ import { A as ChevronUp, I as ArrowUpRight, N as ChevronDown, P as Check, n as TriangleAlert, u as RotateCcw } from "../_libs/lucide-react.mjs";
5
+ import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
6
+ import { C as cn, S as buttonVariants, _ as Skeleton, t as Button$1, w as createSsrRpc } from "./createSsrRpc-4rr4IJh3.mjs";
7
+ import { m as Link } from "../_libs/@tanstack/react-router+[...].mjs";
8
+ import { n as useQuery } from "../_libs/tanstack__react-query.mjs";
9
+ import { c as CardDescription, d as CardTitle, i as AlertTitle, l as CardFooter, o as Card, r as AlertDescription, s as CardContent, t as Alert, u as CardHeader } from "./card-gGh8F6kQ.mjs";
10
+ import { a as InsightsErrorAlert, s as useInsightsTimeFormat } from "./InsightsErrorAlert-DzDVdfgW.mjs";
11
+ import { t as readRecoveryInput } from "./insights-recovery-DSFM-YTL.mjs";
12
+ import { a as CartesianGrid, i as Line, l as ResponsiveContainer, n as YAxis, o as ReferenceLine, r as XAxis, s as Tooltip, t as LineChart } from "../_libs/recharts+[...].mjs";
13
+ //#region node_modules/.nitro/vite/services/ssr/assets/InsightsRolloutCard-DHB2iM4t.js
14
+ var import_react = /* @__PURE__ */ __toESM(require_react());
15
+ var import_jsx_runtime = require_jsx_runtime();
16
+ var THEMES = {
17
+ light: "",
18
+ dark: ".dark"
19
+ };
20
+ var INITIAL_DIMENSION = {
21
+ width: 320,
22
+ height: 200
23
+ };
24
+ var ChartContext = import_react.createContext(null);
25
+ function useChart() {
26
+ const context = import_react.useContext(ChartContext);
27
+ if (!context) throw new Error("useChart must be used within a <ChartContainer />");
28
+ return context;
29
+ }
30
+ function ChartContainer({ id, className, children, config, initialDimension = INITIAL_DIMENSION, ...props }) {
31
+ const uniqueId = import_react.useId();
32
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`;
33
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartContext.Provider, {
34
+ value: { config },
35
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
36
+ "data-slot": "chart",
37
+ "data-chart": chartId,
38
+ className: cn("flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden", className),
39
+ ...props,
40
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartStyle, {
41
+ id: chartId,
42
+ config
43
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ResponsiveContainer, {
44
+ initialDimension,
45
+ children
46
+ })]
47
+ })
48
+ });
49
+ }
50
+ var ChartStyle = ({ id, config }) => {
51
+ const colorConfig = Object.entries(config).filter(([, config]) => config.theme ?? config.color);
52
+ if (!colorConfig.length) return null;
53
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: { __html: Object.entries(THEMES).map(([theme, prefix]) => `
54
+ ${prefix} [data-chart=${id}] {
55
+ ${colorConfig.map(([key, itemConfig]) => {
56
+ const color = itemConfig.theme?.[theme] ?? itemConfig.color;
57
+ return color ? ` --color-${key}: ${color};` : null;
58
+ }).join("\n")}
59
+ }
60
+ `).join("\n") } });
61
+ };
62
+ var ChartTooltip = Tooltip;
63
+ function ChartTooltipContent({ active, payload, className, indicator = "dot", hideLabel = false, hideIndicator = false, label, labelFormatter, labelClassName, formatter, color, nameKey, labelKey }) {
64
+ const { config } = useChart();
65
+ const tooltipLabel = import_react.useMemo(() => {
66
+ if (hideLabel || !payload?.length) return null;
67
+ const [item] = payload;
68
+ const itemConfig = getPayloadConfigFromPayload(config, item, `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`);
69
+ const value = !labelKey && typeof label === "string" ? config[label]?.label ?? label : itemConfig?.label;
70
+ if (labelFormatter) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
71
+ className: cn("font-medium", labelClassName),
72
+ children: labelFormatter(value, payload)
73
+ });
74
+ if (!value) return null;
75
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
76
+ className: cn("font-medium", labelClassName),
77
+ children: value
78
+ });
79
+ }, [
80
+ label,
81
+ labelFormatter,
82
+ payload,
83
+ hideLabel,
84
+ labelClassName,
85
+ config,
86
+ labelKey
87
+ ]);
88
+ if (!active || !payload?.length) return null;
89
+ const nestLabel = payload.length === 1 && indicator !== "dot";
90
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
91
+ className: cn("grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs/relaxed shadow-xl", className),
92
+ children: [!nestLabel ? tooltipLabel : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
93
+ className: "grid gap-1.5",
94
+ children: payload.filter((item) => item.type !== "none").map((item, index) => {
95
+ const itemConfig = getPayloadConfigFromPayload(config, item, `${nameKey ?? item.name ?? item.dataKey ?? "value"}`);
96
+ const indicatorColor = color ?? item.payload?.fill ?? item.color;
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
98
+ className: cn("flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground", indicator === "dot" && "items-center"),
99
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [itemConfig?.icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
100
+ className: cn("shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", {
101
+ "h-2.5 w-2.5": indicator === "dot",
102
+ "w-1": indicator === "line",
103
+ "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
104
+ "my-0.5": nestLabel && indicator === "dashed"
105
+ }),
106
+ style: {
107
+ "--color-bg": indicatorColor,
108
+ "--color-border": indicatorColor
109
+ }
110
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
111
+ className: cn("flex flex-1 justify-between gap-2 leading-none", nestLabel ? "items-end" : "items-center"),
112
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
113
+ className: "grid gap-1.5",
114
+ children: [nestLabel ? tooltipLabel : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
115
+ className: "text-muted-foreground",
116
+ children: itemConfig?.label ?? item.name
117
+ })]
118
+ }), item.value != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
119
+ className: "font-mono font-medium text-foreground tabular-nums",
120
+ children: typeof item.value === "number" ? item.value.toLocaleString() : String(item.value)
121
+ })]
122
+ })] })
123
+ }, index);
124
+ })
125
+ })]
126
+ });
127
+ }
128
+ function getPayloadConfigFromPayload(config, payload, key) {
129
+ if (typeof payload !== "object" || payload === null) return;
130
+ const payloadPayload = "payload" in payload && typeof payload.payload === "object" && payload.payload !== null ? payload.payload : void 0;
131
+ let configLabelKey = key;
132
+ if (key in payload && typeof payload[key] === "string") configLabelKey = payload[key];
133
+ else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === "string") configLabelKey = payloadPayload[key];
134
+ return configLabelKey in config ? config[configLabelKey] : config[key];
135
+ }
136
+ function Empty({ className, ...props }) {
137
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
138
+ "data-slot": "empty",
139
+ className: cn("flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance", className),
140
+ ...props
141
+ });
142
+ }
143
+ function EmptyHeader({ className, ...props }) {
144
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
145
+ "data-slot": "empty-header",
146
+ className: cn("flex max-w-sm flex-col items-center gap-1", className),
147
+ ...props
148
+ });
149
+ }
150
+ var emptyMediaVariants = cva("mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", {
151
+ variants: { variant: {
152
+ default: "bg-transparent",
153
+ icon: "flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-foreground [&_svg:not([class*='size-'])]:size-4"
154
+ } },
155
+ defaultVariants: { variant: "default" }
156
+ });
157
+ function EmptyMedia({ className, variant = "default", ...props }) {
158
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
159
+ "data-slot": "empty-icon",
160
+ "data-variant": variant,
161
+ className: cn(emptyMediaVariants({
162
+ variant,
163
+ className
164
+ })),
165
+ ...props
166
+ });
167
+ }
168
+ function EmptyTitle({ className, ...props }) {
169
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
170
+ "data-slot": "empty-title",
171
+ className: cn("text-sm font-medium tracking-tight", className),
172
+ ...props
173
+ });
174
+ }
175
+ function EmptyDescription({ className, ...props }) {
176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
177
+ "data-slot": "empty-description",
178
+ className: cn("text-xs/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", className),
179
+ ...props
180
+ });
181
+ }
182
+ var Select$1 = SelectRoot;
183
+ function SelectGroup({ className, ...props }) {
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectGroup$1, {
185
+ "data-slot": "select-group",
186
+ className: cn("scroll-my-1 p-1", className),
187
+ ...props
188
+ });
189
+ }
190
+ function SelectValue({ className, ...props }) {
191
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue$1, {
192
+ "data-slot": "select-value",
193
+ className: cn("flex flex-1 text-left", className),
194
+ ...props
195
+ });
196
+ }
197
+ function SelectTrigger({ className, size = "default", children, ...props }) {
198
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectTrigger$1, {
199
+ "data-slot": "select-trigger",
200
+ "data-size": size,
201
+ className: cn("flex w-fit items-center justify-between gap-1.5 rounded-md border border-input bg-input/20 px-2 py-1.5 text-xs/relaxed whitespace-nowrap transition-colors outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5", className),
202
+ ...props,
203
+ children: [children, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectIcon, { render: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "pointer-events-none size-3.5 text-muted-foreground" }) })]
204
+ });
205
+ }
206
+ function SelectContent({ className, children, side = "bottom", sideOffset = 4, align = "center", alignOffset = 0, alignItemWithTrigger = true, ...props }) {
207
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectPositioner, {
208
+ side,
209
+ sideOffset,
210
+ align,
211
+ alignOffset,
212
+ alignItemWithTrigger,
213
+ className: "isolate z-50",
214
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectPopup, {
215
+ "data-slot": "select-content",
216
+ "data-align-trigger": alignItemWithTrigger,
217
+ className: cn("dark relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
218
+ ...props,
219
+ children: [
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollUpButton, {}),
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectList, { children }),
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollDownButton, {})
223
+ ]
224
+ })
225
+ }) });
226
+ }
227
+ function SelectItem({ className, children, ...props }) {
228
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectItem$1, {
229
+ "data-slot": "select-item",
230
+ className: cn("relative flex min-h-7 w-full cursor-default items-center gap-2 rounded-md px-2 py-1 text-xs/relaxed outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className),
231
+ ...props,
232
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItemText, {
233
+ className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap",
234
+ children
235
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItemIndicator, {
236
+ render: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pointer-events-none absolute right-2 flex items-center justify-center" }),
237
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "pointer-events-none" })
238
+ })]
239
+ });
240
+ }
241
+ function SelectScrollUpButton({ className, ...props }) {
242
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollUpArrow, {
243
+ "data-slot": "select-scroll-up-button",
244
+ className: cn("top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5", className),
245
+ ...props,
246
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUp, {})
247
+ });
248
+ }
249
+ function SelectScrollDownButton({ className, ...props }) {
250
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectScrollDownArrow, {
251
+ "data-slot": "select-scroll-down-button",
252
+ className: cn("bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5", className),
253
+ ...props,
254
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {})
255
+ });
256
+ }
257
+ var toggleVariants = cva("group/toggle inline-flex items-center justify-center gap-1 rounded-md text-xs font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
258
+ variants: {
259
+ variant: {
260
+ default: "bg-transparent",
261
+ outline: "border border-input bg-transparent hover:bg-muted"
262
+ },
263
+ size: {
264
+ default: "h-7 min-w-7 px-2 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
265
+ sm: "h-6 min-w-6 rounded-[min(var(--radius-md),8px)] px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
266
+ lg: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2"
267
+ }
268
+ },
269
+ defaultVariants: {
270
+ variant: "default",
271
+ size: "default"
272
+ }
273
+ });
274
+ var ToggleGroupContext = import_react.createContext({
275
+ size: "default",
276
+ variant: "default",
277
+ spacing: 2,
278
+ orientation: "horizontal"
279
+ });
280
+ function ToggleGroup$1({ className, variant, size, spacing = 2, orientation = "horizontal", children, ...props }) {
281
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, {
282
+ "data-slot": "toggle-group",
283
+ "data-variant": variant,
284
+ "data-size": size,
285
+ "data-spacing": spacing,
286
+ "data-orientation": orientation,
287
+ style: { "--gap": spacing },
288
+ className: cn("group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-md data-[size=sm]:rounded-[min(var(--radius-md),8px)] data-vertical:flex-col data-vertical:items-stretch", className),
289
+ ...props,
290
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroupContext.Provider, {
291
+ value: {
292
+ variant,
293
+ size,
294
+ spacing,
295
+ orientation
296
+ },
297
+ children
298
+ })
299
+ });
300
+ }
301
+ function ToggleGroupItem({ className, children, variant = "default", size = "default", ...props }) {
302
+ const context = import_react.useContext(ToggleGroupContext);
303
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toggle, {
304
+ "data-slot": "toggle-group-item",
305
+ "data-variant": context.variant || variant,
306
+ "data-size": context.size || size,
307
+ "data-spacing": context.spacing,
308
+ className: cn("shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-md group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-md group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-md group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-md group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t", toggleVariants({
309
+ variant: context.variant || variant,
310
+ size: context.size || size
311
+ }), className),
312
+ ...props,
313
+ children
314
+ });
315
+ }
316
+ var getRecoveryReportRpc = createServerFn({ method: "GET" }).validator(readRecoveryInput).handler(createSsrRpc("69cd8e2488b082eb2a22e7058be56ad6566f338c471c62557fa6beed5dc1352a"));
317
+ var percent = (rate) => rate === null ? "No reports" : `${rate.toFixed(1)}%`;
318
+ function RolloutChart({ report, inSheet = false }) {
319
+ const [selectedId, setSelectedId] = (0, import_react.useState)(null);
320
+ const [selectedTime, setSelectedTime] = (0, import_react.useState)(null);
321
+ const [metric, setMetric] = (0, import_react.useState)(() => report.series.some(({ points }) => points.some(({ spike }) => spike)) ? "recovery" : "adoption");
322
+ const formatter = useInsightsTimeFormat();
323
+ const series = report.series.find(({ releaseId }) => releaseId === selectedId) ?? report.series[0];
324
+ if (!series) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(EmptyHeader, { children: [
325
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyMedia, {
326
+ variant: "icon",
327
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCcw, { "aria-hidden": "true" })
328
+ }),
329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyTitle, { children: "No rollout activity yet" }),
330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyDescription, { children: "Try a different time window or check again after this deployment reports adoption or recovery." })
331
+ ] }) });
332
+ const point = series.points.find(({ startMs }) => startMs === selectedTime) ?? [...series.points].reverse().find(({ spike }) => spike) ?? [...series.points].reverse().find((item) => (metric === "adoption" ? item.adoptionShare : item.rate) !== null) ?? [...series.points].reverse().find(({ rate }) => rate !== null);
333
+ const markerMs = series.firstAdoptedAtMs === null ? null : Math.floor(series.firstAdoptedAtMs / report.intervalMs) * report.intervalMs;
334
+ const spikeCount = report.series.filter(({ points }) => points.some(({ spike }) => spike)).length;
335
+ const plotted = metric === "adoption" ? [...report.series.filter((item) => item !== series), series] : [series];
336
+ const chartConfig = Object.fromEntries(plotted.map((item, index) => [`series${index}`, {
337
+ label: `ID ${item.releaseId}`,
338
+ color: item.releaseId === series.releaseId ? "var(--primary)" : "var(--muted-foreground)"
339
+ }]));
340
+ const chartData = series.points.map((item, pointIndex) => ({
341
+ startMs: item.startMs,
342
+ ...Object.fromEntries(plotted.map((deployment, index) => [`series${index}`, metric === "adoption" ? deployment.points[pointIndex].adoptionShare : deployment.points[pointIndex].rate]))
343
+ }));
344
+ const selectedValue = metric === "adoption" ? point.adoptionShare : point.rate;
345
+ const tickTime = (value) => new Intl.DateTimeFormat("en", {
346
+ timeZone: formatter.resolvedOptions().timeZone,
347
+ ...report.intervalMs < 216e5 ? {
348
+ hour: "2-digit",
349
+ minute: "2-digit"
350
+ } : {
351
+ month: "short",
352
+ day: "numeric"
353
+ }
354
+ }).format(value);
355
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
356
+ className: "flex min-w-0 flex-col gap-4",
357
+ children: [
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ToggleGroup$1, {
359
+ "aria-label": "Rollout metric",
360
+ variant: "outline",
361
+ spacing: 0,
362
+ value: [metric],
363
+ onValueChange: (values) => {
364
+ const next = values[0];
365
+ if (next === "adoption" || next === "recovery") {
366
+ setSelectedTime(point.startMs);
367
+ setMetric(next);
368
+ }
369
+ },
370
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroupItem, {
371
+ value: "adoption",
372
+ children: "New adoption"
373
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroupItem, {
374
+ value: "recovery",
375
+ children: "Recovery rate"
376
+ })]
377
+ }),
378
+ !inSheet ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
379
+ className: "flex min-w-0 flex-col gap-2",
380
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
381
+ value: series.releaseId,
382
+ onValueChange: (value) => {
383
+ setSelectedId(value);
384
+ setSelectedTime(null);
385
+ },
386
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
387
+ "aria-label": "Deployment ID",
388
+ className: "w-full min-w-0",
389
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {})
390
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectGroup, { children: report.series.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectItem, {
391
+ value: item.releaseId,
392
+ children: [item.points.some(({ spike }) => spike) ? "Review · " : "ID · ", item.releaseId]
393
+ }, item.releaseId)) }) })]
394
+ }), spikeCount > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
395
+ className: "text-xs text-muted-foreground",
396
+ children: [spikeCount, " deployments have recovery spikes. Select an ID to review its trend."]
397
+ }) : null]
398
+ }) : null,
399
+ metric === "adoption" && !inSheet ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
400
+ className: "text-xs text-muted-foreground",
401
+ children: "The highlighted line is the selected ID. Other IDs appear in gray; select a point to compare adoption and recovery."
402
+ }) : null,
403
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartContainer, {
404
+ config: chartConfig,
405
+ className: "h-56 w-full",
406
+ "aria-label": `${metric === "adoption" ? "New adoption share" : "Recovery rate"} for ID ${series.releaseId}`,
407
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(LineChart, {
408
+ accessibilityLayer: true,
409
+ data: chartData,
410
+ margin: {
411
+ top: 24,
412
+ left: -20,
413
+ right: 16
414
+ },
415
+ onClick: (state) => {
416
+ const index = Number(state.activeIndex);
417
+ if (state.activeIndex != null && series.points[index]) setSelectedTime(series.points[index].startMs);
418
+ },
419
+ children: [
420
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CartesianGrid, { vertical: false }),
421
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XAxis, {
422
+ tick: { fill: "var(--muted-foreground)" },
423
+ dataKey: "startMs",
424
+ tickFormatter: tickTime,
425
+ tickLine: false,
426
+ axisLine: false,
427
+ minTickGap: 48
428
+ }),
429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(YAxis, {
430
+ tick: { fill: "var(--muted-foreground)" },
431
+ domain: [0, 100],
432
+ tickFormatter: (value) => `${value}%`,
433
+ tickLine: false,
434
+ axisLine: false,
435
+ ticks: [
436
+ 0,
437
+ 25,
438
+ 50,
439
+ 75,
440
+ 100
441
+ ]
442
+ }),
443
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltipContent, {
444
+ labelFormatter: (_, payload) => formatter.format(Number(payload[0]?.payload.startMs)),
445
+ formatter: (value, name) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
446
+ className: "max-w-64 break-all font-medium tabular-nums",
447
+ children: [
448
+ name,
449
+ ": ",
450
+ Number(value).toFixed(1),
451
+ "%"
452
+ ]
453
+ })
454
+ }) }),
455
+ markerMs !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReferenceLine, {
456
+ x: markerMs,
457
+ stroke: "var(--muted-foreground)",
458
+ strokeDasharray: "4 4",
459
+ label: {
460
+ value: "First adoption",
461
+ position: "insideTopLeft",
462
+ fill: "var(--muted-foreground)",
463
+ fontSize: 11
464
+ }
465
+ }) : null,
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReferenceLine, {
467
+ x: point.startMs,
468
+ stroke: "var(--border)"
469
+ }),
470
+ plotted.map((deployment, seriesIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, {
471
+ name: `ID ${deployment.releaseId}`,
472
+ dataKey: `series${seriesIndex}`,
473
+ type: "linear",
474
+ stroke: `var(--color-series${seriesIndex})`,
475
+ strokeWidth: 2,
476
+ connectNulls: false,
477
+ isAnimationActive: false,
478
+ dot: ({ cx, cy, index }) => {
479
+ const p = deployment.points[index];
480
+ const value = metric === "adoption" ? p?.adoptionShare : p?.rate;
481
+ if (!p || value === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", {}, index);
482
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
483
+ role: "button",
484
+ tabIndex: 0,
485
+ "aria-label": `Inspect ID ${deployment.releaseId}, ${formatter.format(p.startMs)}: ${percent(value)} ${metric === "adoption" ? "new adoption" : "recovered"}`,
486
+ className: "cursor-pointer focus-visible:stroke-foreground focus-visible:stroke-2",
487
+ onClick: (event) => {
488
+ event.stopPropagation();
489
+ setSelectedId(deployment.releaseId);
490
+ setSelectedTime(p.startMs);
491
+ },
492
+ onKeyDown: (event) => {
493
+ if (event.key === "Enter" || event.key === " ") {
494
+ event.preventDefault();
495
+ event.stopPropagation();
496
+ setSelectedId(deployment.releaseId);
497
+ setSelectedTime(p.startMs);
498
+ }
499
+ },
500
+ cx,
501
+ cy,
502
+ r: metric === "recovery" && p.spike ? 5 : 3,
503
+ fill: metric === "recovery" && p.spike ? "var(--destructive)" : `var(--color-series${seriesIndex})`
504
+ }, index);
505
+ }
506
+ }, deployment.releaseId))
507
+ ]
508
+ })
509
+ }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
511
+ className: "flex flex-wrap items-end justify-between gap-4",
512
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
514
+ className: "text-xs text-muted-foreground",
515
+ children: metric === "adoption" ? "New adoption share in selected interval" : "Recovered in selected interval"
516
+ }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
518
+ className: "mt-1 text-4xl font-semibold tracking-tight tabular-nums",
519
+ children: [selectedValue === null ? "—" : selectedValue.toFixed(1), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
520
+ className: "ml-1 text-lg font-medium text-muted-foreground",
521
+ children: "%"
522
+ })]
523
+ }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
525
+ className: "mt-1 text-xs text-muted-foreground",
526
+ children: metric === "adoption" ? `${point.adopted.toLocaleString()} adoption reports · ${percent(point.rate)} recovered` : `${point.recovered.toLocaleString()} recovered / ${(point.adopted + point.recovered).toLocaleString()} adoption + recovery reports`
527
+ })
528
+ ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
529
+ className: "flex gap-2",
530
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
531
+ variant: "outline",
532
+ "aria-label": "Previous interval",
533
+ disabled: point === series.points[0],
534
+ onClick: () => setSelectedTime(point.startMs - report.intervalMs),
535
+ children: "Previous"
536
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
537
+ variant: "outline",
538
+ "aria-label": "Next interval",
539
+ disabled: point === series.points.at(-1),
540
+ onClick: () => setSelectedTime(point.startMs + report.intervalMs),
541
+ children: "Next"
542
+ })]
543
+ })]
544
+ }),
545
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
546
+ className: "text-xs text-muted-foreground",
547
+ children: [
548
+ formatter.format(Math.max(point.startMs, report.sinceMs)),
549
+ " –",
550
+ " ",
551
+ formatter.format(Math.min(point.startMs + report.intervalMs, report.beforeReceivedAtMs))
552
+ ]
553
+ }),
554
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
555
+ className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border p-3",
556
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
557
+ className: "min-w-0",
558
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
559
+ className: "text-xs text-muted-foreground",
560
+ children: "ID"
561
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
562
+ className: "mt-1 break-all font-mono text-xs",
563
+ translate: "no",
564
+ children: series.releaseId
565
+ })]
566
+ }), !inSheet ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
567
+ to: "/",
568
+ search: { releaseId: series.releaseId },
569
+ className: buttonVariants({ variant: "outline" }),
570
+ children: ["Review deployment", /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUpRight, {
571
+ "aria-hidden": "true",
572
+ "data-icon": "inline-end"
573
+ })]
574
+ }) : null]
575
+ }),
576
+ point.spike ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, {
577
+ variant: "destructive",
578
+ children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { "aria-hidden": "true" }),
580
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "Consider rolling back this deployment" }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AlertDescription, { children: [
582
+ "Recovery rose to ",
583
+ percent(point.rate),
584
+ " after adoption began. Review rollout and Enabled settings before deciding to roll back."
585
+ ] })
586
+ ]
587
+ }) : null,
588
+ markerMs !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
589
+ className: "text-xs text-muted-foreground",
590
+ children: [
591
+ "First adoption observed in this window:",
592
+ " ",
593
+ formatter.format(series.firstAdoptedAtMs),
594
+ "."
595
+ ]
596
+ }) : null
597
+ ]
598
+ });
599
+ }
600
+ function InsightsRolloutCard({ input, inSheet = false }) {
601
+ const [sheetWindow, setSheetWindow] = (0, import_react.useState)(input.window);
602
+ const queryInput = inSheet ? {
603
+ ...input,
604
+ window: sheetWindow
605
+ } : input;
606
+ const query = useQuery({
607
+ queryKey: [
608
+ "insights",
609
+ "recovery",
610
+ queryInput
611
+ ],
612
+ queryFn: () => getRecoveryReportRpc({ data: queryInput }),
613
+ staleTime: 3e4,
614
+ refetchOnWindowFocus: true
615
+ });
616
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
617
+ className: "min-w-0 overflow-hidden shadow-sm",
618
+ children: [
619
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, { children: [
620
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, { children: "Rollout activity" }),
621
+ inSheet ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
622
+ value: sheetWindow,
623
+ onValueChange: (value) => {
624
+ if (value === "24h" || value === "7d" || value === "30d") setSheetWindow(value);
625
+ },
626
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
627
+ "aria-label": "Rollout time window",
628
+ className: "w-full",
629
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {})
630
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectGroup, { children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
632
+ value: "24h",
633
+ children: "Last 24 hours"
634
+ }),
635
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
636
+ value: "7d",
637
+ children: "Last 7 days"
638
+ }),
639
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
640
+ value: "30d",
641
+ children: "Last 30 days"
642
+ })
643
+ ] }) })]
644
+ }) : null,
645
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardDescription, { children: "See new deployments take over and spot recovery spikes. Select a point to inspect its ID and interval." })
646
+ ] }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
648
+ className: "flex flex-col gap-4",
649
+ children: query.isPending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Skeleton, {
650
+ "aria-label": "Loading rollout activity",
651
+ className: "h-80 w-full"
652
+ }) : query.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InsightsErrorAlert, {
653
+ error: query.error,
654
+ fallbackTitle: "Rollout activity unavailable"
655
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [query.data.truncated ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, { children: [
656
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { "aria-hidden": "true" }),
657
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "Partial history" }),
658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: "Only complete intervals from the latest 50,000 reports are shown. Choose a shorter window to see more detail." })
659
+ ] }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RolloutChart, {
660
+ report: query.data,
661
+ inSheet
662
+ }, `${queryInput.platform}:${queryInput.channel}:${queryInput.window}:${queryInput.releaseId ?? ""}`)] })
663
+ }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardFooter, {
665
+ className: "flex flex-col items-start gap-3",
666
+ children: [
667
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
668
+ className: "text-xs text-muted-foreground",
669
+ children: "New adoption shows each ID’s share of adoption reports in this platform and channel. Recovery is recovered ÷ (adopted + recovered). Only reports with an ID are included. Reports are not unique devices; gaps mean no reports."
670
+ }),
671
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", {
672
+ className: "text-xs text-muted-foreground",
673
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", {
674
+ className: "cursor-pointer",
675
+ children: "When a spike needs review"
676
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
677
+ className: "mt-2",
678
+ children: "At least 10 reports, 3 recoveries, a recovery rate of 10% or more, and a rise of 10 percentage points from the previous observed interval (0% at first adoption)."
679
+ })]
680
+ }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
682
+ variant: "outline",
683
+ disabled: query.isFetching,
684
+ onClick: () => void query.refetch(),
685
+ children: "Refresh rollout activity"
686
+ })
687
+ ]
688
+ })
689
+ ]
690
+ });
691
+ }
692
+ //#endregion
693
+ export { SelectItem as a, ToggleGroup$1 as c, SelectGroup as i, ToggleGroupItem as l, Select$1 as n, SelectTrigger as o, SelectContent as r, SelectValue as s, InsightsRolloutCard as t };