@replicated/portal-components 0.0.15 → 0.0.17
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/components/metadata/registry.json +2 -2
- package/components/metadata/registry.md +2 -2
- package/dist/actions/index.d.mts +1 -637
- package/dist/actions/index.d.ts +1 -637
- package/dist/actions/index.js +2 -1
- package/dist/actions/index.js.map +1 -1
- package/dist/airgap-instances.d.mts +5 -3
- package/dist/airgap-instances.d.ts +5 -3
- package/dist/airgap-instances.js +94 -5
- package/dist/airgap-instances.js.map +1 -1
- package/dist/esm/actions/index.js +2 -1
- package/dist/esm/actions/index.js.map +1 -1
- package/dist/esm/airgap-instances.js +90 -5
- package/dist/esm/airgap-instances.js.map +1 -1
- package/dist/esm/helm-install-wizard.js +28 -15
- package/dist/esm/helm-install-wizard.js.map +1 -1
- package/dist/esm/index.js +6 -11
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/install-actions.js +54 -11
- package/dist/esm/install-actions.js.map +1 -1
- package/dist/esm/instance-card.js +79 -3
- package/dist/esm/instance-card.js.map +1 -1
- package/dist/esm/license-details.js +2 -1
- package/dist/esm/license-details.js.map +1 -1
- package/dist/esm/linux-install-wizard.js +90 -14
- package/dist/esm/linux-install-wizard.js.map +1 -1
- package/dist/esm/online-instance-list.js +90 -5
- package/dist/esm/online-instance-list.js.map +1 -1
- package/dist/esm/pending-installations.js +187 -103
- package/dist/esm/pending-installations.js.map +1 -1
- package/dist/esm/security-card.js +76 -16
- package/dist/esm/security-card.js.map +1 -1
- package/dist/esm/support-card.js +2 -1
- package/dist/esm/support-card.js.map +1 -1
- package/dist/esm/top-nav-user-menu.js +4 -2
- package/dist/esm/top-nav-user-menu.js.map +1 -1
- package/dist/esm/top-nav.js +5 -10
- package/dist/esm/top-nav.js.map +1 -1
- package/dist/esm/update-layout.js +5 -10
- package/dist/esm/update-layout.js.map +1 -1
- package/dist/esm/upload-support-bundle-modal.js +19 -19
- package/dist/esm/upload-support-bundle-modal.js.map +1 -1
- package/dist/esm/utils/index.js +2 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/helm-install-wizard.d.mts +5 -4
- package/dist/helm-install-wizard.d.ts +5 -4
- package/dist/helm-install-wizard.js +28 -15
- package/dist/helm-install-wizard.js.map +1 -1
- package/dist/index-DkjaogsF.d.mts +891 -0
- package/dist/index-DkjaogsF.d.ts +891 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -11
- package/dist/index.js.map +1 -1
- package/dist/install-actions.d.mts +2 -3
- package/dist/install-actions.d.ts +2 -3
- package/dist/install-actions.js +54 -10
- package/dist/install-actions.js.map +1 -1
- package/dist/install-card.d.mts +1 -1
- package/dist/install-card.d.ts +1 -1
- package/dist/instance-card.d.mts +5 -3
- package/dist/instance-card.d.ts +5 -3
- package/dist/instance-card.js +83 -3
- package/dist/instance-card.js.map +1 -1
- package/dist/license-card.d.mts +1 -1
- package/dist/license-card.d.ts +1 -1
- package/dist/license-details.js +2 -1
- package/dist/license-details.js.map +1 -1
- package/dist/linux-install-wizard.d.mts +6 -6
- package/dist/linux-install-wizard.d.ts +6 -6
- package/dist/linux-install-wizard.js +90 -14
- package/dist/linux-install-wizard.js.map +1 -1
- package/dist/online-instance-list.d.mts +5 -3
- package/dist/online-instance-list.d.ts +5 -3
- package/dist/online-instance-list.js +94 -5
- package/dist/online-instance-list.js.map +1 -1
- package/dist/pending-installations.d.mts +3 -3
- package/dist/pending-installations.d.ts +3 -3
- package/dist/pending-installations.js +186 -102
- package/dist/pending-installations.js.map +1 -1
- package/dist/security-card.d.mts +3 -2
- package/dist/security-card.d.ts +3 -2
- package/dist/security-card.js +76 -16
- package/dist/security-card.js.map +1 -1
- package/dist/styles.css +43 -0
- package/dist/support-bundles-card.d.mts +1 -1
- package/dist/support-bundles-card.d.ts +1 -1
- package/dist/support-card.js +2 -1
- package/dist/support-card.js.map +1 -1
- package/dist/{top-nav-0mb1K_H0.d.mts → top-nav-IRIn66wS.d.mts} +2 -1
- package/dist/{top-nav-0mb1K_H0.d.ts → top-nav-IRIn66wS.d.ts} +2 -1
- package/dist/top-nav-user-menu.d.mts +3 -1
- package/dist/top-nav-user-menu.d.ts +3 -1
- package/dist/top-nav-user-menu.js +4 -2
- package/dist/top-nav-user-menu.js.map +1 -1
- package/dist/top-nav.d.mts +1 -1
- package/dist/top-nav.d.ts +1 -1
- package/dist/top-nav.js +5 -10
- package/dist/top-nav.js.map +1 -1
- package/dist/update-layout.js +5 -10
- package/dist/update-layout.js.map +1 -1
- package/dist/upload-support-bundle-modal.d.mts +7 -3
- package/dist/upload-support-bundle-modal.d.ts +7 -3
- package/dist/upload-support-bundle-modal.js +19 -19
- package/dist/upload-support-bundle-modal.js.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/install-B19AaKF_.d.mts +0 -233
- package/dist/install-Bi1qJ8Bu.d.ts +0 -233
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var navigation = require('next/navigation');
|
|
5
6
|
var Link = require('next/link');
|
|
6
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
8
|
|
|
@@ -102,11 +103,18 @@ var formatTimeAgo = (dateString) => {
|
|
|
102
103
|
};
|
|
103
104
|
var PendingInstallations = ({
|
|
104
105
|
fetchPendingInstallationsAction,
|
|
106
|
+
discardInstallationAction,
|
|
105
107
|
initialInstallations = [],
|
|
106
108
|
pollIntervalMs = 5e3
|
|
107
109
|
}) => {
|
|
108
110
|
const [installations, setInstallations] = react.useState(initialInstallations);
|
|
109
111
|
const [showAll, setShowAll] = react.useState(false);
|
|
112
|
+
const [showConfirmDialog, setShowConfirmDialog] = react.useState(false);
|
|
113
|
+
const [installationToDiscard, setInstallationToDiscard] = react.useState(null);
|
|
114
|
+
const [isDiscarding, setIsDiscarding] = react.useState(false);
|
|
115
|
+
const [discardError, setDiscardError] = react.useState(null);
|
|
116
|
+
const searchParams = navigation.useSearchParams();
|
|
117
|
+
const router = navigation.useRouter();
|
|
110
118
|
react.useEffect(() => {
|
|
111
119
|
const fetchInstallations = async () => {
|
|
112
120
|
try {
|
|
@@ -123,117 +131,193 @@ var PendingInstallations = ({
|
|
|
123
131
|
const intervalId = setInterval(fetchInstallations, pollIntervalMs);
|
|
124
132
|
return () => clearInterval(intervalId);
|
|
125
133
|
}, [fetchPendingInstallationsAction, pollIntervalMs]);
|
|
134
|
+
const installOptionsId = searchParams.get("installOptionsId");
|
|
135
|
+
if (installOptionsId) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
126
138
|
if (installations.length === 0) {
|
|
127
139
|
return null;
|
|
128
140
|
}
|
|
129
141
|
const firstInstallation = installations[0];
|
|
130
142
|
const remainingCount = installations.length - 1;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
const handleDeleteClick = (installation) => {
|
|
144
|
+
setInstallationToDiscard(installation);
|
|
145
|
+
setShowConfirmDialog(true);
|
|
146
|
+
setDiscardError(null);
|
|
147
|
+
};
|
|
148
|
+
const handleCancelDiscard = () => {
|
|
149
|
+
setShowConfirmDialog(false);
|
|
150
|
+
setInstallationToDiscard(null);
|
|
151
|
+
setDiscardError(null);
|
|
152
|
+
};
|
|
153
|
+
const handleConfirmDiscard = async () => {
|
|
154
|
+
if (!installationToDiscard || !discardInstallationAction) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
setIsDiscarding(true);
|
|
158
|
+
setDiscardError(null);
|
|
159
|
+
try {
|
|
160
|
+
await discardInstallationAction(installationToDiscard.id);
|
|
161
|
+
const result = await fetchPendingInstallationsAction();
|
|
162
|
+
setInstallations(result.installations);
|
|
163
|
+
const currentInstallOptionsId = searchParams.get("installOptionsId");
|
|
164
|
+
if (currentInstallOptionsId === installationToDiscard.id) {
|
|
165
|
+
router.push("/install");
|
|
166
|
+
}
|
|
167
|
+
setShowConfirmDialog(false);
|
|
168
|
+
setInstallationToDiscard(null);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error("[pending-installations] Failed to discard installation", error);
|
|
171
|
+
setDiscardError(error instanceof Error ? error.message : "Failed to discard installation");
|
|
172
|
+
} finally {
|
|
173
|
+
setIsDiscarding(false);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 rounded-xl border border-orange-200 bg-orange-50 p-6", children: [
|
|
177
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-4", children: [
|
|
178
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 text-orange-600", children: /* @__PURE__ */ jsxRuntime.jsx(ClockIcon, {}) }),
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-3", children: [
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
182
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-base font-semibold text-gray-900", children: [
|
|
183
|
+
"Pending installation: ",
|
|
184
|
+
firstInstallation.name,
|
|
185
|
+
" \u2022",
|
|
186
|
+
" ",
|
|
187
|
+
firstInstallation.method === "helm" ? "Helm" : "Linux",
|
|
188
|
+
" installation"
|
|
189
|
+
] }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-gray-600", children: [
|
|
191
|
+
"Started ",
|
|
192
|
+
formatTimeAgo(firstInstallation.startedAt),
|
|
193
|
+
" by ",
|
|
194
|
+
firstInstallation.startedBy
|
|
195
|
+
] }),
|
|
196
|
+
remainingCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
197
|
+
"button",
|
|
198
|
+
{
|
|
199
|
+
type: "button",
|
|
200
|
+
onClick: () => setShowAll(!showAll),
|
|
201
|
+
className: "mt-2 flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900",
|
|
202
|
+
children: [
|
|
203
|
+
"View ",
|
|
204
|
+
remainingCount,
|
|
205
|
+
" more pending installation",
|
|
206
|
+
remainingCount !== 1 ? "s" : "",
|
|
207
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, {})
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
)
|
|
149
211
|
] }),
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
"
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
212
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
213
|
+
discardInstallationAction && /* @__PURE__ */ jsxRuntime.jsx(
|
|
214
|
+
"button",
|
|
215
|
+
{
|
|
216
|
+
type: "button",
|
|
217
|
+
onClick: () => handleDeleteClick(firstInstallation),
|
|
218
|
+
className: "rounded-lg p-2 text-red-600 transition hover:bg-red-100",
|
|
219
|
+
"aria-label": "Delete installation",
|
|
220
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {})
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
224
|
+
Link__default.default,
|
|
225
|
+
{
|
|
226
|
+
href: `/install?installOptionsId=${firstInstallation.id}&type=${firstInstallation.method}&step=2`,
|
|
227
|
+
className: "inline-flex items-center gap-2 rounded-lg bg-orange-200 px-4 py-2 text-sm font-semibold text-gray-900 transition hover:bg-orange-300",
|
|
228
|
+
children: [
|
|
229
|
+
"Continue installation",
|
|
230
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArrowRightIcon, {})
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
)
|
|
234
|
+
] })
|
|
165
235
|
] }),
|
|
166
|
-
/* @__PURE__ */ jsxRuntime.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
)
|
|
187
|
-
] })
|
|
188
|
-
] }),
|
|
189
|
-
showAll && remainingCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 space-y-2 border-t border-orange-200 pt-4", children: installations.slice(1).map((installation) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
190
|
-
"div",
|
|
191
|
-
{
|
|
192
|
-
className: "flex items-center justify-between rounded-lg bg-white p-3",
|
|
193
|
-
children: [
|
|
194
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
195
|
-
/* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "text-sm font-medium text-gray-900", children: [
|
|
196
|
-
installation.name,
|
|
197
|
-
" \u2022",
|
|
198
|
-
" ",
|
|
199
|
-
installation.method === "helm" ? "Helm" : "Linux",
|
|
200
|
-
" installation"
|
|
236
|
+
showAll && remainingCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 space-y-2 border-t border-orange-200 pt-4", children: installations.slice(1).map((installation) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
237
|
+
"div",
|
|
238
|
+
{
|
|
239
|
+
className: "flex items-center justify-between rounded-lg bg-white p-3",
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "text-sm font-medium text-gray-900", children: [
|
|
243
|
+
installation.name,
|
|
244
|
+
" \u2022",
|
|
245
|
+
" ",
|
|
246
|
+
installation.method === "helm" ? "Helm" : "Linux",
|
|
247
|
+
" installation"
|
|
248
|
+
] }),
|
|
249
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 text-xs text-gray-600", children: [
|
|
250
|
+
"Started ",
|
|
251
|
+
formatTimeAgo(installation.startedAt),
|
|
252
|
+
" by ",
|
|
253
|
+
installation.startedBy
|
|
254
|
+
] })
|
|
201
255
|
] }),
|
|
202
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
256
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
257
|
+
discardInstallationAction && /* @__PURE__ */ jsxRuntime.jsx(
|
|
258
|
+
"button",
|
|
259
|
+
{
|
|
260
|
+
type: "button",
|
|
261
|
+
onClick: () => handleDeleteClick(installation),
|
|
262
|
+
className: "rounded-lg p-2 text-red-600 transition hover:bg-red-100",
|
|
263
|
+
"aria-label": "Delete installation",
|
|
264
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {})
|
|
265
|
+
}
|
|
266
|
+
),
|
|
267
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
268
|
+
Link__default.default,
|
|
269
|
+
{
|
|
270
|
+
href: `/install?installOptionsId=${installation.id}&type=${installation.method}&step=2`,
|
|
271
|
+
className: "inline-flex items-center gap-2 rounded-lg bg-orange-200 px-3 py-1.5 text-xs font-semibold text-gray-900 transition hover:bg-orange-300",
|
|
272
|
+
children: [
|
|
273
|
+
"Continue",
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArrowRightIcon, {})
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
)
|
|
207
278
|
] })
|
|
208
|
-
]
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
installation.id
|
|
282
|
+
)) })
|
|
283
|
+
] })
|
|
284
|
+
] }),
|
|
285
|
+
showConfirmDialog && installationToDiscard && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-md rounded-lg bg-white p-6 shadow-xl", children: [
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Discard install and service account token" }),
|
|
287
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
|
|
288
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
|
|
289
|
+
"This will permanently delete the service account",
|
|
290
|
+
" ",
|
|
291
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "rounded bg-gray-100 px-1 py-0.5 text-sm", children: installationToDiscard.name }),
|
|
292
|
+
" ",
|
|
293
|
+
"and remove the pending installation. This action cannot be undone."
|
|
294
|
+
] }),
|
|
295
|
+
discardError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-sm text-red-600", children: "Failed to discard installation. Please try again." })
|
|
296
|
+
] }),
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex justify-end gap-3", children: [
|
|
298
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
299
|
+
"button",
|
|
300
|
+
{
|
|
301
|
+
type: "button",
|
|
302
|
+
onClick: handleCancelDiscard,
|
|
303
|
+
disabled: isDiscarding,
|
|
304
|
+
className: "rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50",
|
|
305
|
+
children: "Cancel"
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
309
|
+
"button",
|
|
310
|
+
{
|
|
311
|
+
type: "button",
|
|
312
|
+
onClick: handleConfirmDiscard,
|
|
313
|
+
disabled: isDiscarding,
|
|
314
|
+
className: "rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:opacity-50",
|
|
315
|
+
children: isDiscarding ? "Discarding..." : "Discard install and token"
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
] })
|
|
319
|
+
] }) })
|
|
320
|
+
] });
|
|
237
321
|
};
|
|
238
322
|
PendingInstallations.displayName = "PendingInstallations";
|
|
239
323
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/pending-installations.tsx"],"names":["jsxs","jsx","useState","useEffect","Link"],"mappings":"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","file":"pending-installations.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Link from \"next/link\";\nimport type { PendingInstallation, FetchPendingInstallationsResult } from \"../actions/install\";\n\nexport interface PendingInstallationsProps {\n fetchPendingInstallationsAction: () => Promise<FetchPendingInstallationsResult>;\n initialInstallations?: PendingInstallation[];\n pollIntervalMs?: number;\n}\n\nconst ClockIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-6 w-6\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n);\n\nconst TrashIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-5 w-5\"\n >\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst ArrowRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n >\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n <polyline points=\"12 5 19 12 12 19\" />\n </svg>\n);\n\nconst formatTimeAgo = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n const now = new Date();\n const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);\n\n if (seconds < 60) return \"just now\";\n if (seconds < 3600) {\n const minutes = Math.floor(seconds / 60);\n return `${minutes} ${minutes === 1 ? \"minute\" : \"minutes\"} ago`;\n }\n if (seconds < 86400) {\n const hours = Math.floor(seconds / 3600);\n return `${hours === 1 ? \"an hour\" : `${hours} hours`} ago`;\n }\n const days = Math.floor(seconds / 86400);\n return `${days} ${days === 1 ? \"day\" : \"days\"} ago`;\n } catch {\n return dateString;\n }\n};\n\nexport const PendingInstallations = ({\n fetchPendingInstallationsAction,\n initialInstallations = [],\n pollIntervalMs = 5000\n}: PendingInstallationsProps) => {\n const [installations, setInstallations] = useState<PendingInstallation[]>(initialInstallations);\n const [showAll, setShowAll] = useState(false);\n\n useEffect(() => {\n const fetchInstallations = async () => {\n try {\n const result = await fetchPendingInstallationsAction();\n setInstallations(result.installations);\n } catch (error) {\n console.error(\"[pending-installations] Failed to fetch pending installations\", error);\n }\n };\n\n // Fetch immediately\n fetchInstallations();\n\n // Set up polling interval (skip if pollIntervalMs is 0 or falsy)\n if (!pollIntervalMs) {\n return;\n }\n const intervalId = setInterval(fetchInstallations, pollIntervalMs);\n\n // Cleanup on unmount\n return () => clearInterval(intervalId);\n }, [fetchPendingInstallationsAction, pollIntervalMs]);\n\n // Don't render if no pending installations\n if (installations.length === 0) {\n return null;\n }\n\n const firstInstallation = installations[0]!;\n const remainingCount = installations.length - 1;\n\n return (\n <div className=\"mb-6 rounded-xl border border-orange-200 bg-orange-50 p-6\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex-shrink-0 text-orange-600\">\n <ClockIcon />\n </div>\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-gray-900\">\n Pending installation: {firstInstallation.name} •{\" \"}\n {firstInstallation.method === \"helm\" ? \"Helm\" : \"Linux\"} installation\n </h3>\n <p className=\"mt-1 text-sm text-gray-600\">\n Started {formatTimeAgo(firstInstallation.startedAt)} by {firstInstallation.startedBy}\n </p>\n {remainingCount > 0 && (\n <button\n type=\"button\"\n onClick={() => setShowAll(!showAll)}\n className=\"mt-2 flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900\"\n >\n View {remainingCount} more pending installation{remainingCount !== 1 ? \"s\" : \"\"}\n <ChevronRightIcon />\n </button>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n className=\"rounded-lg p-2 text-red-600 transition hover:bg-red-100\"\n aria-label=\"Delete installation\"\n >\n <TrashIcon />\n </button>\n <Link\n href={`/install?installOptionsId=${firstInstallation.id}&type=${firstInstallation.method}&step=2`}\n className=\"inline-flex items-center gap-2 rounded-lg bg-orange-200 px-4 py-2 text-sm font-semibold text-gray-900 transition hover:bg-orange-300\"\n >\n Continue installation\n <ArrowRightIcon />\n </Link>\n </div>\n </div>\n\n {showAll && remainingCount > 0 && (\n <div className=\"mt-4 space-y-2 border-t border-orange-200 pt-4\">\n {installations.slice(1).map((installation) => (\n <div\n key={installation.id}\n className=\"flex items-center justify-between rounded-lg bg-white p-3\"\n >\n <div>\n <h4 className=\"text-sm font-medium text-gray-900\">\n {installation.name} •{\" \"}\n {installation.method === \"helm\" ? \"Helm\" : \"Linux\"} installation\n </h4>\n <p className=\"mt-0.5 text-xs text-gray-600\">\n Started {formatTimeAgo(installation.startedAt)} by {installation.startedBy}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n className=\"rounded-lg p-2 text-red-600 transition hover:bg-red-100\"\n aria-label=\"Delete installation\"\n >\n <TrashIcon />\n </button>\n <Link\n href={`/install?installOptionsId=${installation.id}&type=${installation.method}&step=2`}\n className=\"inline-flex items-center gap-2 rounded-lg bg-orange-200 px-3 py-1.5 text-xs font-semibold text-gray-900 transition hover:bg-orange-300\"\n >\n Continue\n <ArrowRightIcon />\n </Link>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nPendingInstallations.displayName = \"PendingInstallations\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/pending-installations.tsx"],"names":["jsxs","jsx","useState","useSearchParams","useRouter","useEffect","Link"],"mappings":"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","file":"pending-installations.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useSearchParams, useRouter } from \"next/navigation\";\nimport Link from \"next/link\";\nimport type { PendingInstallation, FetchPendingInstallationsResult, DiscardInstallationResult } from \"../actions/install\";\n\nexport interface PendingInstallationsProps {\n fetchPendingInstallationsAction: () => Promise<FetchPendingInstallationsResult>;\n discardInstallationAction?: (installOptionsId: string) => Promise<DiscardInstallationResult>;\n initialInstallations?: PendingInstallation[];\n pollIntervalMs?: number;\n}\n\nconst ClockIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-6 w-6\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n);\n\nconst TrashIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-5 w-5\"\n >\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst ArrowRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n >\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n <polyline points=\"12 5 19 12 12 19\" />\n </svg>\n);\n\nconst formatTimeAgo = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n const now = new Date();\n const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);\n\n if (seconds < 60) return \"just now\";\n if (seconds < 3600) {\n const minutes = Math.floor(seconds / 60);\n return `${minutes} ${minutes === 1 ? \"minute\" : \"minutes\"} ago`;\n }\n if (seconds < 86400) {\n const hours = Math.floor(seconds / 3600);\n return `${hours === 1 ? \"an hour\" : `${hours} hours`} ago`;\n }\n const days = Math.floor(seconds / 86400);\n return `${days} ${days === 1 ? \"day\" : \"days\"} ago`;\n } catch {\n return dateString;\n }\n};\n\nexport const PendingInstallations = ({\n fetchPendingInstallationsAction,\n discardInstallationAction,\n initialInstallations = [],\n pollIntervalMs = 5000\n}: PendingInstallationsProps) => {\n const [installations, setInstallations] = useState<PendingInstallation[]>(initialInstallations);\n const [showAll, setShowAll] = useState(false);\n const [showConfirmDialog, setShowConfirmDialog] = useState(false);\n const [installationToDiscard, setInstallationToDiscard] = useState<PendingInstallation | null>(null);\n const [isDiscarding, setIsDiscarding] = useState(false);\n const [discardError, setDiscardError] = useState<string | null>(null);\n const searchParams = useSearchParams();\n const router = useRouter();\n\n useEffect(() => {\n const fetchInstallations = async () => {\n try {\n const result = await fetchPendingInstallationsAction();\n setInstallations(result.installations);\n } catch (error) {\n console.error(\"[pending-installations] Failed to fetch pending installations\", error);\n }\n };\n\n // Fetch immediately\n fetchInstallations();\n\n // Set up polling interval (skip if pollIntervalMs is 0 or falsy)\n if (!pollIntervalMs) {\n return;\n }\n const intervalId = setInterval(fetchInstallations, pollIntervalMs);\n\n // Cleanup on unmount\n return () => clearInterval(intervalId);\n }, [fetchPendingInstallationsAction, pollIntervalMs]);\n\n // Don't show banner if already viewing a pending installation\n const installOptionsId = searchParams.get(\"installOptionsId\");\n if (installOptionsId) {\n return null;\n }\n\n // Don't render if no pending installations\n if (installations.length === 0) {\n return null;\n }\n\n const firstInstallation = installations[0]!;\n const remainingCount = installations.length - 1;\n\n const handleDeleteClick = (installation: PendingInstallation) => {\n setInstallationToDiscard(installation);\n setShowConfirmDialog(true);\n setDiscardError(null);\n };\n\n const handleCancelDiscard = () => {\n setShowConfirmDialog(false);\n setInstallationToDiscard(null);\n setDiscardError(null);\n };\n\n const handleConfirmDiscard = async () => {\n if (!installationToDiscard || !discardInstallationAction) {\n return;\n }\n\n setIsDiscarding(true);\n setDiscardError(null);\n\n try {\n await discardInstallationAction(installationToDiscard.id);\n \n // Refresh the installations list\n const result = await fetchPendingInstallationsAction();\n setInstallations(result.installations);\n \n // If we're currently viewing the discarded installation, redirect to install page\n // Check current URL state, not captured closure value\n const currentInstallOptionsId = searchParams.get(\"installOptionsId\");\n if (currentInstallOptionsId === installationToDiscard.id) {\n router.push(\"/install\");\n }\n \n // Close the dialog\n setShowConfirmDialog(false);\n setInstallationToDiscard(null);\n } catch (error) {\n console.error(\"[pending-installations] Failed to discard installation\", error);\n setDiscardError(error instanceof Error ? error.message : \"Failed to discard installation\");\n } finally {\n setIsDiscarding(false);\n }\n };\n\n return (\n <div className=\"mb-6 rounded-xl border border-orange-200 bg-orange-50 p-6\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex-shrink-0 text-orange-600\">\n <ClockIcon />\n </div>\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-gray-900\">\n Pending installation: {firstInstallation.name} •{\" \"}\n {firstInstallation.method === \"helm\" ? \"Helm\" : \"Linux\"} installation\n </h3>\n <p className=\"mt-1 text-sm text-gray-600\">\n Started {formatTimeAgo(firstInstallation.startedAt)} by {firstInstallation.startedBy}\n </p>\n {remainingCount > 0 && (\n <button\n type=\"button\"\n onClick={() => setShowAll(!showAll)}\n className=\"mt-2 flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900\"\n >\n View {remainingCount} more pending installation{remainingCount !== 1 ? \"s\" : \"\"}\n <ChevronRightIcon />\n </button>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {discardInstallationAction && (\n <button\n type=\"button\"\n onClick={() => handleDeleteClick(firstInstallation)}\n className=\"rounded-lg p-2 text-red-600 transition hover:bg-red-100\"\n aria-label=\"Delete installation\"\n >\n <TrashIcon />\n </button>\n )}\n <Link\n href={`/install?installOptionsId=${firstInstallation.id}&type=${firstInstallation.method}&step=2`}\n className=\"inline-flex items-center gap-2 rounded-lg bg-orange-200 px-4 py-2 text-sm font-semibold text-gray-900 transition hover:bg-orange-300\"\n >\n Continue installation\n <ArrowRightIcon />\n </Link>\n </div>\n </div>\n\n {showAll && remainingCount > 0 && (\n <div className=\"mt-4 space-y-2 border-t border-orange-200 pt-4\">\n {installations.slice(1).map((installation) => (\n <div\n key={installation.id}\n className=\"flex items-center justify-between rounded-lg bg-white p-3\"\n >\n <div>\n <h4 className=\"text-sm font-medium text-gray-900\">\n {installation.name} •{\" \"}\n {installation.method === \"helm\" ? \"Helm\" : \"Linux\"} installation\n </h4>\n <p className=\"mt-0.5 text-xs text-gray-600\">\n Started {formatTimeAgo(installation.startedAt)} by {installation.startedBy}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n {discardInstallationAction && (\n <button\n type=\"button\"\n onClick={() => handleDeleteClick(installation)}\n className=\"rounded-lg p-2 text-red-600 transition hover:bg-red-100\"\n aria-label=\"Delete installation\"\n >\n <TrashIcon />\n </button>\n )}\n <Link\n href={`/install?installOptionsId=${installation.id}&type=${installation.method}&step=2`}\n className=\"inline-flex items-center gap-2 rounded-lg bg-orange-200 px-3 py-1.5 text-xs font-semibold text-gray-900 transition hover:bg-orange-300\"\n >\n Continue\n <ArrowRightIcon />\n </Link>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Confirmation Dialog */}\n {showConfirmDialog && installationToDiscard && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50\">\n <div className=\"w-full max-w-md rounded-lg bg-white p-6 shadow-xl\">\n <h3 className=\"text-lg font-semibold text-gray-900\">\n Discard install and service account token\n </h3>\n <div className=\"mt-4\">\n <p className=\"text-sm text-gray-600\">\n This will permanently delete the service account{\" \"}\n <code className=\"rounded bg-gray-100 px-1 py-0.5 text-sm\">{installationToDiscard.name}</code>{\" \"}\n and remove the pending installation. This action cannot be undone.\n </p>\n {discardError && (\n <p className=\"mt-3 text-sm text-red-600\">\n Failed to discard installation. Please try again.\n </p>\n )}\n </div>\n <div className=\"mt-6 flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={handleCancelDiscard}\n disabled={isDiscarding}\n className=\"rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirmDiscard}\n disabled={isDiscarding}\n className=\"rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:opacity-50\"\n >\n {isDiscarding ? \"Discarding...\" : \"Discard install and token\"}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nPendingInstallations.displayName = \"PendingInstallations\";\n"]}
|
package/dist/security-card.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import { C as ChannelRelease } from './install-B19AaKF_.mjs';
|
|
2
|
+
import { S as SecurityReleaseImage, aq as SecurityInfoDiff, as as SBOMMetadata, al as SecurityInstallType, C as ChannelRelease } from './index-DkjaogsF.mjs';
|
|
4
3
|
|
|
5
4
|
/** Pre-fetched security data for SSR */
|
|
6
5
|
interface InitialSecurityData {
|
|
7
6
|
/** Security scan results */
|
|
8
7
|
securityInfo?: {
|
|
9
8
|
images: SecurityReleaseImage[];
|
|
9
|
+
activeInstancesByVersion?: Record<string, number>;
|
|
10
10
|
};
|
|
11
11
|
/** CVE diff between releases */
|
|
12
12
|
securityDiff?: {
|
|
@@ -46,6 +46,7 @@ interface SecurityCardProps {
|
|
|
46
46
|
channelSequence: number;
|
|
47
47
|
}) => Promise<{
|
|
48
48
|
images: SecurityReleaseImage[];
|
|
49
|
+
activeInstancesByVersion?: Record<string, number>;
|
|
49
50
|
}>;
|
|
50
51
|
/** Callback to fetch security diff */
|
|
51
52
|
onFetchSecurityDiff?: (params: {
|
package/dist/security-card.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import { C as ChannelRelease } from './install-Bi1qJ8Bu.js';
|
|
2
|
+
import { S as SecurityReleaseImage, aq as SecurityInfoDiff, as as SBOMMetadata, al as SecurityInstallType, C as ChannelRelease } from './index-DkjaogsF.js';
|
|
4
3
|
|
|
5
4
|
/** Pre-fetched security data for SSR */
|
|
6
5
|
interface InitialSecurityData {
|
|
7
6
|
/** Security scan results */
|
|
8
7
|
securityInfo?: {
|
|
9
8
|
images: SecurityReleaseImage[];
|
|
9
|
+
activeInstancesByVersion?: Record<string, number>;
|
|
10
10
|
};
|
|
11
11
|
/** CVE diff between releases */
|
|
12
12
|
securityDiff?: {
|
|
@@ -46,6 +46,7 @@ interface SecurityCardProps {
|
|
|
46
46
|
channelSequence: number;
|
|
47
47
|
}) => Promise<{
|
|
48
48
|
images: SecurityReleaseImage[];
|
|
49
|
+
activeInstancesByVersion?: Record<string, number>;
|
|
49
50
|
}>;
|
|
50
51
|
/** Callback to fetch security diff */
|
|
51
52
|
onFetchSecurityDiff?: (params: {
|
package/dist/security-card.js
CHANGED
|
@@ -168,6 +168,7 @@ var Dropdown = ({ value, options, onChange, disabled, testId }) => {
|
|
|
168
168
|
children: [
|
|
169
169
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
170
170
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: selected?.label || "Select..." }),
|
|
171
|
+
selected?.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-green-50 px-1.5 py-0.5 text-xs font-medium text-green-600", children: selected.badge }),
|
|
171
172
|
selected?.sublabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-gray-500", children: selected.sublabel })
|
|
172
173
|
] }),
|
|
173
174
|
/* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { className: "h-4 w-4 text-gray-500" })
|
|
@@ -187,7 +188,10 @@ var Dropdown = ({ value, options, onChange, disabled, testId }) => {
|
|
|
187
188
|
"data-testid": `${testId}-option-${option.value}`,
|
|
188
189
|
className: "flex w-full items-center justify-between px-4 py-2 text-left text-sm hover:bg-gray-100",
|
|
189
190
|
children: [
|
|
190
|
-
/* @__PURE__ */ jsxRuntime.
|
|
191
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-gray-900", children: option.label }),
|
|
193
|
+
option.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-green-50 px-1.5 py-0.5 text-xs font-medium text-green-600", children: option.badge })
|
|
194
|
+
] }),
|
|
191
195
|
option.sublabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500", children: option.sublabel })
|
|
192
196
|
]
|
|
193
197
|
},
|
|
@@ -349,14 +353,12 @@ function SecurityCard({
|
|
|
349
353
|
if (!selectedSequence) return filteredReleases[0] || null;
|
|
350
354
|
return filteredReleases.find((r) => r.channelSequence === selectedSequence) || null;
|
|
351
355
|
}, [filteredReleases, selectedSequence]);
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return filteredReleases[idx + 1];
|
|
359
|
-
}, [filteredReleases, selectedRelease]);
|
|
356
|
+
const latestRelease = react.useMemo(() => {
|
|
357
|
+
return filteredReleases.length > 0 ? filteredReleases[0] : null;
|
|
358
|
+
}, [filteredReleases]);
|
|
359
|
+
const isSelectedLatest = react.useMemo(() => {
|
|
360
|
+
return selectedRelease?.channelSequence === latestRelease?.channelSequence;
|
|
361
|
+
}, [selectedRelease, latestRelease]);
|
|
360
362
|
react.useEffect(() => {
|
|
361
363
|
const firstRelease = filteredReleases[0];
|
|
362
364
|
if (filteredReleases.length > 0 && !selectedSequence && firstRelease) {
|
|
@@ -393,12 +395,12 @@ function SecurityCard({
|
|
|
393
395
|
setSecurityError(err instanceof Error ? err.message : "Failed to fetch security data");
|
|
394
396
|
setSecurityData(null);
|
|
395
397
|
}
|
|
396
|
-
if (
|
|
398
|
+
if (!isSelectedLatest && latestRelease && onFetchSecurityDiff) {
|
|
397
399
|
try {
|
|
398
400
|
const diffResult = await onFetchSecurityDiff({
|
|
399
401
|
installType: selectedInstallType,
|
|
400
|
-
fromChannelSequence:
|
|
401
|
-
toChannelSequence:
|
|
402
|
+
fromChannelSequence: selectedRelease.channelSequence,
|
|
403
|
+
toChannelSequence: latestRelease.channelSequence
|
|
402
404
|
});
|
|
403
405
|
setDiffData(diffResult);
|
|
404
406
|
} catch (err) {
|
|
@@ -424,7 +426,7 @@ function SecurityCard({
|
|
|
424
426
|
setIsLoadingSbom(false);
|
|
425
427
|
};
|
|
426
428
|
fetchData();
|
|
427
|
-
}, [selectedRelease, selectedInstallType,
|
|
429
|
+
}, [selectedRelease, selectedInstallType, latestRelease, isSelectedLatest, onFetchSecurityInfo, onFetchSecurityDiff, onFetchSBOM]);
|
|
428
430
|
const installTypeOptions = react.useMemo(() => {
|
|
429
431
|
const options = [];
|
|
430
432
|
if (showLinux) options.push({ value: "linux", label: "Linux" });
|
|
@@ -432,9 +434,10 @@ function SecurityCard({
|
|
|
432
434
|
return options;
|
|
433
435
|
}, [showLinux, showHelm]);
|
|
434
436
|
const releaseOptions = react.useMemo(() => {
|
|
435
|
-
return filteredReleases.map((r) => ({
|
|
437
|
+
return filteredReleases.map((r, index) => ({
|
|
436
438
|
value: r.channelSequence.toString(),
|
|
437
439
|
label: `Version ${r.versionLabel}`,
|
|
440
|
+
badge: index === 0 ? "Latest" : void 0,
|
|
438
441
|
sublabel: `Sequence ${r.channelSequence}${r.isRequired ? " (required)" : ""}`
|
|
439
442
|
}));
|
|
440
443
|
}, [filteredReleases]);
|
|
@@ -501,12 +504,31 @@ function SecurityCard({
|
|
|
501
504
|
}
|
|
502
505
|
}, [selectedRelease, selectedInstallType, onDownloadSBOM]);
|
|
503
506
|
const hasSecurityData = securityData?.images?.some((img) => img.security);
|
|
507
|
+
const activeInstancesOnVersion = react.useMemo(() => {
|
|
508
|
+
if (!selectedRelease?.versionLabel || !securityData?.activeInstancesByVersion) {
|
|
509
|
+
return 0;
|
|
510
|
+
}
|
|
511
|
+
return securityData.activeInstancesByVersion[selectedRelease.versionLabel] || 0;
|
|
512
|
+
}, [selectedRelease, securityData]);
|
|
513
|
+
const fixedCVEsToLatest = react.useMemo(() => {
|
|
514
|
+
if (!diffData?.images) return 0;
|
|
515
|
+
return Object.values(diffData.images).reduce((total, imageDiff) => {
|
|
516
|
+
if (!imageDiff.removed) return total;
|
|
517
|
+
return total + Object.keys(imageDiff.removed.critical || {}).length + Object.keys(imageDiff.removed.high || {}).length + Object.keys(imageDiff.removed.medium || {}).length + Object.keys(imageDiff.removed.low || {}).length;
|
|
518
|
+
}, 0);
|
|
519
|
+
}, [diffData]);
|
|
520
|
+
const hasCriticalFixed = react.useMemo(() => {
|
|
521
|
+
if (!diffData?.images) return false;
|
|
522
|
+
return Object.values(diffData.images).some(
|
|
523
|
+
(imageDiff) => imageDiff.removed?.critical && Object.keys(imageDiff.removed.critical).length > 0
|
|
524
|
+
);
|
|
525
|
+
}, [diffData]);
|
|
504
526
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
505
527
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
506
528
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-900", children: "Security Center" }),
|
|
507
529
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600", children: "Security information and compliance reports for each release" })
|
|
508
530
|
] }),
|
|
509
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
531
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-6", children: [
|
|
510
532
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72", children: [
|
|
511
533
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Install Type" }),
|
|
512
534
|
availableInstallTypes.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -531,7 +553,45 @@ function SecurityCard({
|
|
|
531
553
|
testId: "release-dropdown"
|
|
532
554
|
}
|
|
533
555
|
)
|
|
534
|
-
] })
|
|
556
|
+
] }),
|
|
557
|
+
!isSelectedLatest ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 self-start pt-7", children: [
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
559
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
560
|
+
"a",
|
|
561
|
+
{
|
|
562
|
+
href: "/update",
|
|
563
|
+
className: "rounded px-3 py-1 text-xs text-white no-underline",
|
|
564
|
+
style: {
|
|
565
|
+
backgroundColor: hasCriticalFixed ? "#dc2626" : primaryColor || "#2563eb",
|
|
566
|
+
borderColor: hasCriticalFixed ? "#dc2626" : primaryColor || "#2563eb"
|
|
567
|
+
},
|
|
568
|
+
children: hasCriticalFixed ? "Critical update available" : "Update available"
|
|
569
|
+
}
|
|
570
|
+
),
|
|
571
|
+
fixedCVEsToLatest > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-600", children: [
|
|
572
|
+
fixedCVEsToLatest,
|
|
573
|
+
" Fixed CVEs"
|
|
574
|
+
] })
|
|
575
|
+
] }),
|
|
576
|
+
activeInstancesOnVersion > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600", children: [
|
|
577
|
+
activeInstancesOnVersion,
|
|
578
|
+
" active instance",
|
|
579
|
+
activeInstancesOnVersion !== 1 ? "s" : "",
|
|
580
|
+
" on this version.",
|
|
581
|
+
" ",
|
|
582
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: "/update", className: "font-semibold text-blue-500 hover:underline", children: "See more." })
|
|
583
|
+
] })
|
|
584
|
+
] }) : (
|
|
585
|
+
/* Show active instances inline when on latest */
|
|
586
|
+
activeInstancesOnVersion > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pb-2 text-sm text-gray-600", children: [
|
|
587
|
+
activeInstancesOnVersion,
|
|
588
|
+
" active instance",
|
|
589
|
+
activeInstancesOnVersion !== 1 ? "s" : "",
|
|
590
|
+
" on this version.",
|
|
591
|
+
" ",
|
|
592
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: "/update", className: "font-semibold text-blue-500 hover:underline", children: "See more." })
|
|
593
|
+
] })
|
|
594
|
+
)
|
|
535
595
|
] }),
|
|
536
596
|
(hasSecurityData || isLoadingScans || isLoadingSbom || securityError || sbomError) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-2", children: [
|
|
537
597
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-200 bg-white", children: [
|