diff --git a/docs/contributor/09-10-ui.md b/docs/contributor/09-10-ui.md index 40f8828dc..8c9c44a1c 100644 --- a/docs/contributor/09-10-ui.md +++ b/docs/contributor/09-10-ui.md @@ -30,7 +30,7 @@ Follow the steps below to run BTP Manager with UI: ``` 3. Set the **IMG** environment variable to the image of BTP Manager with UI. ```shell - export IMG=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-844 + export IMG=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-850 ``` 4. Run `deploy` makefile rule to deploy BTP Manager with UI. ```shell @@ -42,7 +42,7 @@ Follow the steps below to run BTP Manager with UI: ``` If you encounter the following error during Pod creation due to Warden's admission webhook: ``` - Error creating: admission webhook "validation.webhook.warden.kyma-project.io" denied the request: Pod images europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-844 validation failed + Error creating: admission webhook "validation.webhook.warden.kyma-project.io" denied the request: Pod images europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-850 validation failed ``` you must scale the BTP Manager deployment to 0 replicas, delete the webhook, and then scale the deployment back to 1 replica. ```shell diff --git a/ui/src/components/CreateBindingForm.tsx b/ui/src/components/CreateBindingForm.tsx index fc1a41b00..76d464b39 100644 --- a/ui/src/components/CreateBindingForm.tsx +++ b/ui/src/components/CreateBindingForm.tsx @@ -18,6 +18,7 @@ function CreateBindingForm(props: any) { const [success, setSuccess] = useState(""); const handleCreate = (e: any): boolean => { + setLoading(true) e.preventDefault(); e.stopPropagation(); @@ -28,7 +29,6 @@ function CreateBindingForm(props: any) { createdBinding.service_instance_id = props.instanceId ?? "" - setLoading(true) axios .post(api("service-bindings"), { name: createdBinding.name, @@ -70,6 +70,7 @@ function CreateBindingForm(props: any) { } useEffect(() => { + setLoading(true) if (!Ok(props.instanceId)) { return; } @@ -82,7 +83,6 @@ function CreateBindingForm(props: any) { return; } - setLoading(true) setLoading(false) setError(undefined) diff --git a/ui/src/components/ServiceBindingsList.tsx b/ui/src/components/ServiceBindingsList.tsx index 20b495ed5..d06b5e50e 100644 --- a/ui/src/components/ServiceBindingsList.tsx +++ b/ui/src/components/ServiceBindingsList.tsx @@ -95,7 +95,6 @@ const ServiceBindingsList = forwardRef((props: any, ref) => { setError(error); setLoading(false); }); - setLoading(false) } else { setServiceInstanceBindings(serviceInstancesData) setLoading(false); diff --git a/ui/src/components/ServiceInstancesDetailsView.tsx b/ui/src/components/ServiceInstancesDetailsView.tsx index fd07fa602..b87a0703c 100644 --- a/ui/src/components/ServiceInstancesDetailsView.tsx +++ b/ui/src/components/ServiceInstancesDetailsView.tsx @@ -5,7 +5,7 @@ import { ServiceInstance, ServiceInstanceBinding, } from "../shared/models"; -import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"; +import { forwardRef, useEffect, useRef, useState } from "react"; import ServiceBindingsList from "./ServiceBindingsList"; import '@ui5/webcomponents/dist/features/InputElementsFormSupport.js'; import CreateBindingForm from "./CreateBindingForm"; @@ -16,27 +16,8 @@ const ServiceInstancesDetailsView = forwardRef((props: any, ref) => { const [error] = useState(); const [instance, setInstance] = useState(); - const dialogRef = useRef(null); const listRef = useRef(null); - useImperativeHandle(ref, () => ({ - - open() { - if (dialogRef.current) { - // @ts-ignore - dialogRef.current.show(); - } - } - - })); - - const handleClose = () => { - if (dialogRef.current) { - // @ts-ignore - dialogRef.current.close(); - setInstance(undefined); - } - }; const onBindingAdded = (binding: ServiceInstanceBinding) => { // @ts-ignore @@ -44,6 +25,7 @@ const ServiceInstancesDetailsView = forwardRef((props: any, ref) => { } useEffect(() => { + setLoading(true); if (!Ok(props.instance)) { return; } @@ -74,33 +56,7 @@ const ServiceInstancesDetailsView = forwardRef((props: any, ref) => { } return ( - - - Create {instance?.name} Service Instance - - - } - /> - } - footer={ - - Close - - } - /> - } - > + <> @@ -116,8 +72,8 @@ const ServiceInstancesDetailsView = forwardRef((props: any, ref) => { onBindingAdded(binding)} instanceId={props.instance.id} instanceName={props.instance.name} /> + - ) } // @ts-ignore diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index fa1df033f..dc4f0064e 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -1,8 +1,7 @@ import * as ui5 from "@ui5/webcomponents-react"; import { Secret, ServiceInstance, ServiceInstances } from "../shared/models"; import axios from "axios"; -import { useEffect, useRef, useState } from "react"; -import { createPortal } from "react-dom"; +import { useEffect, useState } from "react"; import api from "../shared/api"; import Ok from "../shared/validator"; import serviceInstancesData from '../test-data/serivce-instances.json'; @@ -10,6 +9,7 @@ import ServiceInstancesDetailsView from "./ServiceInstancesDetailsView"; import { useParams } from "react-router-dom"; import StatusMessage from "./StatusMessage"; import { splitSecret } from "../shared/common"; +import { FCLLayout, FlexibleColumnLayout } from "@ui5/webcomponents-react"; function ServiceInstancesView(props: any) { const [serviceInstances, setServiceInstances] = useState(); @@ -17,8 +17,8 @@ function ServiceInstancesView(props: any) { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedInstance, setSelectedInstance] = useState(new ServiceInstance()); - const dialogRef = useRef(); const [success, setSuccess] = useState(""); + const [layout, setLayout] = useState(FCLLayout.OneColumn); let { id } = useParams(); @@ -28,6 +28,9 @@ function ServiceInstancesView(props: any) { // disable selection when page refresh is done setSelectedInstance(new ServiceInstance()); + // close side panel + setLayout(FCLLayout.OneColumn) + if (!Ok(props.setTitle)) { return; } @@ -55,7 +58,8 @@ function ServiceInstancesView(props: any) { if (id) { const instance = response.data.items.find((instance) => instance.id === id); if (instance) { - openPortal(instance); + setSelectedInstance(instance) + setLayout(FCLLayout.TwoColumnsMidExpanded) } } setLoading(false); @@ -65,7 +69,7 @@ function ServiceInstancesView(props: any) { setLoading(false); setError(error); }); - } + } } else { setLoading(true) setServiceInstances(serviceInstancesData) @@ -73,7 +77,6 @@ function ServiceInstancesView(props: any) { } }, [id, props, props.secret]); - if (loading) { return } - function openPortal(instance: any) { - setSelectedInstance(instance) - //@ts-ignore - dialogRef.current.open() - } - function deleteInstance(id: string): boolean { setLoading(true); axios @@ -112,13 +109,13 @@ function ServiceInstancesView(props: any) { return true; } - const renderData = () => { - + const renderTableData = () => { + // @ts-ignore if (!Ok(serviceInstances) || !Ok(serviceInstances.items)) { return } - + return serviceInstances?.items.map((instance, index) => { @@ -127,7 +124,8 @@ function ServiceInstancesView(props: any) { { - openPortal(instance) + setSelectedInstance(instance) + setLayout(FCLLayout.TwoColumnsMidExpanded) }} > @@ -162,39 +160,86 @@ function ServiceInstancesView(props: any) { }); }; - return ( - <> - - + const renderData = () => { + if (loading) { + return + } - + if (error) { + return <> +
+ + +
+ + } + return ( + <> + + +
+ + + + + + + Service Instance + + + + Service Namespace + + + + Action + + + } + > + {renderTableData()} + + + +
+ + +
+ +
+ { + if (layout === FCLLayout.MidColumnFullScreen) { + setLayout(FCLLayout.TwoColumnsMidExpanded) + } else { + setLayout(FCLLayout.MidColumnFullScreen) + } + }}> + { + setLayout(FCLLayout.OneColumn) + }}> +
+
+ +
+ +
+ + + ); - - - Service Instance - + }; - - Service Namespace - + return <>{renderData()}; - - Action - - - } - > - {renderData()} - -
- {createPortal(, document.getElementById("App")!!)} - - ); } diff --git a/ui/src/components/ServiceOfferingsDetailsView.tsx b/ui/src/components/ServiceOfferingsDetailsView.tsx index 1ba52a102..a9f8c8186 100644 --- a/ui/src/components/ServiceOfferingsDetailsView.tsx +++ b/ui/src/components/ServiceOfferingsDetailsView.tsx @@ -6,7 +6,7 @@ import { ServiceOfferingDetails, ServiceOfferingPlan, } from "../shared/models"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import axios from "axios"; import api from "../shared/api"; import CreateInstanceForm from "./CreateInstanceForm"; @@ -18,12 +18,6 @@ function ServiceOfferingsDetailsView(props: any) { const [error, setError] = useState(null); const [offering, setOffering] = useState(); const [details, setDetails] = useState(); - const dialogRef = useRef(null); - - const handleClose = () => { - // @ts-ignore - dialogRef.current.close(); - }; const onChangeSelect = (e: any) => { // @ts-ignore @@ -35,6 +29,7 @@ function ServiceOfferingsDetailsView(props: any) { }; useEffect(() => { + setLoading(true); if (!Ok(props.offering)) { return; } @@ -44,7 +39,6 @@ function ServiceOfferingsDetailsView(props: any) { } setSecret(props.secret); - setLoading(true); axios .get(api(`service-offerings/${props.offering.id}`), { @@ -59,16 +53,13 @@ function ServiceOfferingsDetailsView(props: any) { setDetails(response.data); setPlan(response.data?.plans[0]) setOffering(props.offering); - // @ts-ignore - dialogRef.current.show(); + setError(null) }) .catch((error) => { setLoading(false); setError(error); }); - setLoading(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [props.offering, props.secret]); const renderData = () => { if (loading) { @@ -84,34 +75,8 @@ function ServiceOfferingsDetailsView(props: any) { } return ( - <> - - - Create {offering?.metadata.displayName} Service Instance - - - } - /> - } - footer={ - - Close - - } - /> - } - > - +
+ {offering?.metadata.displayName} @@ -172,10 +137,9 @@ function ServiceOfferingsDetailsView(props: any) { - - +
)} - // @ts-ignore + return <>{renderData()}; } diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 748a450df..4bb420f80 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -1,25 +1,26 @@ import * as ui5 from "@ui5/webcomponents-react"; import { useEffect, useState } from "react"; import axios from "axios"; -import { Secret, ServiceOfferings } from "../shared/models"; +import { Secret, ServiceOffering, ServiceOfferings } from "../shared/models"; import api from "../shared/api"; import "@ui5/webcomponents-icons/dist/AllIcons.js" import "@ui5/webcomponents-fiori/dist/illustrations/NoEntries.js" import "@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js" import "@ui5/webcomponents-fiori/dist/illustrations/NoData.js"; import Ok from "../shared/validator"; -import { createPortal } from "react-dom"; import ServiceOfferingsDetailsView from "./ServiceOfferingsDetailsView"; -import { ResponsiveGridLayout } from "@ui5/webcomponents-react"; +import { FCLLayout, FlexibleColumnLayout, ResponsiveGridLayout } from "@ui5/webcomponents-react"; import { splitSecret } from "../shared/common"; +import StatusMessage from "./StatusMessage"; function ServiceOfferingsView(props: any) { const greyImg = "data:image/svg+xml;base64,PHN2ZyBpZD0icGxhY2Vob2xkZXIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDU2IDU2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6IzVhN2E5NDt9LmNscy0ye2ZpbGw6IzA0OTFkMDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPnBsYWNlaG9sZGVyPC90aXRsZT48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik00Ni45NTMsMjAuNTg4YTQuMzYzLDQuMzYzLDAsMCwwLTEuODM3LS40NTksMy4yOTEsMy4yOTEsMCwwLDAtMy40LDMuMzc2LDQuMDg0LDQuMDg0LDAsMCwwLC45LDIuNjI1LDMuMDExLDMuMDExLDAsMCwwLDIuNSwxLjEyNiwzLjA4NSwzLjA4NSwwLDAsMCwxLjQ2Mi0uMzc1LDcuNTEyLDcuNTEyLDAsMCwwLDEuMzItLjg5MSwxMC4xMzUsMTAuMTM1LDAsMCwxLDEuMjI2LS44OTEsMi4yNywyLjI3LDAsMCwxLDEuMTc5LS4zNzVBMS41LDEuNSwwLDAsMSw1MiwyNi40MTJWMzkuMDcxYTIuODQzLDIuODQzLDAsMCwxLS41NzYsMiwyLjkyNiwyLjkyNiwwLDAsMS0yLjE1OS42MjZxLTIuOTIzLDAtNC4zODUuMDQ3dC0yLjEyMi4wNDdINDEuOTFhMy4zMjEsMy4zMjEsMCwwLDAsLjYuNjQ0LDUuNzE3LDUuNzE3LDAsMCwxLDIuMDc0LDQuMjIsNS4wNTQsNS4wNTQsMCwwLDEtMS42NSwzLjc1MUE1LjMzMSw1LjMzMSwwLDAsMSwzOS4xMTgsNTJhNS42LDUuNiwwLDAsMS00LjA1NS0xLjU0Nyw1LjA3MSw1LjA3MSwwLDAsMS0xLjYtMy44LDQuODYyLDQuODYyLDAsMCwxLC41MTktMi4zLDExLjQwNywxMS40MDcsMCwwLDEsMS41MTYtMS45NywyLjMzMywyLjMzMywwLDAsMCwuNDc1LS42OUgyOC4zM2ExLjM5NCwxLjM5NCwwLDAsMS0xLjA4NC0uNDY5LDIuMDExLDIuMDExLDAsMCwxLS41MTktMS4wMzJWMTUuOTA5YTEuOCwxLjgsMCwwLDEsLjQyNC0xLjE3MiwxLjQ0NCwxLjQ0NCwwLDAsMSwxLjE3OS0uNTE2aDcuNzMzYTEuOTQ5LDEuOTQ5LDAsMCwwLS4zNzctLjU2MmwtLjgtMS4xNzFhOC43ODgsOC43ODgsMCwwLDEtLjg0Ny0xLjUsNC43ODMsNC43ODMsMCwwLDEtLjQwNi0xLjY3NkE1LjM0OCw1LjM0OCwwLDAsMSwzOS4wODEsNGE1LjU1Miw1LjU1MiwwLDAsMSwzLjc5LDEuNTUzQTQuNjM1LDQuNjM1LDAsMCwxLDQ0LjU1LDkuMzQ1Yy0uMDI4LDEuNjg4LTIuMDIzLDQuMTI1LTIuMjQxLDQuMzc1YTEuNTc2LDEuNTc2LDAsMCwwLS4zLjVoNy4yNjFBMi42NSwyLjY1LDAsMCwxLDUyLDE2Ljg0N3Y0LjEyNnEwLDEuNzgyLTEuNywxLjc4MmExLjc0MywxLjc0MywwLDAsMS0xLjMxOS0uNTQ5QTEzLjE1MiwxMy4xNTIsMCwwLDAsNDYuOTUzLDIwLjU4OFpNMjguMzMsMzkuMDcxYS41ODIuNTgyLDAsMCwwLC42Ni42NTdoNy4xNjdhMS41NzksMS41NzksMCwwLDEsMS43OTIsMS43ODEsMi4yMzgsMi4yMzgsMCwwLDEtLjM4NywxLjI1NGMtLjI4My40MDgtLjU4Mi44MTMtLjksMS4yMTlzLS42MTMuODMtLjksMS4yNjZhMi41NDYsMi41NDYsMCwwLDAtLjQyNCwxLjQwNywzLjExNSwzLjExNSwwLDAsMCwxLjEzMSwyLjUzMiw0LjAyMiw0LjAyMiwwLDAsMCwyLjY0MS45MzgsMy43NzYsMy43NzYsMCwwLDAsMi40NTItLjkzOEEzLjExNSwzLjExNSwwLDAsMCw0Mi43LDQ2LjY1NWEyLjU0NiwyLjU0NiwwLDAsMC0uNDI0LTEuNDA3LDEyLjUxMywxMi41MTMsMCwwLDAtLjk0My0xLjI2NnEtLjUxOS0uNjA5LS45NDMtMS4xNzJhMi4yNjEsMi4yNjEsMCwwLDEtLjQ2Mi0xLjMsMS42MTQsMS42MTQsMCwwLDEsLjU2Ni0xLjMxMywyLjAwNiwyLjAwNiwwLDAsMSwxLjMyLS40NjhoNy40NXEuOTQyLDAsLjk0My0uNjU3VjI2LjUwNmExLjYwOSwxLjYwOSwwLDAsMC0uNzA3LjQyMnEtLjUxOS40MjEtMS4xNzkuODlhMTEuMDY5LDExLjA2OSwwLDAsMS0xLjUwOS44OTEsMy43NywzLjc3LDAsMCwxLTEuNy40MjIsNS40NSw1LjQ1LDAsMCwxLTMuNjc4LTEuNSw0LjI1LDQuMjUsMCwwLDEtMS4yMjYtMS44NzYsNy4wNTMsNy4wNTMsMCwwLDEtLjM3Ny0yLjI1LDUuMTY2LDUuMTY2LDAsMCwxLDEuNi0zLjcsNS4wMDksNS4wMDksMCwwLDEsMy42NzgtMS42NDEsNC44ODQsNC44ODQsMCwwLDEsMi4zNTcuNTE1QTcuNTg3LDcuNTg3LDAsMCwxLDQ5LjUxOCwyMC4yYy41MDYuNTg4Ljc4NS42MjQuNzg1LjYyNFYxNi44NDdhLjU0NC41NDQsMCwwLDAtLjMzMS0uNDY5LDEuNDIyLDEuNDIyLDAsMCwwLS43MDctLjE4N2gtNy40NWEyLjE0NywyLjE0NywwLDAsMS0xLjMyLS40MjIsMS41ODcsMS41ODcsMCwwLDEtLjU2Ni0xLjM2LDIuMDY3LDIuMDY3LDAsMCwxLC40MjUtMS4xNzJxLjQyNS0uNjA5Ljk0My0xLjIxOWExMi4yMjIsMTIuMjIyLDAsMCwwLC45NDMtMS4yNjYsMi41NDEsMi41NDEsMCwwLDAsLjQyNC0xLjQwNywzLjExOCwzLjExOCwwLDAsMC0xLjEzMi0yLjUzMiwzLjc3MSwzLjc3MSwwLDAsMC0yLjQ1MS0uOTM4LDMuODM5LDMuODM5LDAsMCwwLTIuNTk0LjkzOEEzLjE3OCwzLjE3OCwwLDAsMCwzNS40LDkuMzQ1YTIuNzc2LDIuNzc2LDAsMCwwLC40MjQsMS40NTQsMTAuMDM3LDEwLjAzNywwLDAsMCwuOSwxLjI2NWwuODQ5LDEuMjJhMi45MDksMi45MDksMCwwLDEsLjQ3MSwxLjEyNSwxLjYyNSwxLjYyNSwwLDAsMS0uNTE4LDEuMzYsMS45NTYsMS45NTYsMCwwLDEtMS4yNzQuNDIySDI5LjA4NHEtLjc1NSwwLS43NTQuNjU2Wm0yMy42NywwYTIuNywyLjcsMCwwLDEtLjU3NiwyLDIuNjc1LDIuNjc1LDAsMCwxLTIuMTU5LjYyNiIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTM3LjE0NywzMS4wNzRhMy4zMjgsMy4zMjgsMCwwLDAtMi44NzgtMS4zNiw0LjQ0NSw0LjQ0NSwwLDAsMC0yLjEyLjQyMiw2LjE4NSw2LjE4NSwwLDAsMC0xLjE3OC44OTFxLS41NjcuNDcxLTEuMTMyLjg5MWMtLjM3My4yNzgtLjgwOC43NzMtMS4zLjc3NkgyNi43MjdWMTYuNDZhMy4zMzUsMy4zMzUsMCwwLDAtLjM3Ny0xLjUsMS40MzYsMS40MzYsMCwwLDAtMS40MTUtLjc1MUgxOS4yNzdjLS41LDAtLjc1NC4yNTEtLjc1NC44NDRhMS45MDcsMS45MDcsMCwwLDAsLjM3NywxLjEyNiw5LjE0Niw5LjE0NiwwLDAsMCwuOTQzLDEuMTI1LDUuMzQxLDUuMzQxLDAsMCwxLC45NDMsMS4yNjYsMy4yMzYsMy4yMzYsMCwwLDEsLjM3NywxLjU0Nyw0LjQ1NCw0LjQ1NCwwLDAsMS0xLjI3MywzLjE0MSw0LjA0OSw0LjA0OSwwLDAsMS0zLjA2NSwxLjM2LDMuOSwzLjksMCwwLDEtMy4wMTgtMS4zNiw0LjU0Nyw0LjU0NywwLDAsMS0xLjIyNS0zLjE0MSwyLjkzNiwyLjkzNiwwLDAsMSwuNDI0LTEuNTQ3LDEzLjU0OCwxMy41NDgsMCwwLDEsLjktMS4zMTNjLjMxNC0uNDA2LjYyNy0uNzgxLjk0My0xLjEyNWExLjU4OCwxLjU4OCwwLDAsMCwuNDcxLTEuMDc5cTAtLjg0My0xLjAzNy0uODQ0SDUuN2ExLjU4NywxLjU4NywwLDAsMC0xLjIyNi41MTZBMS44MDYsMS44MDYsMCwwLDAsNCwxNS45OTFWMzkuOWExLjgsMS44LDAsMCwwLC40NzEsMS4yNjYsMS41ODMsMS41ODMsMCwwLDAsMS4yMjYuNTE2aDguNDg4Yy42OTEsMCwxLjAzNS4yMzgsMS4wMzcuNzVhMS41NDcsMS41NDcsMCwwLDEtLjQyMi45NDRMMTMuODA3LDQ0LjVhNi41NDksNi41NDksMCwwLDAtLjk5LDEuMjY2LDMuMTE2LDMuMTE2LDAsMCwwLS40MjQsMS42NDEsNC4yMzcsNC4yMzcsMCwwLDAsMS4zNjcsMy40Nyw0Ljc5MSw0Ljc5MSwwLDAsMCw2LjIyNC0uMDQ3LDQuNTE3LDQuNTE3LDAsMCwwLDEuNDQ1LTMuMjgzLDMuNjMxLDMuNjMxLDAsMCwwLS41MTQtMS44ODljLS4yMTUtLjMwNy0uOTc4LTEuMTU4LS45NzgtMS4xNThMMTguOSw0My4zNzNhMS40OTIsMS40OTIsMCwwLDEtLjM3Ny0uOTM4cTAtLjc1Ljg0OC0uNzVoNS42NThxMS4yMjYsMCwxLjctMS41VjM1LjM0MUgyOC4zNWMuNTU3LDAsMS4wNTQuNTE5LDEuNDg5LjhhMTIuMjkxLDEyLjI5MSwwLDAsMSwxLjIyNi44OTFxLjU2NS40NjksMS4xNzkuODlhMy43ODYsMy43ODYsMCwwLDAsMS44MTYuNDIyLDMuMjU2LDMuMjU2LDAsMCwwLDMuMDg3LTEuNDA2LDUuMTE5LDUuMTE5LDAsMCwwLC45OS0zQTQuNzg4LDQuNzg4LDAsMCwwLDM3LjE0NywzMS4wNzRaIi8+PC9zdmc+" const [offerings, setOfferings] = useState(); + const [selectedOffering, setSelectedOffering] = useState(); const [secret, setSecret] = useState(); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [portal, setPortal] = useState(); + const [layout, setLayout] = useState(FCLLayout.OneColumn); useEffect(() => { setLoading(true); @@ -44,12 +45,12 @@ function ServiceOfferingsView(props: any) { api( `service-offerings` ), { - params: - { - sm_secret_name: secret.name, - sm_secret_namespace: secret.namespace - } - } + params: + { + sm_secret_name: secret.name, + sm_secret_namespace: secret.namespace + } + } ) .then((response) => { setLoading(false); @@ -82,7 +83,13 @@ function ServiceOfferingsView(props: any) { } if (error) { - return + + return <> +
+ + +
+ } // @ts-ignore @@ -93,9 +100,11 @@ function ServiceOfferingsView(props: any) { // @ts-ignore return ( { - setPortal(createPortal(, document.getElementById("App")!!, window.crypto.randomUUID())) + setSelectedOffering(offering) + setLayout(FCLLayout.TwoColumnsMidExpanded) }} header={ -
- - + {cards} -
- {portal != null && portal} + +
+ +
+ { + if (layout === FCLLayout.MidColumnFullScreen) { + setLayout(FCLLayout.TwoColumnsMidExpanded) + } else { + setLayout(FCLLayout.MidColumnFullScreen) + } + }}> + { + setLayout(FCLLayout.OneColumn) + }}> +
+
+ +
+ }; + + return <>{renderData()}; } diff --git a/ui/src/components/StatusMessage.tsx b/ui/src/components/StatusMessage.tsx index eec131201..08b933c99 100644 --- a/ui/src/components/StatusMessage.tsx +++ b/ui/src/components/StatusMessage.tsx @@ -34,18 +34,19 @@ function StatusMessage(props: StatusMessageProps) { return ( + > {message} ); } else if (props.success) { return ( + design="Information"> {props.success} ); + } else { +
} }; diff --git a/ui/src/index.css b/ui/src/index.css index ba8a590d5..284bd27c4 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -48,7 +48,7 @@ code { height: 100%; } -.margin-wrapper { +.margin-wrapper, ui5-panel { margin: 0.5rem 0.5rem 0 0.5rem; padding: 0.5rem 0.5rem 0 0.5rem; } @@ -88,7 +88,7 @@ ui5-select { /* corrected margins on object page */ div[data-component-name="ObjectPage"] { - border-radius: 0.5em; + border-radius: 0.5em 0.5em 0 0; } /* corrected margins on object page */ @@ -97,10 +97,6 @@ header[data-component-name="ObjectPageTopHeader"] { display: inline !important; } -div[data-component-name="ObjectPageContent"] { - padding-top: 1rem; -} - header[data-component-name="ObjectPageTopHeader"]:has(ui5-illustrated-message) { height: 100%; } @@ -108,4 +104,20 @@ header[data-component-name="ObjectPageTopHeader"]:has(ui5-illustrated-message) { ui5-busy-indicator { padding-top: 1rem; display: block; +} + +div[data-component-name="ObjectPageContent"] { + padding-inline: 0; +} + +ui5-flexible-column-layout { + height: 100%; +} + +.icons-container { + display: flex; +} + +ui5-message-strip { + margin-bottom: 1rem; } \ No newline at end of file