@cobaltcore-dev/aurora 1.3.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/ContentHeader-fKKZVu-o.mjs +116 -0
- package/dist/client/ContentHeader-fKKZVu-o.mjs.map +1 -0
- package/dist/client/DeleteFlavorModal-Be2GFiB_.mjs +802 -0
- package/dist/client/DeleteFlavorModal-Be2GFiB_.mjs.map +1 -0
- package/dist/client/{FiltersInput-CKI6zWnm.mjs → FiltersInput-Becwxo_J.mjs} +36 -33
- package/dist/client/FiltersInput-Becwxo_J.mjs.map +1 -0
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs → FloatingIpActionModals-Cq10WljB.mjs} +2 -2
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs.map → FloatingIpActionModals-Cq10WljB.mjs.map} +1 -1
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs +1135 -0
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs.map +1 -0
- package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs +26 -0
- package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs.map +1 -0
- package/dist/client/StorageNotFound-B-zVinVD.mjs +30 -0
- package/dist/client/StorageNotFound-B-zVinVD.mjs.map +1 -0
- package/dist/client/_flavorId-0PioWpEp.mjs +276 -0
- package/dist/client/_flavorId-0PioWpEp.mjs.map +1 -0
- package/dist/client/_flavorId-B7fp6Nk8.mjs +22 -0
- package/dist/client/_flavorId-B7fp6Nk8.mjs.map +1 -0
- package/dist/client/{_flavorId-Dg7MS0Af.mjs → _flavorId-CgueqKTs.mjs} +4 -3
- package/dist/client/_flavorId-CgueqKTs.mjs.map +1 -0
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs → _floatingIpId-B8r64AL9.mjs} +6 -6
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs.map → _floatingIpId-B8r64AL9.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-C9xfRWot.mjs → _floatingIpId-lEobpOER.mjs} +2 -2
- package/dist/client/{_floatingIpId-C9xfRWot.mjs.map → _floatingIpId-lEobpOER.mjs.map} +1 -1
- package/dist/client/{_imageId-8JIbFmGB.mjs → _imageId-Ccv8PedW.mjs} +4 -3
- package/dist/client/_imageId-Ccv8PedW.mjs.map +1 -0
- package/dist/client/_imageId-CiqEQB_J.mjs +558 -0
- package/dist/client/_imageId-CiqEQB_J.mjs.map +1 -0
- package/dist/client/_imageId-D9LR-02T.mjs +22 -0
- package/dist/client/_imageId-D9LR-02T.mjs.map +1 -0
- package/dist/client/{_projectId-DPzv0CCp.mjs → _projectId-BDARsteX.mjs} +4 -4
- package/dist/client/_projectId-BDARsteX.mjs.map +1 -0
- package/dist/client/{_projectId-DfeVJy0G.mjs → _projectId-CtyAHqhH.mjs} +2 -2
- package/dist/client/_projectId-CtyAHqhH.mjs.map +1 -0
- package/dist/client/_projectId-D3VOH5lN.mjs +94 -0
- package/dist/client/_projectId-D3VOH5lN.mjs.map +1 -0
- package/dist/client/{_projectId-B3wmSala.mjs → _projectId-ZBk6vka0.mjs} +83 -81
- package/dist/client/_projectId-ZBk6vka0.mjs.map +1 -0
- package/dist/client/{_securityGroupId-C6eHmrx_.mjs → _securityGroupId-BwgZnoiR.mjs} +2 -2
- package/dist/client/_securityGroupId-BwgZnoiR.mjs.map +1 -0
- package/dist/client/{_securityGroupId-DmplhDgt.mjs → _securityGroupId-Cz2NUHdB.mjs} +750 -741
- package/dist/client/_securityGroupId-Cz2NUHdB.mjs.map +1 -0
- package/dist/client/{_storageType-CzZ4u9x_.mjs → _storageType-BNpP1A2N.mjs} +3 -2
- package/dist/client/_storageType-BNpP1A2N.mjs.map +1 -0
- package/dist/client/_storageType-BxSGKhAI.mjs +15 -0
- package/dist/client/_storageType-BxSGKhAI.mjs.map +1 -0
- package/dist/client/_storageType-DZYCmiLt.mjs +30 -0
- package/dist/client/_storageType-DZYCmiLt.mjs.map +1 -0
- package/dist/client/_storageType-UqAMP-8d.mjs +859 -0
- package/dist/client/_storageType-UqAMP-8d.mjs.map +1 -0
- package/dist/client/_storageType-u51_7OwJ.mjs +7 -0
- package/dist/client/_storageType-u51_7OwJ.mjs.map +1 -0
- package/dist/client/components/{Error → Errors}/RouteError.d.ts +5 -0
- package/dist/client/components/Errors/RouteIdLevelDefaultError.d.ts +18 -0
- package/dist/client/components/Errors/ServiceLevelDefaultError.d.ts +9 -0
- package/dist/client/components/ListToolbar/SelectedFilters.d.ts +7 -2
- package/dist/client/components/ListToolbar/types.d.ts +6 -0
- package/dist/client/components/ListToolbar/valueLabels.d.ts +11 -0
- package/dist/client/{flavors-B1SDOPDu.mjs → flavors-Ce3J-cFa.mjs} +2 -2
- package/dist/client/{flavors-B1SDOPDu.mjs.map → flavors-Ce3J-cFa.mjs.map} +1 -1
- package/dist/client/flavors-D5ThLaXO.mjs +666 -0
- package/dist/client/flavors-D5ThLaXO.mjs.map +1 -0
- package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -1
- package/dist/client/{floatingips-DrCvtXtT.mjs → floatingips-DXnRlLvV.mjs} +7 -7
- package/dist/client/{floatingips-DrCvtXtT.mjs.map → floatingips-DXnRlLvV.mjs.map} +1 -1
- package/dist/client/floatingips-HRbuLxiN.mjs +22 -0
- package/dist/client/floatingips-HRbuLxiN.mjs.map +1 -0
- package/dist/client/floatingips-nN1kQmsu.mjs +14 -0
- package/dist/client/floatingips-nN1kQmsu.mjs.map +1 -0
- package/dist/client/{images-BGQv9kKT.mjs → images-C8M3ysWR.mjs} +810 -770
- package/dist/client/images-C8M3ysWR.mjs.map +1 -0
- package/dist/client/{images-CPmMa4SQ.mjs → images-Cf5R28NR.mjs} +2 -2
- package/dist/client/{images-CPmMa4SQ.mjs.map → images-Cf5R28NR.mjs.map} +1 -1
- package/dist/client/index.js +419 -415
- package/dist/client/index.js.map +1 -1
- package/dist/client/{objects-BR3eeSNH.mjs → objects-BudUAfWY.mjs} +5478 -5519
- package/dist/client/objects-BudUAfWY.mjs.map +1 -0
- package/dist/client/objects-Dc7sKUr8.mjs +67 -0
- package/dist/client/objects-Dc7sKUr8.mjs.map +1 -0
- package/dist/client/objects-Dw7oeTq2.mjs +80 -0
- package/dist/client/objects-Dw7oeTq2.mjs.map +1 -0
- package/dist/client/objects-_g7nGIn5.mjs +25 -0
- package/dist/client/objects-_g7nGIn5.mjs.map +1 -0
- package/dist/client/objects-eBxvY6_n.mjs +78 -0
- package/dist/client/objects-eBxvY6_n.mjs.map +1 -0
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/{securitygroups-DEJQBcxm.mjs → securitygroups-67fFxiwt.mjs} +2 -2
- package/dist/client/{securitygroups-DEJQBcxm.mjs.map → securitygroups-67fFxiwt.mjs.map} +1 -1
- package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -1
- package/dist/client/securitygroups-DXrfyuVF.mjs +580 -0
- package/dist/client/securitygroups-DXrfyuVF.mjs.map +1 -0
- package/dist/client/securitygroups-WLB1_IM6.mjs +22 -0
- package/dist/client/securitygroups-WLB1_IM6.mjs.map +1 -0
- package/dist/client/securitygroups-o0IXZM6S.mjs +14 -0
- package/dist/client/securitygroups-o0IXZM6S.mjs.map +1 -0
- package/dist/client/serviceCatalog-B3lKWC9V.mjs +6 -0
- package/dist/client/serviceCatalog-B3lKWC9V.mjs.map +1 -0
- package/dist/client/storageProviders-CJ5rOh13.mjs +15 -0
- package/dist/client/storageProviders-CJ5rOh13.mjs.map +1 -0
- package/dist/client/trpcClient.d.ts +102 -4
- package/dist/client/useModalTracking-BYd37pXm.mjs +37 -0
- package/dist/client/useModalTracking-BYd37pXm.mjs.map +1 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs +294 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs.map +1 -0
- package/dist/client/utils/serviceCatalog.d.ts +9 -0
- package/dist/client/utils/storageProviders.d.ts +44 -0
- package/dist/server/index.d.ts +102 -4
- package/dist/server/index.js +1319 -416
- package/package.json +4 -4
- package/dist/client/ContentHeader-CPJbgYWn.mjs +0 -115
- package/dist/client/ContentHeader-CPJbgYWn.mjs.map +0 -1
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +0 -773
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +0 -1
- package/dist/client/FiltersInput-CKI6zWnm.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +0 -1152
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +0 -1
- package/dist/client/_flavorId-Dg7MS0Af.mjs.map +0 -1
- package/dist/client/_flavorId-kHl-b8rI.mjs +0 -232
- package/dist/client/_flavorId-kHl-b8rI.mjs.map +0 -1
- package/dist/client/_imageId-8JIbFmGB.mjs.map +0 -1
- package/dist/client/_imageId-BBAlRioC.mjs +0 -574
- package/dist/client/_imageId-BBAlRioC.mjs.map +0 -1
- package/dist/client/_projectId-7Nl1MQTJ.mjs +0 -99
- package/dist/client/_projectId-7Nl1MQTJ.mjs.map +0 -1
- package/dist/client/_projectId-B3wmSala.mjs.map +0 -1
- package/dist/client/_projectId-DPzv0CCp.mjs.map +0 -1
- package/dist/client/_projectId-DfeVJy0G.mjs.map +0 -1
- package/dist/client/_securityGroupId-C6eHmrx_.mjs.map +0 -1
- package/dist/client/_securityGroupId-DmplhDgt.mjs.map +0 -1
- package/dist/client/_storageType-BRWWJtow.mjs +0 -14
- package/dist/client/_storageType-BRWWJtow.mjs.map +0 -1
- package/dist/client/_storageType-C5gS9eut.mjs +0 -845
- package/dist/client/_storageType-C5gS9eut.mjs.map +0 -1
- package/dist/client/_storageType-CzZ4u9x_.mjs.map +0 -1
- package/dist/client/_storageType-zeSZe--V.mjs +0 -7
- package/dist/client/_storageType-zeSZe--V.mjs.map +0 -1
- package/dist/client/flavors-D8_PzQUB.mjs +0 -628
- package/dist/client/flavors-D8_PzQUB.mjs.map +0 -1
- package/dist/client/images-BGQv9kKT.mjs.map +0 -1
- package/dist/client/objects-AERkhfiM.mjs +0 -66
- package/dist/client/objects-AERkhfiM.mjs.map +0 -1
- package/dist/client/objects-BR3eeSNH.mjs.map +0 -1
- package/dist/client/objects-DVccbrL1.mjs +0 -66
- package/dist/client/objects-DVccbrL1.mjs.map +0 -1
- package/dist/client/securitygroups-BjhgLBHm.mjs +0 -620
- package/dist/client/securitygroups-BjhgLBHm.mjs.map +0 -1
- package/dist/client/useModalTracking-BcOKTYRN.mjs +0 -33
- package/dist/client/useModalTracking-BcOKTYRN.mjs.map +0 -1
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs +0 -227
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { i as e } from "./build-WuxXRAqf.mjs";
|
|
2
|
+
import { t } from "./_imageId-Ccv8PedW.mjs";
|
|
3
|
+
import { t as n } from "./RouteIdLevelDefaultError-DPF_x2tG.mjs";
|
|
4
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
5
|
+
import { useNavigate as i } from "@tanstack/react-router";
|
|
6
|
+
import { useLingui as a } from "@lingui/react";
|
|
7
|
+
//#region src/client/routes/_auth/projects/$projectId/compute/images/$imageId.tsx?tsr-split=errorComponent
|
|
8
|
+
function o() {
|
|
9
|
+
let { i18n: o, _: s } = a(), c = i(), { projectId: l } = t.useParams();
|
|
10
|
+
return /*#__PURE__*/ r(n, { action: /*#__PURE__*/ r(e, {
|
|
11
|
+
variant: "primary",
|
|
12
|
+
onClick: () => c({
|
|
13
|
+
to: "/projects/$projectId/compute/images",
|
|
14
|
+
params: { projectId: l }
|
|
15
|
+
}),
|
|
16
|
+
children: o._({ id: "bnql/K" })
|
|
17
|
+
}) });
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { o as errorComponent };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=_imageId-D9LR-02T.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_imageId-D9LR-02T.mjs","names":["Button","useNavigate","useLingui","GlanceImage","MemberStatus","RouteIdLevelDefaultError","ImageErrorComponent","t","navigate","projectId","Route","useParams","to","params","errorComponent"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/images/$imageId.tsx?tsr-split=errorComponent"],"sourcesContent":["import {\n Button,\n Stack,\n Status,\n PopupMenu,\n PopupMenuToggle,\n PopupMenuOptions,\n PopupMenuItem,\n PopupMenuSectionSeparator,\n toast,\n} from \"@cloudoperators/juno-ui-components/index\"\nimport { createFileRoute, redirect, useNavigate, useParams, useSearch } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\nimport { ImageDetailsView } from \"./-components/ImageDetailsView\"\nimport { EditImageDetailsModal } from \"./-components/EditImageDetailsModal\"\nimport { EditImageMetadataModal } from \"./-components/EditImageMetadataModal\"\nimport { DeleteImageModal } from \"./-components/DeleteImageModal\"\nimport { ActivateImageModal } from \"./-components/ActivateImageModal\"\nimport { DeactivateImageModal } from \"./-components/DeactivateImageModal\"\nimport { IMAGE_STATUSES, IMAGE_VISIBILITY } from \"../-constants/filters\"\nimport { GlanceImage, MemberStatus } from \"@/server/Compute/types/image\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { InferrableClientTypes } from \"@trpc/server/unstable-core-do-not-import\"\nimport {\n getImageAccessStatusUpdatedToast,\n getImageAccessStatusErrorToast,\n getImageUpdatedToast,\n getImageActivatedToast,\n getImageActivationErrorToast,\n getImageDeactivatedToast,\n getImageDeactivationErrorToast,\n getImageVisibilityUpdatedToast,\n getImageVisibilityUpdateErrorToast,\n} from \"./-components/ImageToastNotifications\"\nimport { useState } from \"react\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { RouteIdLevelDefaultError } from \"@/client/components/Errors/RouteIdLevelDefaultError\"\n\nfunction ImageErrorComponent() {\n const { t } = useLingui()\n const navigate = useNavigate()\n const { projectId } = Route.useParams()\n\n return (\n <RouteIdLevelDefaultError\n action={\n <Button\n variant=\"primary\"\n onClick={() => navigate({ to: \"/projects/$projectId/compute/images\", params: { projectId } })}\n >\n {t`Back to Images`}\n </Button>\n }\n />\n )\n}\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/images/$imageId\")({\n staticData: {\n section: \"compute\",\n service: \"images\",\n analytics: {\n name: \"compute.images.detail\",\n },\n } satisfies RouteInfo,\n validateSearch: z.object({\n tab: z.enum([\"details\", \"sharing\"]).optional(),\n }),\n loader: async ({ context, params }) => {\n try {\n const image = await context.trpcClient?.compute.getImageById.query({\n project_id: params.projectId,\n imageId: params.imageId,\n })\n return { imageTitle: (image?.name as string | undefined) ?? image?.id ?? null }\n } catch {\n return { imageTitle: null }\n }\n },\n head: ({ loaderData }) => ({\n meta: [{ title: loaderData?.imageTitle ?? \"Image Details\" }],\n }),\n component: RouteComponent,\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const { projectId } = params\n\n const availableServices = (await trpcClient?.auth.getAvailableServices.query()) || []\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if none of compute services available\n if (!serviceIndex[\"image\"] && !serviceIndex[\"compute\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n if (!serviceIndex[\"image\"][\"glance\"]) {\n // Redirect to the \"Compute Services Overview\" page if the \"Glance\" service is not available\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId: params.projectId },\n })\n }\n },\n errorComponent: ImageErrorComponent,\n})\n\nfunction RouteComponent() {\n const { projectId, imageId } = useParams({\n from: \"/_auth/projects/$projectId/compute/images/$imageId\",\n })\n const { tab } = useSearch({\n from: \"/_auth/projects/$projectId/compute/images/$imageId\",\n })\n\n const navigate = useNavigate()\n const { t } = useLingui()\n\n const {\n data: image,\n status,\n error,\n } = trpcReact.compute.getImageById.useQuery({ project_id: projectId, imageId: imageId })\n\n useSetBreadcrumb(Route.id, image?.name as string | undefined)\n\n const { data: permissionsData } = trpcReact.compute.canUser.useQuery({\n project_id: projectId,\n permission: [\n \"images:delete\",\n \"images:update\",\n \"images:create_member\",\n \"images:delete_member\",\n \"images:update_member\",\n ],\n })\n\n const permissions = {\n canDelete: permissionsData?.[0] ?? false,\n canUpdate: permissionsData?.[1] ?? false,\n canCreateMember: permissionsData?.[2] ?? false,\n canDeleteMember: permissionsData?.[3] ?? false,\n canUpdateMember: permissionsData?.[4] ?? false,\n }\n\n const utils = trpcReact.useUtils()\n\n const [editDetailsModalOpen, setEditDetailsModalOpen] = useState(false)\n const [editMetadataModalOpen, setEditMetadataModalOpen] = useState(false)\n const [deleteModalOpen, setDeleteModalOpen] = useState(false)\n const [activateModalOpen, setActivateModalOpen] = useState(false)\n const [deactivateModalOpen, setDeactivateModalOpen] = useState(false)\n\n const updateImageMutation = trpcReact.compute.updateImage.useMutation({\n onSuccess: (updatedImage) => {\n utils.compute.getImageById.setData({ project_id: projectId, imageId }, updatedImage)\n utils.compute.listImagesWithPagination.invalidate()\n },\n })\n\n const deleteImageMutation = trpcReact.compute.deleteImage.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n },\n })\n\n const deactivateImageMutation = trpcReact.compute.deactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.getImageById.invalidate({ project_id: projectId, imageId })\n },\n })\n\n const reactivateImageMutation = trpcReact.compute.reactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.getImageById.invalidate({ project_id: projectId, imageId })\n },\n })\n\n const updateImageVisibilityMutation = trpcReact.compute.updateImageVisibility.useMutation({\n onSuccess: (updatedImage) => {\n utils.compute.getImageById.setData({ project_id: projectId, imageId }, updatedImage)\n },\n })\n\n const isSharedWithMe =\n image?.visibility === IMAGE_VISIBILITY.SHARED && image?.owner !== undefined && image?.owner !== projectId\n\n const { data: myMemberData } = trpcReact.compute.getImageMember.useQuery(\n { project_id: projectId, imageId: imageId, memberId: projectId },\n { enabled: isSharedWithMe && !!imageId && !!projectId }\n )\n\n const updateMemberMutation = trpcReact.compute.updateImageMember.useMutation({\n onSuccess: () => {\n utils.compute.getImageMember.invalidate({ project_id: projectId, imageId: imageId, memberId: projectId })\n utils.compute.listImageMembers.invalidate({ project_id: projectId, imageId: imageId })\n utils.compute.listImagesWithPagination.invalidate()\n utils.compute.listSharedImagesByMemberStatus.invalidate()\n },\n })\n\n const handleMemberStatusChange = async (newStatus: MemberStatus) => {\n try {\n await updateMemberMutation.mutateAsync({ project_id: projectId, imageId, memberId: projectId, status: newStatus })\n const { message, ...options } = getImageAccessStatusUpdatedToast(newStatus)\n toast.info(message, options)\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message\n const { message, ...options } = getImageAccessStatusErrorToast(errorMessage)\n toast.error(message, options)\n }\n }\n\n const handleBack = () => {\n navigate({\n to: \"/projects/$projectId/compute/images\",\n params: { projectId },\n })\n }\n\n const isLoading =\n updateImageMutation.isPending ||\n deleteImageMutation.isPending ||\n deactivateImageMutation.isPending ||\n reactivateImageMutation.isPending ||\n updateImageVisibilityMutation.isPending\n\n const convertToJsonPatchOperations = (\n updatedProperties: Partial<GlanceImage>,\n originalImage: GlanceImage\n ): Array<{ op: \"add\" | \"replace\" | \"remove\"; path: string; value?: unknown }> => {\n const operations: Array<{ op: \"add\" | \"replace\" | \"remove\"; path: string; value?: unknown }> = []\n Object.entries(updatedProperties).forEach(([key, value]) => {\n const path = `/${key}`\n if (value === null || value === undefined) {\n if (key in originalImage) operations.push({ op: \"remove\", path })\n } else {\n const propertyExists = key in originalImage\n operations.push({ op: propertyExists ? \"replace\" : \"add\", path, value })\n }\n })\n return operations\n }\n\n const handleSaveEdit = async (updatedProperties: Partial<GlanceImage>): Promise<boolean> => {\n if (!image) return false\n const operations = convertToJsonPatchOperations(updatedProperties, image)\n try {\n await updateImageMutation.mutateAsync({ project_id: projectId, imageId, operations })\n setEditDetailsModalOpen(false)\n const { message, ...options } = getImageUpdatedToast(String(image.name ?? image.id))\n toast.success(message, options)\n return true\n } catch {\n return false\n }\n }\n\n const handleDelete = async (deletedImage: GlanceImage) => {\n try {\n await deleteImageMutation.mutateAsync({ project_id: projectId, imageId: deletedImage.id })\n setDeleteModalOpen(false)\n handleBack()\n } catch {\n setDeleteModalOpen(false)\n }\n }\n\n const handleActivate = async (img: GlanceImage) => {\n try {\n await reactivateImageMutation.mutateAsync({ project_id: projectId, imageId: img.id })\n setActivateModalOpen(false)\n const { message, ...options } = getImageActivatedToast(String(img.name ?? img.id))\n toast.success(message, options)\n } catch (error) {\n setActivateModalOpen(false)\n const { message, ...options } = getImageActivationErrorToast(img.id, (error as Error)?.message ?? \"\")\n toast.error(message, options)\n }\n }\n\n const handleDeactivate = async (img: GlanceImage) => {\n try {\n await deactivateImageMutation.mutateAsync({ project_id: projectId, imageId: img.id })\n setDeactivateModalOpen(false)\n const { message, ...options } = getImageDeactivatedToast(String(img.name ?? img.id))\n toast.success(message, options)\n } catch (error) {\n setDeactivateModalOpen(false)\n const { message, ...options } = getImageDeactivationErrorToast(img.id, (error as Error)?.message ?? \"\")\n toast.error(message, options)\n }\n }\n\n const handleUpdateVisibility = async (newVisibility: \"public\" | \"private\" | \"shared\" | \"community\") => {\n if (!image) return\n try {\n await updateImageVisibilityMutation.mutateAsync({\n project_id: projectId,\n imageId: image.id,\n visibility: newVisibility,\n })\n const { message, ...options } = getImageVisibilityUpdatedToast(String(image.name ?? image.id), newVisibility)\n toast.success(message, options)\n } catch (error) {\n const { message, ...options } = getImageVisibilityUpdateErrorToast(\n String(image.name ?? image.id),\n (error as Error)?.message ?? \"\"\n )\n toast.error(message, options)\n }\n }\n\n // Handle loading state\n if (status === \"pending\") {\n return <Status status=\"progress\" title={t`Loading Image Details...`} />\n }\n\n // Handle error state\n if (status === \"error\") {\n const errorMessage = error?.message || t`Unknown Error`\n\n return (\n <RouteIdLevelDefaultError\n errorTitle={t`Error Loading Image`}\n errorDescription={errorMessage}\n action={\n <Button onClick={handleBack} variant=\"primary\">\n <Trans>Back to Images</Trans>\n </Button>\n }\n />\n )\n }\n\n // Handle no data state\n if (!image) {\n return <ImageErrorComponent />\n }\n\n const isDeactivated = image.status === IMAGE_STATUSES.DEACTIVATED\n const isPrivate = image.visibility === IMAGE_VISIBILITY.PRIVATE\n const isMemberAccepted = myMemberData?.status === \"accepted\"\n const isImageOwner = image.owner === projectId\n\n const canRejectSharedImage = isSharedWithMe && isMemberAccepted && permissions.canUpdateMember\n const canUpdateOwnImage = !isSharedWithMe && permissions.canUpdate\n const canDeleteOwnImage = !isSharedWithMe && permissions.canDelete && !image.protected\n const canManageSharing =\n !isSharedWithMe &&\n isImageOwner &&\n image.visibility === IMAGE_VISIBILITY.SHARED &&\n (permissions.canCreateMember || permissions.canDeleteMember)\n\n const hasMoreActions = canRejectSharedImage || canUpdateOwnImage || canDeleteOwnImage || canManageSharing\n\n const headerActions = (hasMoreActions || (!isSharedWithMe && permissions.canUpdate)) && (\n <Stack gap=\"0.5\" alignment=\"center\">\n {(hasMoreActions || (!isSharedWithMe && permissions.canUpdate)) && (\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button icon=\"moreVert\" title={t`More Actions`} disabled={isLoading} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n {!isSharedWithMe && permissions.canUpdate && (\n <>\n <PopupMenuItem\n label={isDeactivated ? t`Activate` : t`Deactivate`}\n onClick={() => (isDeactivated ? setActivateModalOpen(true) : setDeactivateModalOpen(true))}\n />\n <PopupMenuItem\n onClick={() => setEditMetadataModalOpen(true)}\n label={t`Edit Metadata`}\n disabled={isLoading}\n />\n </>\n )}\n {!isSharedWithMe &&\n isImageOwner &&\n image.visibility === IMAGE_VISIBILITY.SHARED &&\n (permissions.canCreateMember || permissions.canDeleteMember) && (\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/images/$imageId\",\n params: { projectId, imageId: image.id },\n search: { tab: \"sharing\" },\n })\n }\n />\n )}\n {canRejectSharedImage && (\n <PopupMenuItem label={t`Reject`} onClick={() => handleMemberStatusChange(\"rejected\")} />\n )}\n {!isSharedWithMe && permissions.canUpdate && isPrivate && (\n <PopupMenuItem label={t`Set to \"Shared\"`} onClick={() => handleUpdateVisibility(\"shared\")} />\n )}\n {!isSharedWithMe && permissions.canDelete && !image.protected && (\n <>\n <PopupMenuSectionSeparator />\n <PopupMenuItem label={t`Delete`} onClick={() => setDeleteModalOpen(true)} />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n )}\n\n {!isSharedWithMe && permissions.canUpdate && (\n <Button onClick={() => setEditDetailsModalOpen(true)} variant=\"primary\" disabled={isLoading}>\n <Trans>Edit Details</Trans>\n </Button>\n )}\n </Stack>\n )\n\n // Render success state\n return (\n <>\n <ContentHeader title={String(image.name ?? image.id)} projectId={projectId} actions={headerActions} />\n\n <div className=\"mt-3\">\n <ImageDetailsView\n key={image.id}\n image={image}\n currentProjectId={projectId}\n activeTab={tab ?? \"details\"}\n onTabChange={(newTab) =>\n navigate({\n search: { tab: newTab === \"details\" ? undefined : newTab } as unknown as true,\n })\n }\n permissions={{\n canCreateMember: permissions.canCreateMember,\n canDeleteMember: permissions.canDeleteMember,\n canUpdateMember: permissions.canUpdateMember,\n }}\n myMemberData={myMemberData}\n onMemberStatusChange={handleMemberStatusChange}\n isMemberStatusChanging={updateMemberMutation.isPending}\n />\n </div>\n\n {editDetailsModalOpen && (\n <EditImageDetailsModal\n image={image}\n isOpen={editDetailsModalOpen}\n isLoading={updateImageMutation.isPending}\n onClose={() => setEditDetailsModalOpen(false)}\n onSave={handleSaveEdit}\n />\n )}\n\n {editMetadataModalOpen && (\n <EditImageMetadataModal\n image={image}\n isOpen={editMetadataModalOpen}\n isLoading={updateImageMutation.isPending}\n onClose={() => setEditMetadataModalOpen(false)}\n onSave={handleSaveEdit}\n />\n )}\n\n {deleteModalOpen && (\n <DeleteImageModal\n image={image}\n isOpen={deleteModalOpen}\n isLoading={deleteImageMutation.isPending}\n isDisabled={!!image.protected}\n onClose={() => setDeleteModalOpen(false)}\n onDelete={handleDelete}\n />\n )}\n\n {activateModalOpen && (\n <ActivateImageModal\n image={image}\n isOpen={activateModalOpen}\n isLoading={reactivateImageMutation.isPending}\n onClose={() => setActivateModalOpen(false)}\n onActivate={handleActivate}\n />\n )}\n\n {deactivateModalOpen && (\n <DeactivateImageModal\n image={image}\n isOpen={deactivateModalOpen}\n isLoading={deactivateImageMutation.isPending}\n onClose={() => setDeactivateModalOpen(false)}\n onDeactivate={handleDeactivate}\n />\n )}\n </>\n )\n}\n"],"mappings":";;;;;;;AA2CA,SAASM,IAAAA;CACP,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQJ,EAAAA,GACRM,IAAWP,EAAAA,GACX,EAAEQ,iBAAcC,EAAMC,UAAS;CAErC,OACE,gBAAC,GAAA,EACC,QACE,gBAAC,GAAA;EACC,SAAQ;EACR,eAAeH,EAAS;GAAEI,IAAI;GAAuCC,QAAQ,EAAEJ,aAAU;EAAE,CAAA;EAE1FF,UAAAA,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;;AAKZ"}
|
|
@@ -3,7 +3,7 @@ import { jsx as n } from "react/jsx-runtime";
|
|
|
3
3
|
import { createFileRoute as r, lazyRouteComponent as i, useNavigate as a } from "@tanstack/react-router";
|
|
4
4
|
import { TRPCClientError as o } from "@trpc/client";
|
|
5
5
|
import { Trans as s, useLingui as c } from "@lingui/react";
|
|
6
|
-
//#region src/client/components/
|
|
6
|
+
//#region src/client/components/Errors/RouteError.tsx
|
|
7
7
|
function l({ error: r, title: i, helpText: o, safeErrorMessage: l }) {
|
|
8
8
|
let { i18n: u, _: d } = c(), f = a(), p = u._({ id: "Gfx1qQ" }), m = u._({ id: "K9eC8x" }), h = u._({ id: "W5A0Ly" }), g = l || (typeof r == "string" ? r : null) || (r && typeof r == "object" && "safeMessage" in r && typeof r.safeMessage == "string" ? r.safeMessage : null) || h, _ = o || m;
|
|
9
9
|
return /*#__PURE__*/ n(t, {
|
|
@@ -18,8 +18,8 @@ function l({ error: r, title: i, helpText: o, safeErrorMessage: l }) {
|
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
var u = r("/_auth/projects/$projectId")({
|
|
21
|
-
component: i(() => import("./_projectId-
|
|
22
|
-
errorComponent: i(() => import("./_projectId-
|
|
21
|
+
component: i(() => import("./_projectId-ZBk6vka0.mjs"), "component"),
|
|
22
|
+
errorComponent: i(() => import("./_projectId-CtyAHqhH.mjs"), "errorComponent"),
|
|
23
23
|
loader: async (e) => {
|
|
24
24
|
let { context: t, params: n } = e, r, i;
|
|
25
25
|
try {
|
|
@@ -74,4 +74,4 @@ var u = r("/_auth/projects/$projectId")({
|
|
|
74
74
|
//#endregion
|
|
75
75
|
export { l as n, u as t };
|
|
76
76
|
|
|
77
|
-
//# sourceMappingURL=_projectId-
|
|
77
|
+
//# sourceMappingURL=_projectId-BDARsteX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_projectId-BDARsteX.mjs","names":["Status","Button","useNavigate","RouteError","error","title","helpText","safeErrorMessage","useLingui","navigate","defaultTitle","t","defaultHelpText","defaultErrorMessage","errorMessage","safeMessage","additionalInfo","status","body","action","variant","onClick","to","createFileRoute","TRPCClientError","ScopeError","type","code","message","currentDomain","id","name","Route","component","lazyRouteComponent","$$splitComponentImporter","errorComponent","$$splitErrorComponentImporter","loader","options","context","params","scopeData","scopeError","trpcClient","auth","setCurrentScope","mutate","projectId","error","currentScope","getCurrentScope","query","domain","data","crumbDomain","undefined","crumbProject","availableServices","accountId","description","project","Promise","all","getAvailableServices","getProject","catch","path"],"sources":["../../src/client/components/Errors/RouteError.tsx","../../src/client/routes/_auth/projects/$projectId.tsx"],"sourcesContent":["import { Status, Button } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\n\ninterface RouteErrorProps {\n error: unknown\n title?: string\n helpText?: string\n /** Explicitly pass a safe error message to display. Use this when you want to show specific error details. */\n safeErrorMessage?: string\n}\n\n/**\n * Renders errors that occur outside the application layout, such as an expired\n * cookie or token. In these cases, the normal page content is unavailable and\n * only the header may remain visible.\n */\nexport function RouteError({ error, title, helpText, safeErrorMessage }: RouteErrorProps) {\n const { t } = useLingui()\n const navigate = useNavigate()\n\n const defaultTitle = t`Unable to Load Content`\n const defaultHelpText = t`This could be due to insufficient permissions or a temporary service issue. Please check your access rights or try refreshing the page.`\n const defaultErrorMessage = t`An unexpected error occurred.`\n\n // Security: Do not expose raw Error.message by default as it may contain sensitive information.\n // Only display:\n // 1. Explicitly passed safeErrorMessage\n // 2. String errors (when caller explicitly passes a safe string)\n // 3. error.safeMessage if present (for controlled error exposure)\n // 4. Default translated message for all other cases\n const errorMessage =\n safeErrorMessage ||\n (typeof error === \"string\" ? error : null) ||\n (error && typeof error === \"object\" && \"safeMessage\" in error && typeof error.safeMessage === \"string\"\n ? error.safeMessage\n : null) ||\n defaultErrorMessage\n\n const additionalInfo = helpText || defaultHelpText\n\n return (\n <Status\n status=\"error\"\n title={title || defaultTitle}\n body={errorMessage + \" \" + additionalInfo}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/\" })}>\n <Trans>Go to Home</Trans>\n </Button>\n }\n />\n )\n}\n","import { createFileRoute, Outlet, useLoaderData, useRouteContext } from \"@tanstack/react-router\"\nimport { AppShell, Button, Container, Stack, Status } from \"@cloudoperators/juno-ui-components\"\nimport { SideNavBar } from \"@/client/routes/_auth/projects/-components/SideNavBar\"\nimport { buildNavSections } from \"@/client/routes/_auth/projects/-components/buildNavSections\"\nimport { Breadcrumbs } from \"@/client/components/Breadcrumbs\"\nimport { RouteError } from \"@/client/components/Errors/RouteError\"\nimport { useMemo } from \"react\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport { BreadcrumbExtensionProvider } from \"@/client/context/BreadcrumbExtensionContext\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\n\n// Type for scope error that we catch and handle gracefully\ntype ScopeError = {\n type: \"scope_error\"\n code: string\n message: string\n currentDomain?: { id: string; name: string } | null\n}\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId\")({\n component: RouteComponent,\n errorComponent: ProjectErrorComponent,\n loader: async (options) => {\n const { context, params } = options\n\n // Catch rescope errors and return them as data instead of throwing\n // This allows the component to render a friendly error UI\n let scopeData\n let scopeError: ScopeError | undefined\n\n try {\n scopeData = await context.trpcClient?.auth.setCurrentScope.mutate({\n type: \"project\",\n projectId: params.projectId || \"\",\n })\n } catch (error) {\n if (error instanceof TRPCClientError) {\n // Try to get the current session's domain to show in the error message\n let currentDomain: { id: string; name: string } | null | undefined\n try {\n const currentScope = await context.trpcClient?.auth.getCurrentScope.query()\n if (currentScope?.domain?.id && currentScope?.domain?.name) {\n currentDomain = { id: currentScope.domain.id, name: currentScope.domain.name }\n }\n } catch {\n // Ignore errors fetching current scope\n }\n\n // Return error as data so the component can handle it\n scopeError = {\n type: \"scope_error\",\n code: error.data?.code || \"UNKNOWN\",\n message: error.message,\n currentDomain,\n }\n } else {\n // Unknown errors should still propagate\n throw error\n }\n }\n\n // If scope failed, return early with error state\n if (scopeError) {\n return {\n scopeError,\n projectId: params.projectId,\n // Provide minimal data for error rendering\n trpcClient: context.trpcClient,\n crumbDomain: undefined,\n crumbProject: undefined,\n availableServices: undefined,\n accountId: \"\",\n description: null,\n }\n }\n\n const [availableServices, project] = await Promise.all([\n context.trpcClient?.auth.getAvailableServices.query(),\n context.trpcClient?.project.getProject.query({ projectId: params.projectId }).catch(() => null),\n ])\n\n const accountId = scopeData?.domain?.id || \"\"\n const description = project?.description ?? null\n\n return {\n scopeError: undefined,\n trpcClient: context.trpcClient,\n crumbDomain: { path: `/projects`, name: scopeData?.domain?.name },\n crumbProject: scopeData?.project,\n availableServices,\n accountId,\n projectId: params.projectId,\n description,\n }\n },\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const loaderData = useLoaderData({ from: Route.id })\n const navigate = Route.useNavigate()\n const { enabledServices, serviceExtensions } = useRouteContext({ strict: false })\n\n const projectName = loaderData.crumbProject?.name || loaderData.projectId\n const projectLabel = loaderData.crumbDomain?.name ? `${loaderData.crumbDomain.name}/${projectName}` : projectName\n useSetBreadcrumb(Route.id, projectLabel)\n\n // Handle scope errors with a friendly UI using Juno's Status component\n if (loaderData.scopeError) {\n const { code, message, currentDomain } = loaderData.scopeError\n const domainName = currentDomain?.name\n\n if (code === \"UNAUTHORIZED\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n title={t`Session Changed`}\n body={t`Your session was changed or ended in another browser tab. This can happen if you logged out or switched to a different account or domain elsewhere. Please log in again to continue.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/\" })}>\n <Trans>Sign in</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n if (code === \"NOT_FOUND\") {\n const bodyText = domainName\n ? t`This project doesn't exist or is not accessible from your current domain. Your current domain is ${domainName}. Please select a project from your current domain.`\n : t`This project doesn't exist or is not accessible from your current domain. Please select a project from your current domain.`\n\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={404}\n title={t`Project Not Accessible`}\n body={bodyText}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n if (code === \"FORBIDDEN\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={403}\n title={t`Access Denied`}\n body={t`You don't have permission to access this project.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n // Fallback for other error codes\n return <RouteError error={new Error(message)} />\n }\n\n const { availableServices, projectId, crumbProject, crumbDomain } = loaderData\n\n const sections = useMemo(\n () => buildNavSections(projectId, availableServices!, enabledServices, serviceExtensions),\n [projectId, availableServices, enabledServices, serviceExtensions]\n )\n\n return (\n <AppShell\n embedded\n sideNavigation={\n <SideNavBar\n sections={sections}\n projectId={projectId}\n projectName={crumbProject?.name || projectId}\n domainName={crumbDomain?.name}\n />\n }\n className=\"h-min-screen\"\n >\n <Container>\n <Stack direction=\"vertical\" distribution=\"start\" alignment=\"stretch\" className=\"xl:flex-row\" gap=\"6\">\n {/* Main content area */}\n <div className=\"min-w-0 flex-1\">\n <BreadcrumbExtensionProvider>\n <Breadcrumbs />\n <Outlet />\n </BreadcrumbExtensionProvider>\n </div>\n </Stack>\n </Container>\n </AppShell>\n )\n}\n\nfunction ProjectErrorComponent({ error }: { error: Error & { statusCode?: number } }) {\n const { t } = useLingui()\n const navigate = Route.useNavigate()\n\n // Handle 404 errors with a custom UI\n if (error.statusCode === 404 || error.message === \"Project not found\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={404}\n title={t`Project Not Found`}\n body={t`The project you are looking for doesn't exist or you don't have access to it.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n // For all other errors, use the default RouteError component\n return <RouteError error={error} safeErrorMessage={error instanceof TRPCClientError ? error.message : undefined} />\n}\n"],"mappings":";;;;;;AAiBA,SAAgBG,EAAW,EAAEC,UAAOC,UAAOC,aAAUC,uBAAmC;CACtF,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAWP,EAAAA,GAEXQ,IAAeC,EAAAA,EAAC,EAAA,IAAA,SAAuB,CAAA,GACvCC,IAAkBD,EAAAA,EAAC,EAAA,IAAA,SAAwI,CAAA,GAC3JE,IAAsBF,EAAAA,EAAC,EAAA,IAAA,SAA8B,CAAA,GAQrDG,IACJP,MACC,OAAOH,KAAU,WAAWA,IAAQ,UACpCA,KAAS,OAAOA,KAAU,YAAY,iBAAiBA,KAAS,OAAOA,EAAMW,eAAgB,WAC1FX,EAAMW,cACN,SACJF,GAEIG,IAAiBV,KAAYM;CAEnC,OACE,gBAACZ,GAAAA;EACCiB,QAAO;EACPZ,OAAOA,KAASK;EAChBQ,MAAMJ,IAAe,MAAME;EAC3BG,QACE,gBAAClB,GAAAA;GAAOmB,SAAQ;GAAUC,eAAeZ,EAAS,EAAEa,IAAI,IAAI,CAAA;GAC1D,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;AAKV;ACjCA,IAAaU,IAAQT,EAAgB,4BAAA,CAAA,CAA8B;CACjEU,WAASC,6CAAA,WAAA;CACTE,gBAAcF,6CAAA,gBAAA;CACdI,QAAQ,OAAOC,MAAAA;EACb,IAAM,EAAEC,YAASC,cAAWF,GAIxBG,GACAC;EAEJ,IAAI;GACFD,IAAY,MAAMF,EAAQI,YAAYC,KAAKC,gBAAgBC,OAAO;IAChErB,MAAM;IACNsB,WAAWP,EAAOO,aAAa;GACjC,CAAA;EACF,SAASC,GAAO;GACd,IAAIA,aAAiBzB,GAAiB;IAEpC,IAAIK;IACJ,IAAI;KACF,IAAMqB,IAAe,MAAMV,EAAQI,YAAYC,KAAKM,gBAAgBC,MAAAA;KACpE,AAAIF,GAAcG,QAAQvB,MAAMoB,GAAcG,QAAQtB,SACpDF,IAAgB;MAAEC,IAAIoB,EAAaG,OAAOvB;MAAIC,MAAMmB,EAAaG,OAAOtB;KAAK;IAEjF,QAAQ,CACN;IAIFY,IAAa;KACXjB,MAAM;KACNC,MAAMsB,EAAMK,MAAM3B,QAAQ;KAC1BC,SAASqB,EAAMrB;KACfC;IACF;GACF,OAEE,MAAMoB;EAEV;EAGA,IAAIN,GACF,OAAO;GACLA;GACAK,WAAWP,EAAOO;GAElBJ,YAAYJ,EAAQI;GACpBW,aAAaC,KAAAA;GACbC,cAAcD,KAAAA;GACdE,mBAAmBF,KAAAA;GACnBG,WAAW;GACXC,aAAa;EACf;EAGF,IAAM,CAACF,GAAmBG,KAAW,MAAMC,QAAQC,IAAI,CACrDvB,EAAQI,YAAYC,KAAKmB,qBAAqBZ,MAAAA,GAC9CZ,EAAQI,YAAYiB,QAAQI,WAAWb,MAAM,EAAEJ,WAAWP,EAAOO,UAAU,CAAA,CAAA,CAAGkB,YAAY,IAAA,CAC3F,CAAA,GAEKP,IAAYjB,GAAWW,QAAQvB,MAAM,IACrC8B,IAAcC,GAASD,eAAe;EAE5C,OAAO;GACLjB,YAAYa,KAAAA;GACZZ,YAAYJ,EAAQI;GACpBW,aAAa;IAAEY,MAAM;IAAapC,MAAMW,GAAWW,QAAQtB;GAAK;GAChE0B,cAAcf,GAAWmB;GACzBH;GACAC;GACAX,WAAWP,EAAOO;GAClBY;EACF;CACF;AACF,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as e, i as t, rt as n } from "./build-WuxXRAqf.mjs";
|
|
2
|
-
import { n as r, t as i } from "./_projectId-
|
|
2
|
+
import { n as r, t as i } from "./_projectId-BDARsteX.mjs";
|
|
3
3
|
import { jsx as a } from "react/jsx-runtime";
|
|
4
4
|
import { TRPCClientError as o } from "@trpc/client";
|
|
5
5
|
import { Trans as s, useLingui as c } from "@lingui/react";
|
|
@@ -27,4 +27,4 @@ function l({ error: l }) {
|
|
|
27
27
|
//#endregion
|
|
28
28
|
export { l as errorComponent };
|
|
29
29
|
|
|
30
|
-
//# sourceMappingURL=_projectId-
|
|
30
|
+
//# sourceMappingURL=_projectId-CtyAHqhH.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_projectId-CtyAHqhH.mjs","names":["Button","Container","Status","RouteError","TRPCClientError","useLingui","Trans","ScopeError","type","code","message","currentDomain","id","name","Route","ProjectErrorComponent","error","Error","statusCode","t","navigate","useNavigate","to","undefined","errorComponent"],"sources":["../../src/client/routes/_auth/projects/$projectId.tsx?tsr-split=errorComponent"],"sourcesContent":["import { createFileRoute, Outlet, useLoaderData, useRouteContext } from \"@tanstack/react-router\"\nimport { AppShell, Button, Container, Stack, Status } from \"@cloudoperators/juno-ui-components\"\nimport { SideNavBar } from \"@/client/routes/_auth/projects/-components/SideNavBar\"\nimport { buildNavSections } from \"@/client/routes/_auth/projects/-components/buildNavSections\"\nimport { Breadcrumbs } from \"@/client/components/Breadcrumbs\"\nimport { RouteError } from \"@/client/components/Errors/RouteError\"\nimport { useMemo } from \"react\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport { BreadcrumbExtensionProvider } from \"@/client/context/BreadcrumbExtensionContext\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\n\n// Type for scope error that we catch and handle gracefully\ntype ScopeError = {\n type: \"scope_error\"\n code: string\n message: string\n currentDomain?: { id: string; name: string } | null\n}\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId\")({\n component: RouteComponent,\n errorComponent: ProjectErrorComponent,\n loader: async (options) => {\n const { context, params } = options\n\n // Catch rescope errors and return them as data instead of throwing\n // This allows the component to render a friendly error UI\n let scopeData\n let scopeError: ScopeError | undefined\n\n try {\n scopeData = await context.trpcClient?.auth.setCurrentScope.mutate({\n type: \"project\",\n projectId: params.projectId || \"\",\n })\n } catch (error) {\n if (error instanceof TRPCClientError) {\n // Try to get the current session's domain to show in the error message\n let currentDomain: { id: string; name: string } | null | undefined\n try {\n const currentScope = await context.trpcClient?.auth.getCurrentScope.query()\n if (currentScope?.domain?.id && currentScope?.domain?.name) {\n currentDomain = { id: currentScope.domain.id, name: currentScope.domain.name }\n }\n } catch {\n // Ignore errors fetching current scope\n }\n\n // Return error as data so the component can handle it\n scopeError = {\n type: \"scope_error\",\n code: error.data?.code || \"UNKNOWN\",\n message: error.message,\n currentDomain,\n }\n } else {\n // Unknown errors should still propagate\n throw error\n }\n }\n\n // If scope failed, return early with error state\n if (scopeError) {\n return {\n scopeError,\n projectId: params.projectId,\n // Provide minimal data for error rendering\n trpcClient: context.trpcClient,\n crumbDomain: undefined,\n crumbProject: undefined,\n availableServices: undefined,\n accountId: \"\",\n description: null,\n }\n }\n\n const [availableServices, project] = await Promise.all([\n context.trpcClient?.auth.getAvailableServices.query(),\n context.trpcClient?.project.getProject.query({ projectId: params.projectId }).catch(() => null),\n ])\n\n const accountId = scopeData?.domain?.id || \"\"\n const description = project?.description ?? null\n\n return {\n scopeError: undefined,\n trpcClient: context.trpcClient,\n crumbDomain: { path: `/projects`, name: scopeData?.domain?.name },\n crumbProject: scopeData?.project,\n availableServices,\n accountId,\n projectId: params.projectId,\n description,\n }\n },\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const loaderData = useLoaderData({ from: Route.id })\n const navigate = Route.useNavigate()\n const { enabledServices, serviceExtensions } = useRouteContext({ strict: false })\n\n const projectName = loaderData.crumbProject?.name || loaderData.projectId\n const projectLabel = loaderData.crumbDomain?.name ? `${loaderData.crumbDomain.name}/${projectName}` : projectName\n useSetBreadcrumb(Route.id, projectLabel)\n\n // Handle scope errors with a friendly UI using Juno's Status component\n if (loaderData.scopeError) {\n const { code, message, currentDomain } = loaderData.scopeError\n const domainName = currentDomain?.name\n\n if (code === \"UNAUTHORIZED\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n title={t`Session Changed`}\n body={t`Your session was changed or ended in another browser tab. This can happen if you logged out or switched to a different account or domain elsewhere. Please log in again to continue.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/\" })}>\n <Trans>Sign in</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n if (code === \"NOT_FOUND\") {\n const bodyText = domainName\n ? t`This project doesn't exist or is not accessible from your current domain. Your current domain is ${domainName}. Please select a project from your current domain.`\n : t`This project doesn't exist or is not accessible from your current domain. Please select a project from your current domain.`\n\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={404}\n title={t`Project Not Accessible`}\n body={bodyText}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n if (code === \"FORBIDDEN\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={403}\n title={t`Access Denied`}\n body={t`You don't have permission to access this project.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n // Fallback for other error codes\n return <RouteError error={new Error(message)} />\n }\n\n const { availableServices, projectId, crumbProject, crumbDomain } = loaderData\n\n const sections = useMemo(\n () => buildNavSections(projectId, availableServices!, enabledServices, serviceExtensions),\n [projectId, availableServices, enabledServices, serviceExtensions]\n )\n\n return (\n <AppShell\n embedded\n sideNavigation={\n <SideNavBar\n sections={sections}\n projectId={projectId}\n projectName={crumbProject?.name || projectId}\n domainName={crumbDomain?.name}\n />\n }\n className=\"h-min-screen\"\n >\n <Container>\n <Stack direction=\"vertical\" distribution=\"start\" alignment=\"stretch\" className=\"xl:flex-row\" gap=\"6\">\n {/* Main content area */}\n <div className=\"min-w-0 flex-1\">\n <BreadcrumbExtensionProvider>\n <Breadcrumbs />\n <Outlet />\n </BreadcrumbExtensionProvider>\n </div>\n </Stack>\n </Container>\n </AppShell>\n )\n}\n\nfunction ProjectErrorComponent({ error }: { error: Error & { statusCode?: number } }) {\n const { t } = useLingui()\n const navigate = Route.useNavigate()\n\n // Handle 404 errors with a custom UI\n if (error.statusCode === 404 || error.message === \"Project not found\") {\n return (\n <Container className=\"py-8\">\n <Status\n status=\"error\"\n code={404}\n title={t`Project Not Found`}\n body={t`The project you are looking for doesn't exist or you don't have access to it.`}\n action={\n <Button variant=\"primary\" onClick={() => navigate({ to: \"/projects\" })}>\n <Trans>Go to Projects</Trans>\n </Button>\n }\n />\n </Container>\n )\n }\n\n // For all other errors, use the default RouteError component\n return <RouteError error={error} safeErrorMessage={error instanceof TRPCClientError ? error.message : undefined} />\n}\n"],"mappings":";;;;;;AAiNA,SAASe,EAAsB,EAAEC,YAAmD;CAClF,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQX,EAAAA,GACRe,IAAWN,EAAMO,YAAW;CAsBlC,OAnBIL,EAAME,eAAe,OAAOF,EAAMN,YAAY,sBAE9C,gBAAC,GAAA;EAAU,WAAU;EACnB,UAAA,gBAAC,GAAA;GACC,QAAO;GACP,MAAM;GACN,OAAOS,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;GACR,MAAMA,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;GACP,QACE,gBAAC,GAAA;IAAO,SAAQ;IAAU,eAAeC,EAAS,EAAEE,IAAI,YAAY,CAAA;IAClE,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;MASL,gBAAC,GAAA;EAAkBN;EAAO,kBAAkBA,aAAiBZ,IAAkBY,EAAMN,UAAUa,KAAAA;;AACxG"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Q as e, f as t } from "./build-WuxXRAqf.mjs";
|
|
2
|
+
import { t as n } from "./Slot-CWb612-_.mjs";
|
|
3
|
+
import { t as r } from "./helpers-1PpYf-fC.mjs";
|
|
4
|
+
import { t as i } from "./serviceCatalog-B3lKWC9V.mjs";
|
|
5
|
+
import { n as a, t as o } from "./storageProviders-CJ5rOh13.mjs";
|
|
6
|
+
import { t as s } from "./ContentHeader-fKKZVu-o.mjs";
|
|
7
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
|
+
import { useLoaderData as u, useNavigate as d, useRouteContext as f } from "@tanstack/react-router";
|
|
9
|
+
import { Trans as p, useLingui as m } from "@lingui/react";
|
|
10
|
+
//#region src/client/routes/_auth/projects/$projectId/index.tsx?tsr-split=component
|
|
11
|
+
function h({ group: e, label: r, to: i, service: a }) {
|
|
12
|
+
let o = d(), { slots: s } = f({ strict: !1 });
|
|
13
|
+
return /*#__PURE__*/ l(t, {
|
|
14
|
+
onClick: () => o({ to: i }),
|
|
15
|
+
className: "flex min-h-40 flex-col gap-4 px-3 pt-2 pb-3",
|
|
16
|
+
"data-testid": "service-card",
|
|
17
|
+
children: [/*#__PURE__*/ l("div", {
|
|
18
|
+
className: "flex min-w-0 flex-col",
|
|
19
|
+
children: [/*#__PURE__*/ c("p", {
|
|
20
|
+
className: "text-theme-light text-xs leading-5 font-medium",
|
|
21
|
+
children: e
|
|
22
|
+
}), /*#__PURE__*/ l("div", {
|
|
23
|
+
className: "flex items-center gap-2",
|
|
24
|
+
children: [/*#__PURE__*/ c("p", {
|
|
25
|
+
className: "text-theme-high text-lg leading-7 font-bold",
|
|
26
|
+
"data-testid": "service-card-label",
|
|
27
|
+
children: r
|
|
28
|
+
}), s?.serviceBadge && /*#__PURE__*/ c(n, {
|
|
29
|
+
component: s.serviceBadge,
|
|
30
|
+
useShadowDOM: !1,
|
|
31
|
+
currentService: a
|
|
32
|
+
})]
|
|
33
|
+
})]
|
|
34
|
+
}), /*#__PURE__*/ c("div", { className: "flex-1" })]
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function g() {
|
|
38
|
+
let { crumbProject: t, availableServices: n, projectId: d, description: g } = u({ from: "/_auth/projects/$projectId" }), { i18n: _, _: v } = m(), { enabledServices: y, serviceExtensions: b } = f({ strict: !1 }), x = (e) => !y || y.includes(e), S = r(n ?? []), C = `/projects/${d}`, w = [];
|
|
39
|
+
S.image?.glance && x("images") && w.push({
|
|
40
|
+
group: _._({ id: "rp0Bd0" }),
|
|
41
|
+
label: _._({ id: "an5hVd" }),
|
|
42
|
+
to: `${C}/compute/images`,
|
|
43
|
+
service: "images"
|
|
44
|
+
}), S.compute?.nova && x("flavors") && w.push({
|
|
45
|
+
group: _._({ id: "rp0Bd0" }),
|
|
46
|
+
label: _._({ id: "neiJm0" }),
|
|
47
|
+
to: `${C}/compute/flavors`,
|
|
48
|
+
service: "flavors"
|
|
49
|
+
}), S.network && (x("securitygroups") && w.push({
|
|
50
|
+
group: _._({ id: "OR475H" }),
|
|
51
|
+
label: _._({ id: "4opp4r" }),
|
|
52
|
+
to: `${C}/network/securitygroups`,
|
|
53
|
+
service: "securitygroups"
|
|
54
|
+
}), x("floatingips") && w.push({
|
|
55
|
+
group: _._({ id: "OR475H" }),
|
|
56
|
+
label: _._({ id: "u77/s4" }),
|
|
57
|
+
to: `${C}/network/floatingips`,
|
|
58
|
+
service: "floatingips"
|
|
59
|
+
})), i(S, o.SWIFT) && x("containers") && w.push({
|
|
60
|
+
group: _._({ id: "BrrIs8" }),
|
|
61
|
+
label: _._({ id: "+OEi73" }),
|
|
62
|
+
to: `${C}/storage/${o.SWIFT}/${a[o.SWIFT]}`,
|
|
63
|
+
service: "containers"
|
|
64
|
+
}), i(S, o.CEPH) && x("ceph-containers") && w.push({
|
|
65
|
+
group: _._({ id: "BrrIs8" }),
|
|
66
|
+
label: _._({ id: "KhNDX4" }),
|
|
67
|
+
to: `${C}/storage/${o.CEPH}/${a[o.CEPH]}`,
|
|
68
|
+
service: "ceph-containers"
|
|
69
|
+
});
|
|
70
|
+
for (let e of b ?? []) S[e.serviceType]?.[e.serviceName] && (!y || y.includes(e.serviceType)) && w.push({
|
|
71
|
+
group: _._({ id: "MILoeL" }),
|
|
72
|
+
label: e.label,
|
|
73
|
+
to: `/projects/${d}/services/${e.serviceType}`,
|
|
74
|
+
service: e.serviceType
|
|
75
|
+
});
|
|
76
|
+
return /*#__PURE__*/ l(e, {
|
|
77
|
+
direction: "vertical",
|
|
78
|
+
children: [/*#__PURE__*/ c(s, {
|
|
79
|
+
title: t?.name ?? _._({ id: "e0NrBM" }),
|
|
80
|
+
projectId: d,
|
|
81
|
+
description: g
|
|
82
|
+
}), w.length > 0 ? /*#__PURE__*/ c("div", {
|
|
83
|
+
className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4",
|
|
84
|
+
children: w.map((e) => /*#__PURE__*/ c(h, { ...e }, e.to))
|
|
85
|
+
}) : /*#__PURE__*/ c("p", {
|
|
86
|
+
className: "text-theme-light text-sm",
|
|
87
|
+
children: /*#__PURE__*/ c(p, { id: "Q1W//7" })
|
|
88
|
+
})]
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { g as component };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=_projectId-D3VOH5lN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_projectId-D3VOH5lN.mjs","names":["useLoaderData","useNavigate","Card","Stack","getServiceIndex","Trans","useLingui","useRouteContext","ContentHeader","Slot","hasServiceByName","STORAGE_PROVIDER","STORAGE_TYPE_BY_PROVIDER","ServiceCardProps","group","label","to","service","ServiceCard","navigate","slots","strict","serviceBadge","RouteComponent","crumbProject","availableServices","projectId","description","from","t","enabledServices","serviceExtensions","isEnabled","includes","serviceIndex","base","cards","push","SWIFT","CEPH","extension","serviceType","serviceName","name","length","map","card","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/index.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, useLoaderData, useNavigate } from \"@tanstack/react-router\"\nimport { Card, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { useRouteContext } from \"@tanstack/react-router\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { Slot } from \"@/client/components/Slot\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { hasServiceByName } from \"@/client/utils/serviceCatalog\"\nimport { STORAGE_PROVIDER, STORAGE_TYPE_BY_PROVIDER } from \"@/client/utils/storageProviders\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/\")({\n staticData: {\n analytics: {\n name: \"projects.detail\",\n },\n } satisfies RouteInfo,\n component: RouteComponent,\n})\n\ninterface ServiceCardProps {\n group: string\n label: string\n to: string\n service: string\n}\n\nfunction ServiceCard({ group, label, to, service }: ServiceCardProps) {\n const navigate = useNavigate()\n const { slots } = useRouteContext({ strict: false })\n\n return (\n <Card\n onClick={() => navigate({ to: to as never })}\n className=\"flex min-h-40 flex-col gap-4 px-3 pt-2 pb-3\"\n data-testid=\"service-card\"\n >\n <div className=\"flex min-w-0 flex-col\">\n <p className=\"text-theme-light text-xs leading-5 font-medium\">{group}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-theme-high text-lg leading-7 font-bold\" data-testid=\"service-card-label\">\n {label}\n </p>\n {slots?.serviceBadge && <Slot component={slots.serviceBadge} useShadowDOM={false} currentService={service} />}\n </div>\n </div>\n <div className=\"flex-1\" />\n </Card>\n )\n}\n\nfunction RouteComponent() {\n const { crumbProject, availableServices, projectId, description } = useLoaderData({\n from: \"/_auth/projects/$projectId\",\n })\n const { t } = useLingui()\n const { enabledServices, serviceExtensions } = useRouteContext({ strict: false })\n const isEnabled = (service: string) => !enabledServices || enabledServices.includes(service)\n\n const serviceIndex = getServiceIndex(availableServices ?? [])\n const base = `/projects/${projectId}`\n\n const cards: ServiceCardProps[] = []\n\n if (serviceIndex[\"image\"]?.[\"glance\"] && isEnabled(\"images\"))\n cards.push({ group: t`Compute`, label: t`Images`, to: `${base}/compute/images`, service: \"images\" })\n if (serviceIndex[\"compute\"]?.[\"nova\"] && isEnabled(\"flavors\"))\n cards.push({ group: t`Compute`, label: t`Flavors`, to: `${base}/compute/flavors`, service: \"flavors\" })\n if (serviceIndex[\"network\"]) {\n if (isEnabled(\"securitygroups\"))\n cards.push({\n group: t`Network`,\n label: t`Security Groups`,\n to: `${base}/network/securitygroups`,\n service: \"securitygroups\",\n })\n if (isEnabled(\"floatingips\"))\n cards.push({\n group: t`Network`,\n label: t`Floating IPs`,\n to: `${base}/network/floatingips`,\n service: \"floatingips\",\n })\n }\n if (hasServiceByName(serviceIndex, STORAGE_PROVIDER.SWIFT) && isEnabled(\"containers\"))\n cards.push({\n group: t`Storage`,\n label: t`Object Storage (Swift)`,\n to: `${base}/storage/${STORAGE_PROVIDER.SWIFT}/${STORAGE_TYPE_BY_PROVIDER[STORAGE_PROVIDER.SWIFT]}`,\n service: \"containers\",\n })\n if (hasServiceByName(serviceIndex, STORAGE_PROVIDER.CEPH) && isEnabled(\"ceph-containers\"))\n cards.push({\n group: t`Storage`,\n label: t`Object Storage (Ceph)`,\n to: `${base}/storage/${STORAGE_PROVIDER.CEPH}/${STORAGE_TYPE_BY_PROVIDER[STORAGE_PROVIDER.CEPH]}`,\n service: \"ceph-containers\",\n })\n\n for (const extension of serviceExtensions ?? []) {\n // if the extension's service is in the catalog and enabled, display a card for it\n if (\n serviceIndex[extension.serviceType]?.[extension.serviceName] &&\n (!enabledServices || enabledServices.includes(extension.serviceType))\n )\n cards.push({\n group: t`Services`,\n label: extension.label,\n to: `/projects/${projectId}/services/${extension.serviceType}`,\n service: extension.serviceType,\n })\n }\n\n return (\n <Stack direction=\"vertical\">\n <ContentHeader title={crumbProject?.name ?? t`Project`} projectId={projectId} description={description} />\n {cards.length > 0 ? (\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4\">\n {cards.map((card) => (\n <ServiceCard key={card.to} {...card} />\n ))}\n </div>\n ) : (\n <p className=\"text-theme-light text-sm\">\n <Trans>No services available for this project.</Trans>\n </p>\n )}\n </Stack>\n )\n}\n"],"mappings":";;;;;;;;;;AA4BA,SAASkB,EAAY,EAAEJ,UAAOC,UAAOC,OAAIC,cAA2B;CAClE,IAAME,IAAWlB,EAAAA,GACX,EAAEmB,aAAUb,EAAgB,EAAEc,QAAQ,GAAM,CAAA;CAElD,OACE,gBAAC,GAAA;EACC,eAAeF,EAAS,EAAMH,MAAY,CAAA;EAC1C,WAAU;EACV,eAAY;EAEZ,UAAA,CAAA,gBAAC,OAAA;GAAI,WAAU;GACb,UAAA,CAAA,gBAAC,KAAA;IAAE,WAAU;IAAkDF,UAAAA;GAC/D,CAAA,GAAA,gBAAC,OAAA;IAAI,WAAU;IACb,UAAA,CAAA,gBAAC,KAAA;KAAE,WAAU;KAA8C,eAAY;KACpEC,UAAAA;IAEFK,CAAAA,GAAAA,GAAOE,gBAAgB,gBAAC,GAAA;KAAK,WAAWF,EAAME;KAAc,cAAc;KAAO,gBAAgBL;;;EAGtG,CAAA,GAAA,gBAAC,OAAA,EAAI,WAAU,SAAA,CAAA,CAAA;;AAGrB;AAEA,SAASM,IAAAA;CACP,IAAM,EAAEC,iBAAcC,sBAAmBC,cAAWC,mBAAgB3B,EAAc,EAChF4B,MAAM,6BACR,CAAA,GACM,EAAA,MAAA,GAAA,GAAA,MAAQtB,EAAAA,GACR,EAAEwB,oBAAiBC,yBAAsBxB,EAAgB,EAAEc,QAAQ,GAAM,CAAA,GACzEW,KAAaf,MAAoB,CAACa,KAAmBA,EAAgBG,SAAShB,CAAAA,GAE9EiB,IAAe9B,EAAgBqB,KAAqB,CAAA,CAAE,GACtDU,IAAO,aAAaT,KAEpBU,IAA4B,CAAA;CA6BlC,AA3BIF,EAAa,OAAW,UAAaF,EAAU,QAAA,KACjDI,EAAMC,KAAK;EAAEvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EAAWd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EAAUb,IAAI,GAAGmB,EAAI;EAAmBlB,SAAS;CAAS,CAAA,GAChGiB,EAAa,SAAa,QAAWF,EAAU,SAAA,KACjDI,EAAMC,KAAK;EAAEvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EAAWd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EAAWb,IAAI,GAAGmB,EAAI;EAAoBlB,SAAS;CAAU,CAAA,GACnGiB,EAAa,YACXF,EAAU,gBAAA,KACZI,EAAMC,KAAK;EACTvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRb,IAAI,GAAGmB,EAAI;EACXlB,SAAS;CACX,CAAA,GACEe,EAAU,aAAA,KACZI,EAAMC,KAAK;EACTvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRb,IAAI,GAAGmB,EAAI;EACXlB,SAAS;CACX,CAAA,IAEAP,EAAiBwB,GAAcvB,EAAiB2B,KAAK,KAAKN,EAAU,YAAA,KACtEI,EAAMC,KAAK;EACTvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRb,IAAI,GAAGmB,EAAI,WAAYxB,EAAiB2B,MAAK,GAAI1B,EAAyBD,EAAiB2B;EAC3FrB,SAAS;CACX,CAAA,GACEP,EAAiBwB,GAAcvB,EAAiB4B,IAAI,KAAKP,EAAU,iBAAA,KACrEI,EAAMC,KAAK;EACTvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRd,OAAOc,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRb,IAAI,GAAGmB,EAAI,WAAYxB,EAAiB4B,KAAI,GAAI3B,EAAyBD,EAAiB4B;EAC1FtB,SAAS;CACX,CAAA;CAEF,KAAK,IAAMuB,KAAaT,KAAqB,CAAA,GAE3C,AACEG,EAAaM,EAAUC,YAAY,GAAGD,EAAUE,iBAC/C,CAACZ,KAAmBA,EAAgBG,SAASO,EAAUC,WAAW,MAEnEL,EAAMC,KAAK;EACTvB,OAAOe,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;EACRd,OAAOyB,EAAUzB;EACjBC,IAAI,aAAaU,EAAS,YAAac,EAAUC;EACjDxB,SAASuB,EAAUC;CACrB,CAAA;CAGJ,OACE,gBAAC,GAAA;EAAM,WAAU;EACf,UAAA,CAAA,gBAAC,GAAA;GAAc,OAAOjB,GAAcmB,QAAQd,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;GAAsBH;GAAwBC;EAC1FS,CAAAA,GAAAA,EAAMQ,SAAS,IACd,gBAAC,OAAA;GAAI,WAAU;GACZR,UAAAA,EAAMS,KAAKC,MACV,gBAAC,GAAA,EAA0B,GAAIA,EAAbA,GAAAA,EAAK9B,EAAE,CAAA;EAI7B,CAAA,IAAA,gBAAC,KAAA;GAAE,WAAU;GACX,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;AAKV"}
|
|
@@ -1,68 +1,70 @@
|
|
|
1
1
|
import { A as e, G as t, N as n, Q as r, Y as i, _ as a, b as o, i as s, rt as c, ut as l, w as u, z as d } from "./build-WuxXRAqf.mjs";
|
|
2
2
|
import { t as f } from "./Slot-CWb612-_.mjs";
|
|
3
|
-
import { n as p, t as m } from "./_projectId-
|
|
3
|
+
import { n as p, t as m } from "./_projectId-BDARsteX.mjs";
|
|
4
4
|
import { t as h } from "./helpers-1PpYf-fC.mjs";
|
|
5
|
-
import { t as g } from "./
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
5
|
+
import { t as g } from "./serviceCatalog-B3lKWC9V.mjs";
|
|
6
|
+
import { n as _, t as v } from "./storageProviders-CJ5rOh13.mjs";
|
|
7
|
+
import { t as y } from "./routeInfo-DP3v74Wg.mjs";
|
|
8
|
+
import { t as b } from "./useSetBreadcrumb-tn7lBaQV.mjs";
|
|
9
|
+
import { n as x, r as S, t as C } from "./useBreadcrumbs-ha3IlaxX.mjs";
|
|
10
|
+
import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
11
|
+
import { useContext as D, useEffect as O, useMemo as k, useState as A } from "react";
|
|
12
|
+
import { Outlet as j, useLoaderData as M, useMatches as N, useNavigate as P, useParams as F, useRouteContext as I } from "@tanstack/react-router";
|
|
13
|
+
import { Trans as L, useLingui as R } from "@lingui/react";
|
|
14
|
+
import { i18n as z } from "@lingui/core";
|
|
13
15
|
//#region src/client/routes/_auth/projects/-components/SideNavBar.tsx
|
|
14
|
-
var
|
|
15
|
-
let s =
|
|
16
|
+
var B = ({ projectId: e, projectName: t, domainName: r, sections: i }) => {
|
|
17
|
+
let s = P(), c = N(), { provider: d, serviceType: p } = F({ strict: !1 }), { slots: m } = I({ strict: !1 }), h = (e) => m?.serviceBadge ? /*#__PURE__*/ T(f, {
|
|
16
18
|
component: m.serviceBadge,
|
|
17
19
|
useShadowDOM: !1,
|
|
18
20
|
currentService: e
|
|
19
|
-
}) : null,
|
|
20
|
-
return
|
|
21
|
-
|
|
21
|
+
}) : null, g = [...c].reverse().find((e) => y(e.staticData) && (e.staticData.section !== void 0 || e.staticData.service !== void 0)), _ = g && y(g.staticData) ? g.staticData : void 0, v = _?.section ?? null, b = _?.service ?? p ?? null, [x, S] = A(() => Object.fromEntries(i.map((e) => [e.section, 0])));
|
|
22
|
+
return O(() => {
|
|
23
|
+
v && S((e) => ({
|
|
22
24
|
...e,
|
|
23
|
-
[
|
|
25
|
+
[v]: (e[v] || 0) + 1
|
|
24
26
|
}));
|
|
25
|
-
}, [
|
|
27
|
+
}, [v]), /*#__PURE__*/ T(u, {
|
|
26
28
|
ariaLabel: "Project Side Navigation",
|
|
27
|
-
children: /*#__PURE__*/
|
|
28
|
-
/*#__PURE__*/
|
|
29
|
+
children: /*#__PURE__*/ E(w, { children: [/*#__PURE__*/ T(o, { children: /*#__PURE__*/ E(w, { children: [
|
|
30
|
+
/*#__PURE__*/ T(n, {
|
|
29
31
|
onClick: () => s({
|
|
30
32
|
to: "/projects/$projectId",
|
|
31
33
|
params: { projectId: e }
|
|
32
34
|
}),
|
|
33
|
-
label: /*#__PURE__*/
|
|
35
|
+
label: /*#__PURE__*/ E(w, { children: [r && /*#__PURE__*/ E("p", {
|
|
34
36
|
className: "text-theme-light text-xs leading-4 font-bold",
|
|
35
37
|
children: [r, " /"]
|
|
36
|
-
}), /*#__PURE__*/
|
|
38
|
+
}), /*#__PURE__*/ T("p", {
|
|
37
39
|
className: "leading-5 font-normal",
|
|
38
40
|
children: t
|
|
39
41
|
})] })
|
|
40
42
|
}),
|
|
41
|
-
/*#__PURE__*/
|
|
42
|
-
i.map(({ section: e, label: t, services: r }) => /*#__PURE__*/
|
|
43
|
+
/*#__PURE__*/ T(a, { spacing: "1" }),
|
|
44
|
+
i.map(({ section: e, label: t, services: r }) => /*#__PURE__*/ T(l, {
|
|
43
45
|
label: t,
|
|
44
46
|
open: !0,
|
|
45
47
|
children: r.map((t) => {
|
|
46
|
-
let r =
|
|
47
|
-
return /*#__PURE__*/
|
|
48
|
+
let r = v === e && (v === "storage" && b === "containers" ? t.params.provider === d : b === t.service);
|
|
49
|
+
return /*#__PURE__*/ T(n, {
|
|
48
50
|
onClick: () => t.navigate(s),
|
|
49
|
-
label: /*#__PURE__*/
|
|
51
|
+
label: /*#__PURE__*/ E("span", {
|
|
50
52
|
className: "flex items-start gap-2",
|
|
51
53
|
children: [t.label, h(t.service)]
|
|
52
54
|
}),
|
|
53
55
|
selected: r
|
|
54
56
|
}, t.service);
|
|
55
57
|
})
|
|
56
|
-
}, `${e}-${
|
|
57
|
-
] }) }), m?.sideNavBanner && /*#__PURE__*/
|
|
58
|
+
}, `${e}-${x[e]}`))
|
|
59
|
+
] }) }), m?.sideNavBanner && /*#__PURE__*/ T(f, { component: m.sideNavBanner })] })
|
|
58
60
|
});
|
|
59
61
|
};
|
|
60
62
|
//#endregion
|
|
61
63
|
//#region src/client/routes/_auth/projects/-components/buildNavSections.ts
|
|
62
|
-
function
|
|
64
|
+
function V(e, t, n, r) {
|
|
63
65
|
let i = h(t), a = (e) => !n || n.includes(e), o = [...i.image?.glance && a("images") ? [{
|
|
64
66
|
service: "images",
|
|
65
|
-
label:
|
|
67
|
+
label: z._({ id: "an5hVd" }),
|
|
66
68
|
navigate: (t) => t({
|
|
67
69
|
to: "/projects/$projectId/compute/images",
|
|
68
70
|
params: { projectId: e }
|
|
@@ -70,7 +72,7 @@ function R(e, t, n, r) {
|
|
|
70
72
|
params: { projectId: e }
|
|
71
73
|
}] : [], ...i?.compute?.nova && a("flavors") ? [{
|
|
72
74
|
service: "flavors",
|
|
73
|
-
label:
|
|
75
|
+
label: z._({ id: "neiJm0" }),
|
|
74
76
|
navigate: (t) => t({
|
|
75
77
|
to: "/projects/$projectId/compute/flavors",
|
|
76
78
|
params: { projectId: e }
|
|
@@ -78,7 +80,7 @@ function R(e, t, n, r) {
|
|
|
78
80
|
params: { projectId: e }
|
|
79
81
|
}] : []], s = i.network ? [...a("securitygroups") ? [{
|
|
80
82
|
service: "securitygroups",
|
|
81
|
-
label:
|
|
83
|
+
label: z._({ id: "4opp4r" }),
|
|
82
84
|
navigate: (t) => t({
|
|
83
85
|
to: "/projects/$projectId/network/securitygroups",
|
|
84
86
|
params: { projectId: e }
|
|
@@ -86,63 +88,63 @@ function R(e, t, n, r) {
|
|
|
86
88
|
params: { projectId: e }
|
|
87
89
|
}] : [], ...a("floatingips") ? [{
|
|
88
90
|
service: "floatingips",
|
|
89
|
-
label:
|
|
91
|
+
label: z._({ id: "u77/s4" }),
|
|
90
92
|
navigate: (t) => t({
|
|
91
93
|
to: "/projects/$projectId/network/floatingips",
|
|
92
94
|
params: { projectId: e }
|
|
93
95
|
}),
|
|
94
96
|
params: { projectId: e }
|
|
95
|
-
}] : []] : [], c = [...i
|
|
97
|
+
}] : []] : [], c = [...g(i, v.SWIFT) && a("containers") ? [{
|
|
96
98
|
service: "containers",
|
|
97
|
-
label:
|
|
99
|
+
label: z._({ id: "+OEi73" }),
|
|
98
100
|
navigate: (t) => t({
|
|
99
101
|
to: "/projects/$projectId/storage/$provider/$storageType",
|
|
100
102
|
params: {
|
|
101
103
|
projectId: e,
|
|
102
|
-
provider:
|
|
103
|
-
storageType:
|
|
104
|
+
provider: v.SWIFT,
|
|
105
|
+
storageType: _[v.SWIFT]
|
|
104
106
|
}
|
|
105
107
|
}),
|
|
106
108
|
params: {
|
|
107
109
|
projectId: e,
|
|
108
|
-
provider:
|
|
109
|
-
storageType:
|
|
110
|
+
provider: v.SWIFT,
|
|
111
|
+
storageType: _[v.SWIFT]
|
|
110
112
|
}
|
|
111
|
-
}] : [], ...i
|
|
113
|
+
}] : [], ...g(i, v.CEPH) && a("ceph-containers") ? [{
|
|
112
114
|
service: "ceph-containers",
|
|
113
|
-
label:
|
|
115
|
+
label: z._({ id: "KhNDX4" }),
|
|
114
116
|
navigate: (t) => t({
|
|
115
117
|
to: "/projects/$projectId/storage/$provider/$storageType",
|
|
116
118
|
params: {
|
|
117
119
|
projectId: e,
|
|
118
|
-
provider:
|
|
119
|
-
storageType:
|
|
120
|
+
provider: v.CEPH,
|
|
121
|
+
storageType: _[v.CEPH]
|
|
120
122
|
}
|
|
121
123
|
}),
|
|
122
124
|
params: {
|
|
123
125
|
projectId: e,
|
|
124
|
-
provider:
|
|
125
|
-
storageType:
|
|
126
|
+
provider: v.CEPH,
|
|
127
|
+
storageType: _[v.CEPH]
|
|
126
128
|
}
|
|
127
129
|
}] : []], l = /* @__PURE__ */ new Map([
|
|
128
130
|
["compute", {
|
|
129
131
|
section: "compute",
|
|
130
|
-
label:
|
|
132
|
+
label: z._({ id: "rp0Bd0" }),
|
|
131
133
|
services: o
|
|
132
134
|
}],
|
|
133
135
|
["network", {
|
|
134
136
|
section: "network",
|
|
135
|
-
label:
|
|
137
|
+
label: z._({ id: "OR475H" }),
|
|
136
138
|
services: s
|
|
137
139
|
}],
|
|
138
140
|
["storage", {
|
|
139
141
|
section: "storage",
|
|
140
|
-
label:
|
|
142
|
+
label: z._({ id: "BrrIs8" }),
|
|
141
143
|
services: c
|
|
142
144
|
}],
|
|
143
145
|
["services", {
|
|
144
146
|
section: "services",
|
|
145
|
-
label:
|
|
147
|
+
label: z._({ id: "MILoeL" }),
|
|
146
148
|
services: []
|
|
147
149
|
}]
|
|
148
150
|
]);
|
|
@@ -165,8 +167,8 @@ function R(e, t, n, r) {
|
|
|
165
167
|
}
|
|
166
168
|
//#endregion
|
|
167
169
|
//#region src/client/components/Breadcrumbs.tsx
|
|
168
|
-
function
|
|
169
|
-
let e =
|
|
170
|
+
function H() {
|
|
171
|
+
let e = P(), { projectId: t } = F({ strict: !1 }), { breadcrumbs: n } = D(x), r = C(), a = k(() => n.length === 0 || r.length === 0 ? r : [
|
|
170
172
|
...r.slice(0, -1),
|
|
171
173
|
{
|
|
172
174
|
...r[r.length - 1],
|
|
@@ -183,9 +185,9 @@ function z() {
|
|
|
183
185
|
t,
|
|
184
186
|
e
|
|
185
187
|
]);
|
|
186
|
-
return /*#__PURE__*/
|
|
188
|
+
return /*#__PURE__*/ T(i, {
|
|
187
189
|
className: "relative z-1 mt-8 mb-4",
|
|
188
|
-
children: a.map((e, t) => /*#__PURE__*/
|
|
190
|
+
children: a.map((e, t) => /*#__PURE__*/ T(d, {
|
|
189
191
|
label: e.label,
|
|
190
192
|
icon: e.icon,
|
|
191
193
|
onClick: e.onClick,
|
|
@@ -195,20 +197,20 @@ function z() {
|
|
|
195
197
|
}
|
|
196
198
|
//#endregion
|
|
197
199
|
//#region src/client/routes/_auth/projects/$projectId.tsx?tsr-split=component
|
|
198
|
-
function
|
|
199
|
-
let { i18n: n, _: i } =
|
|
200
|
-
if (
|
|
200
|
+
function U() {
|
|
201
|
+
let { i18n: n, _: i } = R(), a = M({ from: m.id }), o = m.useNavigate(), { enabledServices: l, serviceExtensions: u } = I({ strict: !1 }), d = a.crumbProject?.name || a.projectId, f = a.crumbDomain?.name ? `${a.crumbDomain.name}/${d}` : d;
|
|
202
|
+
if (b(m.id, f), a.scopeError) {
|
|
201
203
|
let { code: t, message: r, currentDomain: i } = a.scopeError, l = i?.name;
|
|
202
|
-
if (t === "UNAUTHORIZED") return /*#__PURE__*/
|
|
204
|
+
if (t === "UNAUTHORIZED") return /*#__PURE__*/ T(e, {
|
|
203
205
|
className: "py-8",
|
|
204
|
-
children: /*#__PURE__*/
|
|
206
|
+
children: /*#__PURE__*/ T(c, {
|
|
205
207
|
status: "error",
|
|
206
|
-
title: n._({ id: "
|
|
207
|
-
body: n._({ id: "
|
|
208
|
-
action: /*#__PURE__*/
|
|
208
|
+
title: n._({ id: "odyhRS" }),
|
|
209
|
+
body: n._({ id: "EpLAGw" }),
|
|
210
|
+
action: /*#__PURE__*/ T(s, {
|
|
209
211
|
variant: "primary",
|
|
210
212
|
onClick: () => o({ to: "/" }),
|
|
211
|
-
children: /*#__PURE__*/
|
|
213
|
+
children: /*#__PURE__*/ T(L, { id: "5lWFkC" })
|
|
212
214
|
})
|
|
213
215
|
})
|
|
214
216
|
});
|
|
@@ -217,65 +219,65 @@ function B() {
|
|
|
217
219
|
id: "+A0ERd",
|
|
218
220
|
values: { domainName: l }
|
|
219
221
|
}) : n._({ id: "5rPh4Y" });
|
|
220
|
-
return /*#__PURE__*/
|
|
222
|
+
return /*#__PURE__*/ T(e, {
|
|
221
223
|
className: "py-8",
|
|
222
|
-
children: /*#__PURE__*/
|
|
224
|
+
children: /*#__PURE__*/ T(c, {
|
|
223
225
|
status: "error",
|
|
224
226
|
code: 404,
|
|
225
227
|
title: n._({ id: "SK7RzY" }),
|
|
226
228
|
body: t,
|
|
227
|
-
action: /*#__PURE__*/
|
|
229
|
+
action: /*#__PURE__*/ T(s, {
|
|
228
230
|
variant: "primary",
|
|
229
231
|
onClick: () => o({ to: "/projects" }),
|
|
230
|
-
children: /*#__PURE__*/
|
|
232
|
+
children: /*#__PURE__*/ T(L, { id: "aKznJS" })
|
|
231
233
|
})
|
|
232
234
|
})
|
|
233
235
|
});
|
|
234
236
|
}
|
|
235
|
-
return t === "FORBIDDEN" ? /*#__PURE__*/
|
|
237
|
+
return t === "FORBIDDEN" ? /*#__PURE__*/ T(e, {
|
|
236
238
|
className: "py-8",
|
|
237
|
-
children: /*#__PURE__*/
|
|
239
|
+
children: /*#__PURE__*/ T(c, {
|
|
238
240
|
status: "error",
|
|
239
241
|
code: 403,
|
|
240
242
|
title: n._({ id: "VTfZPy" }),
|
|
241
243
|
body: n._({ id: "hXKwm5" }),
|
|
242
|
-
action: /*#__PURE__*/
|
|
244
|
+
action: /*#__PURE__*/ T(s, {
|
|
243
245
|
variant: "primary",
|
|
244
246
|
onClick: () => o({ to: "/projects" }),
|
|
245
|
-
children: /*#__PURE__*/
|
|
247
|
+
children: /*#__PURE__*/ T(L, { id: "aKznJS" })
|
|
246
248
|
})
|
|
247
249
|
})
|
|
248
|
-
}) : /*#__PURE__*/
|
|
250
|
+
}) : /*#__PURE__*/ T(p, { error: Error(r) });
|
|
249
251
|
}
|
|
250
|
-
let { availableServices: h, projectId: g, crumbProject:
|
|
252
|
+
let { availableServices: h, projectId: g, crumbProject: _, crumbDomain: v } = a, y = k(() => V(g, h, l, u), [
|
|
251
253
|
g,
|
|
252
254
|
h,
|
|
253
255
|
l,
|
|
254
256
|
u
|
|
255
257
|
]);
|
|
256
|
-
return /*#__PURE__*/
|
|
258
|
+
return /*#__PURE__*/ T(t, {
|
|
257
259
|
embedded: !0,
|
|
258
|
-
sideNavigation: /*#__PURE__*/
|
|
259
|
-
sections:
|
|
260
|
+
sideNavigation: /*#__PURE__*/ T(B, {
|
|
261
|
+
sections: y,
|
|
260
262
|
projectId: g,
|
|
261
|
-
projectName:
|
|
262
|
-
domainName:
|
|
263
|
+
projectName: _?.name || g,
|
|
264
|
+
domainName: v?.name
|
|
263
265
|
}),
|
|
264
266
|
className: "h-min-screen",
|
|
265
|
-
children: /*#__PURE__*/
|
|
267
|
+
children: /*#__PURE__*/ T(e, { children: /*#__PURE__*/ T(r, {
|
|
266
268
|
direction: "vertical",
|
|
267
269
|
distribution: "start",
|
|
268
270
|
alignment: "stretch",
|
|
269
271
|
className: "xl:flex-row",
|
|
270
272
|
gap: "6",
|
|
271
|
-
children: /*#__PURE__*/
|
|
273
|
+
children: /*#__PURE__*/ T("div", {
|
|
272
274
|
className: "min-w-0 flex-1",
|
|
273
|
-
children: /*#__PURE__*/
|
|
275
|
+
children: /*#__PURE__*/ E(S, { children: [/*#__PURE__*/ T(H, {}), /*#__PURE__*/ T(j, {})] })
|
|
274
276
|
})
|
|
275
277
|
}) })
|
|
276
278
|
});
|
|
277
279
|
}
|
|
278
280
|
//#endregion
|
|
279
|
-
export {
|
|
281
|
+
export { U as component };
|
|
280
282
|
|
|
281
|
-
//# sourceMappingURL=_projectId-
|
|
283
|
+
//# sourceMappingURL=_projectId-ZBk6vka0.mjs.map
|