@replicated/portal-components 0.0.2 → 0.0.4

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 (216) hide show
  1. package/components/metadata/registry.json +83 -2
  2. package/components/metadata/registry.md +27 -2
  3. package/dist/actions/index.d.mts +566 -3
  4. package/dist/actions/index.d.ts +566 -3
  5. package/dist/actions/index.js +1853 -12
  6. package/dist/actions/index.js.map +1 -1
  7. package/dist/airgap-instances.d.mts +26 -0
  8. package/dist/airgap-instances.d.ts +26 -0
  9. package/dist/airgap-instances.js +354 -0
  10. package/dist/airgap-instances.js.map +1 -0
  11. package/dist/error-page.d.mts +14 -0
  12. package/dist/error-page.d.ts +14 -0
  13. package/dist/error-page.js +153 -0
  14. package/dist/error-page.js.map +1 -0
  15. package/dist/error.d.mts +15 -0
  16. package/dist/error.d.ts +15 -0
  17. package/dist/error.js +144 -0
  18. package/dist/error.js.map +1 -0
  19. package/dist/esm/actions/index.js +1816 -13
  20. package/dist/esm/actions/index.js.map +1 -1
  21. package/dist/esm/airgap-instances.js +352 -0
  22. package/dist/esm/airgap-instances.js.map +1 -0
  23. package/dist/esm/error-page.js +151 -0
  24. package/dist/esm/error-page.js.map +1 -0
  25. package/dist/esm/error.js +142 -0
  26. package/dist/esm/error.js.map +1 -0
  27. package/dist/esm/helm-install-wizard.js +1007 -0
  28. package/dist/esm/helm-install-wizard.js.map +1 -0
  29. package/dist/esm/index.js +2232 -155
  30. package/dist/esm/index.js.map +1 -1
  31. package/dist/esm/install-actions.js +746 -0
  32. package/dist/esm/install-actions.js.map +1 -0
  33. package/dist/esm/install-card.js +115 -0
  34. package/dist/esm/install-card.js.map +1 -0
  35. package/dist/esm/install-targets.js +48 -0
  36. package/dist/esm/install-targets.js.map +1 -0
  37. package/dist/esm/instance-card.js +197 -0
  38. package/dist/esm/instance-card.js.map +1 -0
  39. package/dist/esm/join-team.js +218 -0
  40. package/dist/esm/join-team.js.map +1 -0
  41. package/dist/esm/license-card.js +131 -0
  42. package/dist/esm/license-card.js.map +1 -0
  43. package/dist/esm/license-details.js +667 -0
  44. package/dist/esm/license-details.js.map +1 -0
  45. package/dist/esm/linux-install-wizard.js +1083 -0
  46. package/dist/esm/linux-install-wizard.js.map +1 -0
  47. package/dist/esm/login.js +261 -0
  48. package/dist/esm/login.js.map +1 -0
  49. package/dist/esm/online-instance-list.js +287 -0
  50. package/dist/esm/online-instance-list.js.map +1 -0
  51. package/dist/esm/pending-installations.js +235 -0
  52. package/dist/esm/pending-installations.js.map +1 -0
  53. package/dist/esm/release-history-panel.js +100 -0
  54. package/dist/esm/release-history-panel.js.map +1 -0
  55. package/dist/esm/release-notes-card.js +23 -0
  56. package/dist/esm/release-notes-card.js.map +1 -0
  57. package/dist/esm/security-card.js +700 -0
  58. package/dist/esm/security-card.js.map +1 -0
  59. package/dist/esm/support-bundle-collection-card.js +170 -0
  60. package/dist/esm/support-bundle-collection-card.js.map +1 -0
  61. package/dist/esm/support-bundles-card.js +306 -0
  62. package/dist/esm/support-bundles-card.js.map +1 -0
  63. package/dist/esm/support-card.js +305 -0
  64. package/dist/esm/support-card.js.map +1 -0
  65. package/dist/esm/team-selection.js +117 -0
  66. package/dist/esm/team-selection.js.map +1 -0
  67. package/dist/esm/team-settings-card.js +78 -0
  68. package/dist/esm/team-settings-card.js.map +1 -0
  69. package/dist/esm/team-settings.js +136 -0
  70. package/dist/esm/team-settings.js.map +1 -0
  71. package/dist/esm/top-nav-user-menu.js +173 -0
  72. package/dist/esm/top-nav-user-menu.js.map +1 -0
  73. package/dist/esm/top-nav.js +398 -0
  74. package/dist/esm/top-nav.js.map +1 -0
  75. package/dist/esm/update-layout.js +405 -0
  76. package/dist/esm/update-layout.js.map +1 -0
  77. package/dist/esm/updates-card.js +85 -0
  78. package/dist/esm/updates-card.js.map +1 -0
  79. package/dist/esm/upload-support-bundle-modal.js +143 -0
  80. package/dist/esm/upload-support-bundle-modal.js.map +1 -0
  81. package/dist/esm/user-settings-card.js +21 -0
  82. package/dist/esm/user-settings-card.js.map +1 -0
  83. package/dist/esm/user-settings.js +368 -0
  84. package/dist/esm/user-settings.js.map +1 -0
  85. package/dist/esm/utils/index.js +170 -0
  86. package/dist/esm/utils/index.js.map +1 -0
  87. package/dist/helm-install-wizard.d.mts +38 -0
  88. package/dist/helm-install-wizard.d.ts +38 -0
  89. package/dist/helm-install-wizard.js +1011 -0
  90. package/dist/helm-install-wizard.js.map +1 -0
  91. package/dist/index.d.mts +11 -27
  92. package/dist/index.d.ts +11 -27
  93. package/dist/index.js +2258 -154
  94. package/dist/index.js.map +1 -1
  95. package/dist/install-B19AaKF_.d.mts +233 -0
  96. package/dist/install-Bi1qJ8Bu.d.ts +233 -0
  97. package/dist/install-actions.d.mts +141 -0
  98. package/dist/install-actions.d.ts +141 -0
  99. package/dist/install-actions.js +765 -0
  100. package/dist/install-actions.js.map +1 -0
  101. package/dist/install-card.d.mts +15 -0
  102. package/dist/install-card.d.ts +15 -0
  103. package/dist/install-card.js +117 -0
  104. package/dist/install-card.js.map +1 -0
  105. package/dist/install-targets.d.mts +19 -0
  106. package/dist/install-targets.d.ts +19 -0
  107. package/dist/install-targets.js +50 -0
  108. package/dist/install-targets.js.map +1 -0
  109. package/dist/instance-card.d.mts +22 -0
  110. package/dist/instance-card.d.ts +22 -0
  111. package/dist/instance-card.js +199 -0
  112. package/dist/instance-card.js.map +1 -0
  113. package/dist/join-team.d.mts +30 -0
  114. package/dist/join-team.d.ts +30 -0
  115. package/dist/join-team.js +220 -0
  116. package/dist/join-team.js.map +1 -0
  117. package/dist/license-card.d.mts +15 -0
  118. package/dist/license-card.d.ts +15 -0
  119. package/dist/license-card.js +133 -0
  120. package/dist/license-card.js.map +1 -0
  121. package/dist/license-details.d.mts +10 -0
  122. package/dist/license-details.d.ts +10 -0
  123. package/dist/license-details.js +669 -0
  124. package/dist/license-details.js.map +1 -0
  125. package/dist/linux-install-wizard.d.mts +66 -0
  126. package/dist/linux-install-wizard.d.ts +66 -0
  127. package/dist/linux-install-wizard.js +1093 -0
  128. package/dist/linux-install-wizard.js.map +1 -0
  129. package/dist/login.d.mts +37 -0
  130. package/dist/login.d.ts +37 -0
  131. package/dist/login.js +263 -0
  132. package/dist/login.js.map +1 -0
  133. package/dist/online-instance-list.d.mts +22 -0
  134. package/dist/online-instance-list.d.ts +22 -0
  135. package/dist/online-instance-list.js +289 -0
  136. package/dist/online-instance-list.js.map +1 -0
  137. package/dist/pending-installations.d.mts +15 -0
  138. package/dist/pending-installations.d.ts +15 -0
  139. package/dist/pending-installations.js +237 -0
  140. package/dist/pending-installations.js.map +1 -0
  141. package/dist/release-history-panel.d.mts +22 -0
  142. package/dist/release-history-panel.d.ts +22 -0
  143. package/dist/release-history-panel.js +102 -0
  144. package/dist/release-history-panel.js.map +1 -0
  145. package/dist/release-notes-card.d.mts +13 -0
  146. package/dist/release-notes-card.d.ts +13 -0
  147. package/dist/release-notes-card.js +25 -0
  148. package/dist/release-notes-card.js.map +1 -0
  149. package/dist/security-card.d.mts +73 -0
  150. package/dist/security-card.d.ts +73 -0
  151. package/dist/security-card.js +702 -0
  152. package/dist/security-card.js.map +1 -0
  153. package/dist/styles.css +1877 -194
  154. package/dist/support-bundle-collection-card.d.mts +20 -0
  155. package/dist/support-bundle-collection-card.d.ts +20 -0
  156. package/dist/support-bundle-collection-card.js +172 -0
  157. package/dist/support-bundle-collection-card.js.map +1 -0
  158. package/dist/support-bundles-card.d.mts +19 -0
  159. package/dist/support-bundles-card.d.ts +19 -0
  160. package/dist/support-bundles-card.js +308 -0
  161. package/dist/support-bundles-card.js.map +1 -0
  162. package/dist/support-card.d.mts +8 -0
  163. package/dist/support-card.d.ts +8 -0
  164. package/dist/support-card.js +307 -0
  165. package/dist/support-card.js.map +1 -0
  166. package/dist/team-selection.d.mts +23 -0
  167. package/dist/team-selection.d.ts +23 -0
  168. package/dist/team-selection.js +119 -0
  169. package/dist/team-selection.js.map +1 -0
  170. package/dist/team-settings-card-Dq1d9b5c.d.mts +14 -0
  171. package/dist/team-settings-card-Dq1d9b5c.d.ts +14 -0
  172. package/dist/team-settings-card.d.mts +2 -0
  173. package/dist/team-settings-card.d.ts +2 -0
  174. package/dist/team-settings-card.js +80 -0
  175. package/dist/team-settings-card.js.map +1 -0
  176. package/dist/team-settings.d.mts +25 -0
  177. package/dist/team-settings.d.ts +25 -0
  178. package/dist/team-settings.js +138 -0
  179. package/dist/team-settings.js.map +1 -0
  180. package/dist/top-nav-0mb1K_H0.d.mts +32 -0
  181. package/dist/top-nav-0mb1K_H0.d.ts +32 -0
  182. package/dist/top-nav-user-menu.d.mts +18 -0
  183. package/dist/top-nav-user-menu.d.ts +18 -0
  184. package/dist/top-nav-user-menu.js +175 -0
  185. package/dist/top-nav-user-menu.js.map +1 -0
  186. package/dist/top-nav.d.mts +3 -0
  187. package/dist/top-nav.d.ts +3 -0
  188. package/dist/top-nav.js +400 -0
  189. package/dist/top-nav.js.map +1 -0
  190. package/dist/update-layout.d.mts +12 -0
  191. package/dist/update-layout.d.ts +12 -0
  192. package/dist/update-layout.js +407 -0
  193. package/dist/update-layout.js.map +1 -0
  194. package/dist/updates-card-BbubBrVR.d.mts +18 -0
  195. package/dist/updates-card-BbubBrVR.d.ts +18 -0
  196. package/dist/updates-card.d.mts +2 -0
  197. package/dist/updates-card.d.ts +2 -0
  198. package/dist/updates-card.js +87 -0
  199. package/dist/updates-card.js.map +1 -0
  200. package/dist/upload-support-bundle-modal.d.mts +19 -0
  201. package/dist/upload-support-bundle-modal.d.ts +19 -0
  202. package/dist/upload-support-bundle-modal.js +145 -0
  203. package/dist/upload-support-bundle-modal.js.map +1 -0
  204. package/dist/user-settings-card.d.mts +8 -0
  205. package/dist/user-settings-card.d.ts +8 -0
  206. package/dist/user-settings-card.js +23 -0
  207. package/dist/user-settings-card.js.map +1 -0
  208. package/dist/user-settings.d.mts +47 -0
  209. package/dist/user-settings.d.ts +47 -0
  210. package/dist/user-settings.js +370 -0
  211. package/dist/user-settings.js.map +1 -0
  212. package/dist/utils/index.d.mts +70 -0
  213. package/dist/utils/index.d.ts +70 -0
  214. package/dist/utils/index.js +177 -0
  215. package/dist/utils/index.js.map +1 -0
  216. package/package.json +163 -3
@@ -0,0 +1,261 @@
1
+ "use client";
2
+ import { forwardRef, useState, useMemo } from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ /**
6
+ * Enterprise Portal Components
7
+ * This file is generated by tsup. Do not edit manually.
8
+ */
9
+
10
+ var variantStyles = {
11
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-primary",
12
+ secondary: "bg-secondary/20 text-secondary-foreground hover:bg-secondary/30 focus-visible:ring-secondary",
13
+ ghost: "bg-transparent text-primary hover:bg-primary/10 focus-visible:ring-primary/60",
14
+ destructive: "bg-danger text-white hover:bg-danger/90 focus-visible:ring-danger"
15
+ };
16
+ var sizeStyles = {
17
+ sm: "h-8 px-3 text-sm",
18
+ md: "h-10 px-4 text-sm",
19
+ lg: "h-12 px-6 text-base"
20
+ };
21
+ var inlineFlexBase = "inline-flex items-center justify-center gap-2 rounded-md font-medium tracking-tight transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-60";
22
+ var Spinner = () => /* @__PURE__ */ jsx("span", { className: "inline-flex h-3.5 w-3.5 animate-spin items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "h-3 w-3 rounded-full border-2 border-transparent border-t-current" }) });
23
+ var composeClassName = (...values) => values.filter(Boolean).join(" ");
24
+ var Button = forwardRef(
25
+ ({
26
+ variant = "primary",
27
+ size = "md",
28
+ type = "button",
29
+ isLoading = false,
30
+ leadingIcon,
31
+ trailingIcon,
32
+ disabled,
33
+ className,
34
+ children,
35
+ ...props
36
+ }, ref) => {
37
+ const computedLeading = isLoading ? /* @__PURE__ */ jsx(Spinner, {}) : leadingIcon;
38
+ const computedDisabled = disabled ?? isLoading;
39
+ return /* @__PURE__ */ jsxs(
40
+ "button",
41
+ {
42
+ ref,
43
+ type,
44
+ className: composeClassName(
45
+ inlineFlexBase,
46
+ variantStyles[variant],
47
+ sizeStyles[size],
48
+ className
49
+ ),
50
+ "aria-busy": isLoading || void 0,
51
+ disabled: computedDisabled,
52
+ ...props,
53
+ children: [
54
+ computedLeading ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex", children: computedLeading }) : null,
55
+ /* @__PURE__ */ jsx("span", { className: "flex-1 whitespace-nowrap", children }),
56
+ trailingIcon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex", children: trailingIcon }) : null
57
+ ]
58
+ }
59
+ );
60
+ }
61
+ );
62
+ Button.displayName = "Button";
63
+ var Login = forwardRef(
64
+ ({
65
+ logo,
66
+ title = "Enterprise Factory Installation Portal",
67
+ description = "Sign in to manage your enterprise installation",
68
+ label = "Work email address",
69
+ placeholder = "you@company.com",
70
+ ctaLabel = "Continue with email \u2192",
71
+ initialEmail = "",
72
+ isSubmitting = false,
73
+ onContinue,
74
+ onVerifyCode,
75
+ redirectPath = "/",
76
+ className,
77
+ ...props
78
+ }, ref) => {
79
+ const [mode, setMode] = useState("email");
80
+ const [email, setEmail] = useState(initialEmail);
81
+ const [submittedEmail, setSubmittedEmail] = useState(initialEmail);
82
+ const [verificationCode, setVerificationCode] = useState("");
83
+ const [verifying, setVerifying] = useState(false);
84
+ const [pending, setPending] = useState(false);
85
+ const [verificationError, setVerificationError] = useState(
86
+ null
87
+ );
88
+ const handleSubmit = async (event) => {
89
+ event.preventDefault();
90
+ if (!onContinue || mode !== "email") {
91
+ return;
92
+ }
93
+ try {
94
+ setPending(true);
95
+ const result = await onContinue(email);
96
+ if (result && typeof result === "object" && "showVerification" in result && result.showVerification === false) {
97
+ return;
98
+ }
99
+ setSubmittedEmail(email);
100
+ setVerificationCode("");
101
+ setVerificationError(null);
102
+ setMode("verify");
103
+ } finally {
104
+ setPending(false);
105
+ }
106
+ };
107
+ const disabled = mode === "email" && (isSubmitting || pending);
108
+ const verificationMessage = useMemo(() => {
109
+ if (!submittedEmail) {
110
+ return null;
111
+ }
112
+ return `If there is an account for ${submittedEmail}, an email will be sent with a login code.`;
113
+ }, [submittedEmail]);
114
+ const handleVerify = async () => {
115
+ if (!onVerifyCode || !verificationCode) {
116
+ return;
117
+ }
118
+ try {
119
+ setVerificationError(null);
120
+ setVerifying(true);
121
+ const result = await onVerifyCode(verificationCode, redirectPath);
122
+ if (result && typeof result === "object" && "success" in result && result.success === false) {
123
+ const message = result.message ?? "Unable to verify code. Try again.";
124
+ setVerificationError(message);
125
+ return;
126
+ }
127
+ setVerificationCode("");
128
+ } catch (error) {
129
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
130
+ setVerificationError(error.message);
131
+ } else {
132
+ setVerificationError("Unable to verify code. Try again.");
133
+ }
134
+ } finally {
135
+ setVerifying(false);
136
+ }
137
+ };
138
+ return /* @__PURE__ */ jsxs(
139
+ "form",
140
+ {
141
+ ref,
142
+ className: [
143
+ "w-full max-w-xl rounded-3xl border-2 border-gray-900 bg-white p-12 shadow-xl",
144
+ "text-gray-900 transition-shadow",
145
+ className
146
+ ].filter(Boolean).join(" "),
147
+ onSubmit: handleSubmit,
148
+ ...props,
149
+ children: [
150
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-6 text-center", children: [
151
+ logo ?? /* @__PURE__ */ jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-500 to-violet-500 text-lg font-semibold leading-tight text-white", children: "EP" }),
152
+ /* @__PURE__ */ jsxs("div", { children: [
153
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold tracking-tight text-gray-900", children: title }),
154
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-base text-gray-600", children: description })
155
+ ] })
156
+ ] }),
157
+ mode === "email" ? /* @__PURE__ */ jsxs("div", { className: "mt-10 space-y-4", children: [
158
+ /* @__PURE__ */ jsx(
159
+ "label",
160
+ {
161
+ htmlFor: "login-email",
162
+ className: "block text-sm font-medium text-gray-700",
163
+ children: label
164
+ }
165
+ ),
166
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
167
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 flex items-center pl-4", children: /* @__PURE__ */ jsx(
168
+ "svg",
169
+ {
170
+ className: "h-5 w-5 text-gray-400",
171
+ fill: "none",
172
+ viewBox: "0 0 24 24",
173
+ stroke: "currentColor",
174
+ children: /* @__PURE__ */ jsx(
175
+ "path",
176
+ {
177
+ strokeLinecap: "round",
178
+ strokeLinejoin: "round",
179
+ strokeWidth: 2,
180
+ d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
181
+ }
182
+ )
183
+ }
184
+ ) }),
185
+ /* @__PURE__ */ jsx(
186
+ "input",
187
+ {
188
+ id: "login-email",
189
+ type: "email",
190
+ inputMode: "email",
191
+ autoComplete: "email",
192
+ placeholder,
193
+ value: email,
194
+ onChange: (event) => setEmail(event.target.value),
195
+ className: "portal-input w-full py-4 pr-4 text-base",
196
+ style: { paddingLeft: "3rem" },
197
+ disabled,
198
+ required: true
199
+ }
200
+ )
201
+ ] }),
202
+ /* @__PURE__ */ jsx(
203
+ Button,
204
+ {
205
+ type: "submit",
206
+ size: "lg",
207
+ className: "w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700",
208
+ disabled,
209
+ isLoading: disabled,
210
+ children: ctaLabel
211
+ }
212
+ )
213
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "mt-10 space-y-4", children: [
214
+ /* @__PURE__ */ jsxs("div", { children: [
215
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-gray-900", children: "Verification Code" }),
216
+ verificationMessage ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-gray-600", children: verificationMessage }) : null,
217
+ verificationError ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium text-red-600", children: verificationError }) : null
218
+ ] }),
219
+ /* @__PURE__ */ jsx(
220
+ "label",
221
+ {
222
+ htmlFor: "login-code",
223
+ className: "block text-sm font-medium text-gray-700",
224
+ children: "One-time code"
225
+ }
226
+ ),
227
+ /* @__PURE__ */ jsx(
228
+ "input",
229
+ {
230
+ id: "login-code",
231
+ inputMode: "numeric",
232
+ maxLength: 12,
233
+ placeholder: "Enter 12 digit code",
234
+ className: "portal-input w-full px-5 py-4 text-base",
235
+ value: verificationCode,
236
+ onChange: (event) => setVerificationCode(event.target.value)
237
+ }
238
+ ),
239
+ /* @__PURE__ */ jsx(
240
+ Button,
241
+ {
242
+ type: "button",
243
+ size: "lg",
244
+ className: "w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700",
245
+ disabled: verificationCode.length !== 12 || verifying,
246
+ isLoading: verifying,
247
+ onClick: handleVerify,
248
+ children: "Verify code"
249
+ }
250
+ )
251
+ ] })
252
+ ]
253
+ }
254
+ );
255
+ }
256
+ );
257
+ Login.displayName = "Login";
258
+
259
+ export { Login };
260
+ //# sourceMappingURL=login.js.map
261
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/button.tsx","../../src/components/login.tsx"],"names":["forwardRef","jsxs","jsx"],"mappings":"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","file":"login.js","sourcesContent":["import {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ReactNode\n} from \"react\";\n\nconst buttonVariants = [\"primary\", \"secondary\", \"ghost\", \"destructive\"] as const;\nconst buttonSizes = [\"sm\", \"md\", \"lg\"] as const;\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary:\n \"bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-primary\",\n secondary:\n \"bg-secondary/20 text-secondary-foreground hover:bg-secondary/30 focus-visible:ring-secondary\",\n ghost:\n \"bg-transparent text-primary hover:bg-primary/10 focus-visible:ring-primary/60\",\n destructive:\n \"bg-danger text-white hover:bg-danger/90 focus-visible:ring-danger\"\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: \"h-8 px-3 text-sm\",\n md: \"h-10 px-4 text-sm\",\n lg: \"h-12 px-6 text-base\"\n};\n\nconst inlineFlexBase =\n \"inline-flex items-center justify-center gap-2 rounded-md font-medium tracking-tight transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-60\";\n\nconst Spinner = () => (\n <span className=\"inline-flex h-3.5 w-3.5 animate-spin items-center justify-center\">\n <span className=\"h-3 w-3 rounded-full border-2 border-transparent border-t-current\" />\n </span>\n);\n\nexport type ButtonVariant = (typeof buttonVariants)[number];\nexport type ButtonSize = (typeof buttonSizes)[number];\n\nexport interface ButtonProps extends ComponentPropsWithoutRef<\"button\"> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n isLoading?: boolean;\n leadingIcon?: ReactNode;\n trailingIcon?: ReactNode;\n}\n\nconst composeClassName = (\n ...values: Array<string | undefined | false>\n): string => values.filter(Boolean).join(\" \");\n\n/**\n * Button is the primary interactive primitive for triggering portal actions.\n * It is theme aware via CSS variables generated from portal tokens.\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"primary\",\n size = \"md\",\n type = \"button\",\n isLoading = false,\n leadingIcon,\n trailingIcon,\n disabled,\n className,\n children,\n ...props\n },\n ref\n ) => {\n const computedLeading = isLoading ? <Spinner /> : leadingIcon;\n const computedDisabled = disabled ?? isLoading;\n\n return (\n <button\n ref={ref}\n type={type}\n className={composeClassName(\n inlineFlexBase,\n variantStyles[variant],\n sizeStyles[size],\n className\n )}\n aria-busy={isLoading || undefined}\n disabled={computedDisabled}\n {...props}\n >\n {computedLeading ? (\n <span aria-hidden=\"true\" className=\"inline-flex\">\n {computedLeading}\n </span>\n ) : null}\n <span className=\"flex-1 whitespace-nowrap\">{children}</span>\n {trailingIcon ? (\n <span aria-hidden=\"true\" className=\"inline-flex\">\n {trailingIcon}\n </span>\n ) : null}\n </button>\n );\n }\n);\n\nButton.displayName = \"Button\";\n","'use client';\n\nimport {\n forwardRef,\n useMemo,\n useState,\n type ComponentPropsWithoutRef,\n type FormEvent,\n type ReactNode\n} from \"react\";\n\nimport { Button } from \"./button\";\n\nexport interface LoginProps\n extends Omit<ComponentPropsWithoutRef<\"form\">, \"onSubmit\" | \"children\"> {\n logo?: ReactNode;\n title?: string;\n description?: string;\n label?: string;\n placeholder?: string;\n ctaLabel?: string;\n initialEmail?: string;\n isSubmitting?: boolean;\n /** \n * Called when user submits email. Return { showVerification: false } to prevent\n * showing the verification code form (e.g., for SAML redirect).\n */\n onContinue?: (email: string) => Promise<void | { showVerification: boolean }> | void | { showVerification: boolean };\n onVerifyCode?: (\n code: string,\n redirectPath: string\n ) => Promise<\n | void\n | { success: true }\n | { success: false; message?: string }\n >;\n redirectPath?: string;\n}\n\n/**\n * Login renders a compact form card tailored for portal authentication flows.\n * The component keeps styling self-contained so it can be dropped into the\n * local Next.js template without additional wrappers.\n */\nexport const Login = forwardRef<HTMLFormElement, LoginProps>(\n (\n {\n logo,\n title = \"Enterprise Factory Installation Portal\",\n description = \"Sign in to manage your enterprise installation\",\n label = \"Work email address\",\n placeholder = \"you@company.com\",\n ctaLabel = \"Continue with email →\",\n initialEmail = \"\",\n isSubmitting = false,\n onContinue,\n onVerifyCode,\n redirectPath = \"/\",\n className,\n ...props\n },\n ref\n ) => {\n const [mode, setMode] = useState<\"email\" | \"verify\">(\"email\");\n const [email, setEmail] = useState(initialEmail);\n const [submittedEmail, setSubmittedEmail] = useState(initialEmail);\n const [verificationCode, setVerificationCode] = useState(\"\");\n const [verifying, setVerifying] = useState(false);\n const [pending, setPending] = useState(false);\n const [verificationError, setVerificationError] = useState<string | null>(\n null\n );\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!onContinue || mode !== \"email\") {\n return;\n }\n\n try {\n setPending(true);\n const result = await onContinue(email);\n \n // Check if we should show verification form\n // If result is { showVerification: false }, don't show it (e.g., SAML redirect)\n if (result && typeof result === \"object\" && \"showVerification\" in result && result.showVerification === false) {\n // Don't transition to verify mode - caller is handling redirect\n return;\n }\n \n // Show verification code form\n setSubmittedEmail(email);\n setVerificationCode(\"\");\n setVerificationError(null);\n setMode(\"verify\");\n } finally {\n setPending(false);\n }\n };\n\n const disabled = mode === \"email\" && (isSubmitting || pending);\n const verificationMessage = useMemo(() => {\n if (!submittedEmail) {\n return null;\n }\n return `If there is an account for ${submittedEmail}, an email will be sent with a login code.`;\n }, [submittedEmail]);\n\n const handleVerify = async () => {\n if (!onVerifyCode || !verificationCode) {\n return;\n }\n try {\n setVerificationError(null);\n setVerifying(true);\n const result = await onVerifyCode(verificationCode, redirectPath);\n if (\n result &&\n typeof result === \"object\" &&\n \"success\" in result &&\n (result as { success?: unknown }).success === false\n ) {\n const message =\n (result as { message?: string }).message ??\n \"Unable to verify code. Try again.\";\n setVerificationError(message);\n return;\n }\n setVerificationCode(\"\");\n } catch (error) {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof (error as { message?: unknown }).message === \"string\"\n ) {\n setVerificationError((error as { message: string }).message);\n } else {\n setVerificationError(\"Unable to verify code. Try again.\");\n }\n } finally {\n setVerifying(false);\n }\n };\n\n return (\n <form\n ref={ref}\n className={[\n \"w-full max-w-xl rounded-3xl border-2 border-gray-900 bg-white p-12 shadow-xl\",\n \"text-gray-900 transition-shadow\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n onSubmit={handleSubmit}\n {...props}\n >\n <div className=\"flex flex-col items-center gap-6 text-center\">\n {logo ?? (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-500 to-violet-500 text-lg font-semibold leading-tight text-white\">\n EP\n </div>\n )}\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight text-gray-900\">\n {title}\n </h1>\n <p className=\"mt-3 text-base text-gray-600\">{description}</p>\n </div>\n </div>\n {mode === \"email\" ? (\n <div className=\"mt-10 space-y-4\">\n <label\n htmlFor=\"login-email\"\n className=\"block text-sm font-medium text-gray-700\"\n >\n {label}\n </label>\n <div className=\"relative\">\n <div className=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-4\">\n <svg\n className=\"h-5 w-5 text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\"\n />\n </svg>\n </div>\n <input\n id=\"login-email\"\n type=\"email\"\n inputMode=\"email\"\n autoComplete=\"email\"\n placeholder={placeholder}\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n className=\"portal-input w-full py-4 pr-4 text-base\"\n style={{ paddingLeft: '3rem' }}\n disabled={disabled}\n required\n />\n </div>\n <Button\n type=\"submit\"\n size=\"lg\"\n className=\"w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700\"\n disabled={disabled}\n isLoading={disabled}\n >\n {ctaLabel}\n </Button>\n </div>\n ) : (\n <div className=\"mt-10 space-y-4\">\n <div>\n <p className=\"text-sm font-semibold text-gray-900\">\n Verification Code\n </p>\n {verificationMessage ? (\n <p className=\"mt-2 text-sm text-gray-600\">{verificationMessage}</p>\n ) : null}\n {verificationError ? (\n <p className=\"mt-2 text-sm font-medium text-red-600\">\n {verificationError}\n </p>\n ) : null}\n </div>\n <label\n htmlFor=\"login-code\"\n className=\"block text-sm font-medium text-gray-700\"\n >\n One-time code\n </label>\n <input\n id=\"login-code\"\n inputMode=\"numeric\"\n maxLength={12}\n placeholder=\"Enter 12 digit code\"\n className=\"portal-input w-full px-5 py-4 text-base\"\n value={verificationCode}\n onChange={(event) => setVerificationCode(event.target.value)}\n />\n <Button\n type=\"button\"\n size=\"lg\"\n className=\"w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700\"\n disabled={verificationCode.length !== 12 || verifying}\n isLoading={verifying}\n onClick={handleVerify}\n >\n Verify code\n </Button>\n </div>\n )}\n </form>\n );\n }\n);\n\nLogin.displayName = \"Login\";\n"]}
@@ -0,0 +1,287 @@
1
+ "use client";
2
+ import { useState } from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ /**
6
+ * Enterprise Portal Components
7
+ * This file is generated by tsup. Do not edit manually.
8
+ */
9
+
10
+
11
+ // src/actions/instances.ts
12
+ var ACTIVE_INSTANCE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
13
+ function isInstanceActive(instance) {
14
+ if (!instance.lastCheckin) {
15
+ return false;
16
+ }
17
+ const lastCheckinTime = new Date(instance.lastCheckin).getTime();
18
+ const threshold = Date.now() - ACTIVE_INSTANCE_THRESHOLD_MS;
19
+ return lastCheckinTime > threshold;
20
+ }
21
+ function filterActiveInactiveInstances(instances) {
22
+ const activeInstances = instances.filter(isInstanceActive);
23
+ const inactiveInstances = instances.filter((instance) => !isInstanceActive(instance));
24
+ return { activeInstances, inactiveInstances };
25
+ }
26
+ function getInstallType(instance, installOptions) {
27
+ const instanceHasNoInstallTypes = !instance.kotsInstallId && !instance.kurlInstallId && !instance.embeddedClusterId;
28
+ const isManuallyCreatedAirgapInstance = instance.isAirgap && instanceHasNoInstallTypes;
29
+ if (instance.embeddedClusterId) {
30
+ return "embedded cluster";
31
+ }
32
+ if (instanceHasNoInstallTypes && instance.k8sDistribution) {
33
+ return "helm";
34
+ }
35
+ if (isManuallyCreatedAirgapInstance && !instance.k8sDistribution) {
36
+ if (installOptions) {
37
+ const matchingInstallOption = installOptions.find(
38
+ (option) => option.instance_id === instance.id
39
+ );
40
+ if (matchingInstallOption) {
41
+ if (matchingInstallOption.install_type === "helm") {
42
+ return "helm";
43
+ }
44
+ if (matchingInstallOption.install_type === "linux") {
45
+ return "embedded cluster";
46
+ }
47
+ }
48
+ }
49
+ return "embedded cluster";
50
+ }
51
+ return null;
52
+ }
53
+ function calculateUpdatesForInstance(instance, channelReleases) {
54
+ if (!channelReleases || !Array.isArray(channelReleases)) {
55
+ return 0;
56
+ }
57
+ const instanceChannelSequence = instance.channelSequence ?? 0;
58
+ const matchingReleases = channelReleases.filter(
59
+ (release) => release.channelId === instance.channelId
60
+ );
61
+ return matchingReleases.filter(
62
+ (release) => release.channelSequence > instanceChannelSequence
63
+ ).length;
64
+ }
65
+ function getInstanceName(instance) {
66
+ const nameTag = instance.tags?.find((tag) => tag.key === "name");
67
+ return nameTag?.value || instance.id.slice(0, 7);
68
+ }
69
+ function formatDateTime(dateString) {
70
+ if (!dateString) return "N/A";
71
+ const date = new Date(dateString);
72
+ return date.toLocaleDateString("en-US", {
73
+ month: "numeric",
74
+ day: "numeric",
75
+ year: "numeric",
76
+ hour: "numeric",
77
+ minute: "2-digit",
78
+ hour12: true
79
+ });
80
+ }
81
+ function UpdateBadge({ count }) {
82
+ if (count <= 0) return null;
83
+ return /* @__PURE__ */ jsx("span", { className: "ml-1.5 inline-flex h-5 w-5 items-center justify-center rounded-full bg-rose-500 text-xs font-medium text-white", children: count });
84
+ }
85
+ function StatusBadge({ status }) {
86
+ const colorMap = {
87
+ ready: "bg-green-50 text-green-600",
88
+ updating: "bg-green-50 text-green-600",
89
+ unknown: "bg-blue-50 text-blue-500",
90
+ missing: "bg-pink-50 text-pink-600",
91
+ unavailable: "bg-pink-50 text-pink-600",
92
+ degraded: "bg-yellow-50 text-yellow-600"
93
+ };
94
+ const colorClass = colorMap[status] || "bg-gray-50 text-gray-600";
95
+ return /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${colorClass}`, children: [
96
+ status,
97
+ /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
98
+ ] });
99
+ }
100
+ function InstanceCard({
101
+ instance,
102
+ isActive,
103
+ channelReleases = [],
104
+ installOptions = [],
105
+ onUpdateClick,
106
+ primaryColor = "#6366f1"
107
+ }) {
108
+ const [showInstanceId, setShowInstanceId] = useState(false);
109
+ const [showTooltip, setShowTooltip] = useState(false);
110
+ const instanceName = getInstanceName(instance);
111
+ const installType = getInstallType(instance, installOptions);
112
+ const availableUpdates = calculateUpdatesForInstance(instance, channelReleases);
113
+ const displayText = showInstanceId ? instance.id.slice(0, 7) : instanceName || instance.id.slice(0, 7);
114
+ const getTooltipText = () => {
115
+ if (instanceName) {
116
+ return showInstanceId ? "Click to show instance name" : "Click to show instance ID";
117
+ }
118
+ return "Instance ID";
119
+ };
120
+ const getOverallStatus = () => {
121
+ if (!instance.resourceStates || instance.resourceStates.length === 0) {
122
+ return "unknown";
123
+ }
124
+ const stateCounts = instance.resourceStates.reduce((acc, resource) => {
125
+ acc[resource.state] = (acc[resource.state] || 0) + 1;
126
+ return acc;
127
+ }, {});
128
+ let maxCount = 0;
129
+ let maxStatus = "unknown";
130
+ for (const [status, count] of Object.entries(stateCounts)) {
131
+ if (count > maxCount) {
132
+ maxCount = count;
133
+ maxStatus = status;
134
+ }
135
+ }
136
+ return maxStatus;
137
+ };
138
+ const overallStatus = getOverallStatus();
139
+ const handleUpdateClick = () => {
140
+ if (onUpdateClick) {
141
+ onUpdateClick(instance.id);
142
+ }
143
+ };
144
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[auto_1fr_auto] gap-3", children: [
145
+ /* @__PURE__ */ jsx(
146
+ "div",
147
+ {
148
+ className: `mt-1.5 h-2 w-2 rounded-full ${isActive ? "bg-green-400" : "bg-gray-300"}`
149
+ }
150
+ ),
151
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
152
+ /* @__PURE__ */ jsxs("div", { className: "flex h-min flex-wrap items-center gap-3", children: [
153
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
154
+ /* @__PURE__ */ jsx(
155
+ "span",
156
+ {
157
+ className: "text-sm font-medium text-gray-900 cursor-pointer hover:underline",
158
+ onClick: () => setShowInstanceId(!showInstanceId),
159
+ onMouseEnter: () => setShowTooltip(true),
160
+ onMouseLeave: () => setShowTooltip(false),
161
+ title: showInstanceId ? instance.id : instanceName || instance.id,
162
+ children: displayText
163
+ }
164
+ ),
165
+ showTooltip && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 text-xs text-white bg-gray-800 rounded whitespace-nowrap z-10", children: [
166
+ getTooltipText(),
167
+ /* @__PURE__ */ jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-gray-800" })
168
+ ] })
169
+ ] }),
170
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-gray-600", children: [
171
+ "Version: ",
172
+ instance.versionLabel || "Unknown",
173
+ /* @__PURE__ */ jsx(UpdateBadge, { count: availableUpdates })
174
+ ] }),
175
+ instance.isAirgap && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-indigo-100 px-2 py-0.5 text-xs font-medium text-indigo-700", children: "air gap" }),
176
+ installType && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: installType }),
177
+ instance.resourceStates && instance.resourceStates.length > 0 && /* @__PURE__ */ jsx(StatusBadge, { status: overallStatus })
178
+ ] }),
179
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-4", children: [
180
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
181
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: "First check-in:" }),
182
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600", children: formatDateTime(instance.firstCheckin) })
183
+ ] }),
184
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
185
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: "Last check-in:" }),
186
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600", children: formatDateTime(instance.lastCheckin) })
187
+ ] })
188
+ ] }),
189
+ instance.tags && instance.tags.filter((tag) => tag.key !== "name").length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: instance.tags.filter((tag) => tag.key !== "name").map((tag) => /* @__PURE__ */ jsx(
190
+ "span",
191
+ {
192
+ className: "rounded-md bg-gray-100 px-2 py-1 text-sm text-gray-600",
193
+ children: tag.value
194
+ },
195
+ tag.key
196
+ )) })
197
+ ] }),
198
+ availableUpdates > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
199
+ "button",
200
+ {
201
+ onClick: handleUpdateClick,
202
+ className: "rounded px-4 py-1.5 text-sm font-medium text-white transition-opacity hover:opacity-90",
203
+ style: { backgroundColor: primaryColor },
204
+ children: "Update available"
205
+ }
206
+ ) })
207
+ ] }) });
208
+ }
209
+ InstanceCard.displayName = "InstanceCard";
210
+ var OnlineInstanceList = ({
211
+ instances = [],
212
+ channelReleases = [],
213
+ installOptions = [],
214
+ onUpdateClick,
215
+ primaryColor = "#6366f1",
216
+ activeCount,
217
+ inactiveCount
218
+ }) => {
219
+ const [showInactive, setShowInactive] = useState(false);
220
+ const { activeInstances, inactiveInstances } = filterActiveInactiveInstances(instances);
221
+ const activeTotal = activeCount ?? activeInstances.length;
222
+ const inactiveTotal = inactiveCount ?? inactiveInstances.length;
223
+ const hasInactiveInstances = inactiveTotal > 0;
224
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
225
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
226
+ /* @__PURE__ */ jsxs("h2", { className: "mb-0 flex items-center gap-4 text-xl font-semibold text-gray-900", children: [
227
+ "Online instances",
228
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold text-emerald-500", children: [
229
+ activeTotal,
230
+ " active"
231
+ ] }),
232
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold text-rose-400", children: [
233
+ inactiveTotal,
234
+ " inactive"
235
+ ] })
236
+ ] }),
237
+ hasInactiveInstances && /* @__PURE__ */ jsx(
238
+ "button",
239
+ {
240
+ onClick: () => setShowInactive(!showInactive),
241
+ className: "mb-0 cursor-pointer text-sm font-medium text-blue-500 hover:underline",
242
+ children: showInactive ? "Hide inactive instances" : "Show inactive instances"
243
+ }
244
+ )
245
+ ] }),
246
+ /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
247
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
248
+ /* @__PURE__ */ jsxs("h3", { className: "text-sm font-medium text-gray-800", children: [
249
+ "Active",
250
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-gray-400", children: "last 24 hours" })
251
+ ] }),
252
+ activeInstances.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-gray-200 bg-white p-4 text-sm text-gray-500", children: "No active instances found" }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: activeInstances.map((instance) => /* @__PURE__ */ jsx(
253
+ InstanceCard,
254
+ {
255
+ instance,
256
+ isActive: true,
257
+ channelReleases,
258
+ installOptions,
259
+ onUpdateClick,
260
+ primaryColor
261
+ },
262
+ instance.id
263
+ )) })
264
+ ] }),
265
+ showInactive && inactiveInstances.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
266
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-800", children: "Inactive" }),
267
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: inactiveInstances.map((instance) => /* @__PURE__ */ jsx(
268
+ InstanceCard,
269
+ {
270
+ instance,
271
+ isActive: false,
272
+ channelReleases,
273
+ installOptions,
274
+ onUpdateClick,
275
+ primaryColor
276
+ },
277
+ instance.id
278
+ )) })
279
+ ] })
280
+ ] })
281
+ ] });
282
+ };
283
+ OnlineInstanceList.displayName = "OnlineInstanceList";
284
+
285
+ export { OnlineInstanceList };
286
+ //# sourceMappingURL=online-instance-list.js.map
287
+ //# sourceMappingURL=online-instance-list.js.map