From 1155580f0baefca70ef7390d2d653e9950058df2 Mon Sep 17 00:00:00 2001 From: WangLiNaruto Date: Tue, 10 Dec 2024 19:42:03 +0800 Subject: [PATCH] Changes to ISV view in UI to show current status of the service template --- .../catalog/services/delete/DeleteService.tsx | 12 +- .../services/details/ServiceProvider.tsx | 143 ++++++++++---- ...ail.tsx => ServiceTemplateBasicDetail.tsx} | 17 +- .../details/ServiceTemplateDetails.tsx | 48 +++++ .../re-register/ReRegisterService.tsx | 14 +- .../services/unregister/UnregisterService.tsx | 10 +- .../catalog/services/update/UpdateResult.tsx | 2 +- .../catalog/services/update/UpdateService.tsx | 174 +++++++++++------- .../tree/ServiceContent.tsx | 4 +- src/styles/catalog.module.css | 24 +++ src/styles/register.module.css | 6 +- src/xpanse-api/generated/sdk.gen.ts | 30 +++ src/xpanse-api/generated/types.gen.ts | 14 +- 13 files changed, 352 insertions(+), 146 deletions(-) rename src/components/content/catalog/services/details/{ServiceDetail.tsx => ServiceTemplateBasicDetail.tsx} (91%) create mode 100644 src/components/content/catalog/services/details/ServiceTemplateDetails.tsx diff --git a/src/components/content/catalog/services/delete/DeleteService.tsx b/src/components/content/catalog/services/delete/DeleteService.tsx index a9cab8fed..09d32036b 100644 --- a/src/components/content/catalog/services/delete/DeleteService.tsx +++ b/src/components/content/catalog/services/delete/DeleteService.tsx @@ -7,21 +7,19 @@ import { CloseCircleOutlined } from '@ant-design/icons'; import { Button, Popconfirm } from 'antd'; import React from 'react'; import catalogStyles from '../../../../../styles/catalog.module.css'; -import { serviceTemplateRegistrationState } from '../../../../../xpanse-api/generated'; -import { useGetReRegisterMutationState } from '../re-register/ReRegisterMutation'; +import { ServiceTemplateDetailVo } from '../../../../../xpanse-api/generated'; import { useDeleteRequest } from './DeleteServiceMutation'; function DeleteService({ id, setIsViewDisabled, - serviceRegistrationStatus, + activeServiceDetail, }: { id: string; setIsViewDisabled: (isViewDisabled: boolean) => void; - serviceRegistrationStatus: serviceTemplateRegistrationState; + activeServiceDetail: ServiceTemplateDetailVo; }): React.JSX.Element { const deleteRequest = useDeleteRequest(id); - const reRegisterState = useGetReRegisterMutationState(id); const deleteService = () => { setIsViewDisabled(true); @@ -45,8 +43,8 @@ function DeleteService({ className={catalogStyles.catalogManageBtnClass} disabled={ deleteRequest.isSuccess || - (reRegisterState.length > 0 && reRegisterState[0].status === 'success') || - serviceRegistrationStatus !== serviceTemplateRegistrationState.IN_REVIEW + activeServiceDetail.availableInCatalog || + activeServiceDetail.serviceTemplateRegistrationState === 'approved' } > Delete diff --git a/src/components/content/catalog/services/details/ServiceProvider.tsx b/src/components/content/catalog/services/details/ServiceProvider.tsx index 2b6e0a4bd..7d56baa9a 100644 --- a/src/components/content/catalog/services/details/ServiceProvider.tsx +++ b/src/components/content/catalog/services/details/ServiceProvider.tsx @@ -3,8 +3,7 @@ * SPDX-FileCopyrightText: Huawei Inc. */ -import { EnvironmentOutlined } from '@ant-design/icons'; -import { Empty, Image, Tabs } from 'antd'; +import { Badge, Empty, Image, Tabs } from 'antd'; import { Tab } from 'rc-tabs/lib/interface'; import React, { useMemo } from 'react'; import { createSearchParams, useNavigate, useSearchParams } from 'react-router-dom'; @@ -29,16 +28,14 @@ import { import { cspMap } from '../../../common/csp/CspLogo'; import { DeleteResult } from '../delete/DeleteResult'; import DeleteService from '../delete/DeleteService'; -import { ServicePolicies } from '../policies/ServicePolicies'; import { useReRegisterRequest } from '../re-register/ReRegisterMutation'; import { ReRegisterResult } from '../re-register/ReRegisterResult'; import ReRegisterService from '../re-register/ReRegisterService'; import { UnregisterResult } from '../unregister/UnregisterResult'; import UnregisterService from '../unregister/UnregisterService'; import UpdateService from '../update/UpdateService'; -import ServiceDetail from './ServiceDetail'; -import { ServiceHostingOptions } from './ServiceHostingOptions'; import { ServiceProviderSkeleton } from './ServiceProviderSkeleton'; +import ServiceTemplateDetails from './ServiceTemplateDetails'; function ServiceProvider({ categoryOclData, @@ -208,47 +205,129 @@ function ServiceProvider({ -

- -  Service Hosting Options -

- - - + {(activeServiceDetail.serviceTemplateRegistrationState === 'in-review' || + activeServiceDetail.serviceTemplateRegistrationState === 'approved') && + !activeServiceDetail.availableInCatalog ? ( + Review In-Progress} + color='#e67300' + > + + + ) : activeServiceDetail.serviceTemplateRegistrationState === 'approved' && + activeServiceDetail.availableInCatalog ? ( + Available In Catalog} + color='#87d068' + > + + + ) : activeServiceDetail.isUpdatePending && activeServiceDetail.availableInCatalog ? ( + + Available in catalog
+ Updated template review in progress. + + } + color='#e67300' + > + +
+ ) : activeServiceDetail.serviceTemplateRegistrationState === 'approved' && + !activeServiceDetail.availableInCatalog && + !activeServiceDetail.isUpdatePending ? ( + Not Available in Catalog} + color='#cd201f' + > + + + ) : activeServiceDetail.serviceTemplateRegistrationState === 'rejected' && + !activeServiceDetail.availableInCatalog && + activeServiceDetail.isUpdatePending ? ( + Review In-Progress} + color='#e67300' + > + + + ) : activeServiceDetail.serviceTemplateRegistrationState === 'approved' && + activeServiceDetail.availableInCatalog && + activeServiceDetail.isUpdatePending ? ( + Available In Catalog} + color='#87d068' + > + + + ) : null} ) : ( // Necessary when user manually enters wrong details in the URL query parameters. diff --git a/src/components/content/catalog/services/details/ServiceDetail.tsx b/src/components/content/catalog/services/details/ServiceTemplateBasicDetail.tsx similarity index 91% rename from src/components/content/catalog/services/details/ServiceDetail.tsx rename to src/components/content/catalog/services/details/ServiceTemplateBasicDetail.tsx index 8a800ff1c..197ca7f7d 100644 --- a/src/components/content/catalog/services/details/ServiceDetail.tsx +++ b/src/components/content/catalog/services/details/ServiceTemplateBasicDetail.tsx @@ -15,11 +15,9 @@ import { DeployedService, serviceDeploymentState, ServiceTemplateDetailVo, - serviceTemplateRegistrationState, } from '../../../../../xpanse-api/generated'; import { useCurrentUserRoleStore } from '../../../../layouts/header/useCurrentRoleStore'; import { reportsRoute } from '../../../../utils/constants'; -import { ServiceTemplateRegisterStatus } from '../../../common/catalog/ServiceTemplateRegisterStatus.tsx'; import { ApiDoc } from '../../../common/doc/ApiDoc'; import { AgreementText } from '../../../common/ocl/AgreementText'; import { BillingText } from '../../../common/ocl/BillingText'; @@ -32,7 +30,11 @@ import DeploymentManagement from '../../../deployment/DeploymentManagement'; import ServiceConfigManagement from '../../../serviceConfigurationManage/ServiceConfigManagement'; import { ShowIcon } from './ShowIcon'; -function ServiceDetail({ serviceDetails }: { serviceDetails: ServiceTemplateDetailVo }): React.JSX.Element { +function ServiceTemplateBasicDetail({ + serviceDetails, +}: { + serviceDetails: ServiceTemplateDetailVo; +}): React.JSX.Element { const currentRole = useCurrentUserRoleStore((state) => state.currentUserRole); const navigate = useNavigate(); let numberOfActiveServiceDeployments: number = 0; @@ -121,13 +123,6 @@ function ServiceDetail({ serviceDetails }: { serviceDetails: ServiceTemplateDeta {serviceDetails.createTime} {serviceDetails.lastModifiedTime} - - - {serviceDetails.deployment.credentialType} @@ -164,4 +159,4 @@ function ServiceDetail({ serviceDetails }: { serviceDetails: ServiceTemplateDeta ); } -export default ServiceDetail; +export default ServiceTemplateBasicDetail; diff --git a/src/components/content/catalog/services/details/ServiceTemplateDetails.tsx b/src/components/content/catalog/services/details/ServiceTemplateDetails.tsx new file mode 100644 index 000000000..fe4260573 --- /dev/null +++ b/src/components/content/catalog/services/details/ServiceTemplateDetails.tsx @@ -0,0 +1,48 @@ +import { EnvironmentOutlined } from '@ant-design/icons'; +import { Card } from 'antd'; +import React from 'react'; +import catalogStyles from '../../../../../styles/catalog.module.css'; +import { ServiceTemplateDetailVo } from '../../../../../xpanse-api/generated'; +import { ServicePolicies } from '../policies/ServicePolicies'; +import { ServiceHostingOptions } from './ServiceHostingOptions'; +import ServiceTemplateBasicDetail from './ServiceTemplateBasicDetail'; + +function serviceTemplateDetails({ + isViewDisabled, + serviceDetails, + groupServiceTemplatesByCsp, + serviceCspInQuery, + serviceHostingTypeInQuery, + onChangeServiceHostingType, +}: { + isViewDisabled: boolean; + serviceDetails: ServiceTemplateDetailVo; + groupServiceTemplatesByCsp: Map; + serviceCspInQuery: string; + serviceHostingTypeInQuery: string; + onChangeServiceHostingType: (serviceTemplateDetailVo: ServiceTemplateDetailVo) => void; +}): React.JSX.Element { + return ( + <> + +
+ +  Service Hosting Options +
+ + + +
+ + ); +} +export default serviceTemplateDetails; diff --git a/src/components/content/catalog/services/re-register/ReRegisterService.tsx b/src/components/content/catalog/services/re-register/ReRegisterService.tsx index 8f0076934..46936581b 100644 --- a/src/components/content/catalog/services/re-register/ReRegisterService.tsx +++ b/src/components/content/catalog/services/re-register/ReRegisterService.tsx @@ -8,21 +8,17 @@ import { UseMutationResult } from '@tanstack/react-query'; import { Button, Popconfirm } from 'antd'; import React from 'react'; import catalogStyles from '../../../../../styles/catalog.module.css'; -import { ServiceTemplateDetailVo, serviceTemplateRegistrationState } from '../../../../../xpanse-api/generated'; -import { useGetDeleteMutationState } from '../delete/DeleteServiceMutation'; +import { ServiceTemplateDetailVo } from '../../../../../xpanse-api/generated'; function ReRegisterService({ - id, setIsViewDisabled, reRegisterRequest, - serviceRegistrationStatus, + activeServiceDetail, }: { - id: string; setIsViewDisabled: (isViewDisabled: boolean) => void; reRegisterRequest: UseMutationResult; - serviceRegistrationStatus: serviceTemplateRegistrationState; + activeServiceDetail: ServiceTemplateDetailVo; }): React.JSX.Element { - const deleteState = useGetDeleteMutationState(id); const reRegister = () => { setIsViewDisabled(true); reRegisterRequest.mutate(); @@ -45,8 +41,8 @@ function ReRegisterService({ className={catalogStyles.catalogManageBtnClass} disabled={ reRegisterRequest.isSuccess || - (deleteState.length > 0 && deleteState[0].status === 'success') || - serviceRegistrationStatus !== serviceTemplateRegistrationState.IN_REVIEW + activeServiceDetail.availableInCatalog || + activeServiceDetail.serviceTemplateRegistrationState !== 'approved' } > Re-register diff --git a/src/components/content/catalog/services/unregister/UnregisterService.tsx b/src/components/content/catalog/services/unregister/UnregisterService.tsx index fb1005ab5..1212db280 100644 --- a/src/components/content/catalog/services/unregister/UnregisterService.tsx +++ b/src/components/content/catalog/services/unregister/UnregisterService.tsx @@ -7,17 +7,16 @@ import { MinusCircleOutlined } from '@ant-design/icons'; import { Button, Popconfirm } from 'antd'; import React from 'react'; import catalogStyles from '../../../../../styles/catalog.module.css'; -import { serviceTemplateRegistrationState } from '../../../../../xpanse-api/generated'; import { useUnregisterRequest } from './UnregisterMutation'; function UnregisterService({ id, setIsViewDisabled, - serviceRegistrationStatus, + availableInCatalog, }: { id: string; setIsViewDisabled: (isViewDisabled: boolean) => void; - serviceRegistrationStatus: serviceTemplateRegistrationState; + availableInCatalog: boolean; }): React.JSX.Element { const unregisterRequest = useUnregisterRequest(id); @@ -41,10 +40,7 @@ function UnregisterService({ icon={} type='primary' className={catalogStyles.catalogManageBtnClass} - disabled={ - unregisterRequest.isSuccess || - serviceRegistrationStatus === serviceTemplateRegistrationState.IN_REVIEW - } + disabled={unregisterRequest.isSuccess || !availableInCatalog} > Unregister diff --git a/src/components/content/catalog/services/update/UpdateResult.tsx b/src/components/content/catalog/services/update/UpdateResult.tsx index e592aa116..98e906c2f 100644 --- a/src/components/content/catalog/services/update/UpdateResult.tsx +++ b/src/components/content/catalog/services/update/UpdateResult.tsx @@ -34,7 +34,7 @@ function UpdateResult({ message={ serviceRegistrationStatus === serviceTemplateRegistrationState.APPROVED ? ( <> - Service {ocl.name} updated in catalog successfully. + Service {ocl.name} updated was submitted for review. ) : ( <> diff --git a/src/components/content/catalog/services/update/UpdateService.tsx b/src/components/content/catalog/services/update/UpdateService.tsx index ee0bccc9a..ee06e7eef 100644 --- a/src/components/content/catalog/services/update/UpdateService.tsx +++ b/src/components/content/catalog/services/update/UpdateService.tsx @@ -5,7 +5,8 @@ import { AppstoreAddOutlined, CloudUploadOutlined, EditOutlined, UploadOutlined } from '@ant-design/icons'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { Button, Col, Modal, Row, Upload, UploadFile } from 'antd'; +import { Button, Col, Form, Modal, Radio, Row, Upload, UploadFile } from 'antd'; +import { CheckboxChangeEvent } from 'antd/es/checkbox'; import { RcFile } from 'antd/es/upload'; import React, { useRef, useState } from 'react'; import appStyles from '../../../../../styles/app.module.css'; @@ -19,6 +20,7 @@ import { ErrorResponse, Ocl, ServiceTemplateChangeInfo, + ServiceTemplateDetailVo, serviceTemplateRegistrationState, update, type UpdateData, @@ -34,12 +36,13 @@ import UpdateResult from './UpdateResult'; function UpdateService({ id, category, - isViewDisabled, + activeServiceDetail, }: { id: string; category: category; - isViewDisabled: boolean; + activeServiceDetail: ServiceTemplateDetailVo; }): React.JSX.Element { + const [form] = Form.useForm(); const ocl = useRef(undefined); const files = useRef([]); const yamlValidationResult = useRef(''); @@ -51,12 +54,13 @@ function UpdateService({ const [yamlSyntaxValidationStatus, setYamlSyntaxValidationStatus] = useState('notStarted'); const [oclValidationStatus, setOclValidationStatus] = useState('notStarted'); const [isModalOpen, setIsModalOpen] = useState(false); + const [isRemoveServiceTemplateUntilApproved, setIsRemoveServiceTemplateUntilApproved] = useState(false); const queryClient = useQueryClient(); const updateServiceRequest = useMutation({ mutationFn: (ocl: Ocl) => { const data: UpdateData = { id: id, - isRemoveServiceTemplateUntilApproved: true, + isRemoveServiceTemplateUntilApproved: isRemoveServiceTemplateUntilApproved, requestBody: ocl, }; return update(data); @@ -165,6 +169,10 @@ function UpdateService({ return false; }; + const onChange = (e: CheckboxChangeEvent) => { + setIsRemoveServiceTemplateUntilApproved(e.target.checked); + }; + return (
@@ -203,71 +211,101 @@ function UpdateService({ /> ) : null}
- - - -
- -
- - -
- -
- - -
- {yamlSyntaxValidationStatus === 'completed' || - yamlSyntaxValidationStatus === 'error' ? ( - - ) : null} -
- -
-
+ + + +
+ +
+ + +
+ +
+ + +
+ {yamlSyntaxValidationStatus === 'completed' || + yamlSyntaxValidationStatus === 'error' ? ( + + ) : null} +
+ +
+
+ {files.current.length > 0 ? ( + + Remove current service template until updated service template is approved + + } + required={true} + rules={[{ required: true, message: 'Eula needs to be accepted' }]} + > + + true + false + + + ) : null} + +
+
+
{oclDisplayData.current}
-
{oclDisplayData.current}
diff --git a/src/components/content/registeredServices/tree/ServiceContent.tsx b/src/components/content/registeredServices/tree/ServiceContent.tsx index 0512bed5e..d39747b48 100644 --- a/src/components/content/registeredServices/tree/ServiceContent.tsx +++ b/src/components/content/registeredServices/tree/ServiceContent.tsx @@ -17,9 +17,9 @@ import { serviceNamespaceQuery, serviceVersionKeyQuery, } from '../../../utils/constants.tsx'; -import ServiceDetail from '../../catalog/services/details/ServiceDetail.tsx'; import { ServiceHostingOptions } from '../../catalog/services/details/ServiceHostingOptions.tsx'; import { ServiceProviderSkeleton } from '../../catalog/services/details/ServiceProviderSkeleton.tsx'; +import ServiceTemplateBasicDetail from '../../catalog/services/details/ServiceTemplateBasicDetail.tsx'; function ServiceContent({ availableServiceList, @@ -134,7 +134,7 @@ function ServiceContent({ serviceHostingTypeInQuery={serviceHostingTypeInQuery} updateServiceHostingType={onChangeServiceHostingType} /> - + ) : ( // Necessary when user manually enters wrong details in the URL query parameters. diff --git a/src/styles/catalog.module.css b/src/styles/catalog.module.css index c82459873..97243600c 100644 --- a/src/styles/catalog.module.css +++ b/src/styles/catalog.module.css @@ -51,6 +51,11 @@ display: flex; } +.service-template-card { + margin-top: 10px; + padding-top: 0px !important; +} + .catalog-skeleton { margin: 30px; position: absolute; @@ -76,7 +81,10 @@ } .catalog-details-h3 { + padding-top: 15px; font-size: 16px; + font-weight: bold; + padding-bottom: 10px; } .catalog-details-h6 { @@ -125,3 +133,19 @@ height: 26px; display: inline-block; } + +.service-template-state { + animation: blink-animation 1s infinite; +} + +@keyframes blink-animation { + 0% { + opacity: 1; + } + 50% { + opacity: 0; + } + 100% { + opacity: 1; + } +} diff --git a/src/styles/register.module.css b/src/styles/register.module.css index 740592e3a..7d519eb44 100644 --- a/src/styles/register.module.css +++ b/src/styles/register.module.css @@ -7,17 +7,13 @@ padding: 24px; } -.register-buttons { +.registerButtons { display: flex; align-items: baseline; gap: 10px; margin-top: 20px; } -.register-buttons-upload { - margin-right: 5px; -} - .register-buttons-register { margin-left: 5px; margin-right: 5px; diff --git a/src/xpanse-api/generated/sdk.gen.ts b/src/xpanse-api/generated/sdk.gen.ts index 6d2ec8d21..325d9bd59 100644 --- a/src/xpanse-api/generated/sdk.gen.ts +++ b/src/xpanse-api/generated/sdk.gen.ts @@ -81,6 +81,8 @@ import type { GetMetricsResponse, GetOrderableServiceDetailsByIdData, GetOrderableServiceDetailsByIdResponse, + GetOrderableServiceDetailsByServiceIdData, + GetOrderableServiceDetailsByServiceIdResponse, GetOrderableServicesData, GetOrderableServicesResponse, GetOrderDetailsByOrderIdData, @@ -1388,6 +1390,34 @@ export const queryTasks = (data: QueryTasksData = {}): CancelablePromise Required role: admin or isv or user
+ * @param data The data for the request. + * @param data.serviceId The id of deployed service. + * @returns UserOrderableServiceVo OK + * @throws ApiError + */ +export const getOrderableServiceDetailsByServiceId = ( + data: GetOrderableServiceDetailsByServiceIdData +): CancelablePromise => { + return __request(OpenAPI, { + method: 'GET', + url: '/xpanse/services/{serviceId}/service_template', + path: { + serviceId: data.serviceId, + }, + errors: { + 400: 'Bad Request', + 401: 'Unauthorized', + 403: 'Forbidden', + 408: 'Request Timeout', + 422: 'Unprocessable Entity', + 500: 'Internal Server Error', + 502: 'Bad Gateway', + }, + }); +}; + /** * List compute resources of the service.
Required role: admin or user
* @param data The data for the request. diff --git a/src/xpanse-api/generated/types.gen.ts b/src/xpanse-api/generated/types.gen.ts index 2af272818..0b71d406b 100644 --- a/src/xpanse-api/generated/types.gen.ts +++ b/src/xpanse-api/generated/types.gen.ts @@ -2066,10 +2066,7 @@ export type ServiceOrderDetails = { * The id of the workflow. */ workflowId?: string; - /** - * The error message if the service order task failed. - */ - errorMsg?: string; + errorResponse?: ErrorResponse; /** * The id of the user who created the service order. */ @@ -3246,6 +3243,15 @@ export type QueryTasksData = { export type QueryTasksResponse = Array; +export type GetOrderableServiceDetailsByServiceIdData = { + /** + * The id of deployed service. + */ + serviceId: string; +}; + +export type GetOrderableServiceDetailsByServiceIdResponse = UserOrderableServiceVo; + export type GetComputeResourceInventoryOfServiceData = { /** * Id of the deployed service