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 (
}
onClick={showModal}
className={catalogStyles.catalogManageBtnClass}
- disabled={isViewDisabled}
+ disabled={activeServiceDetail.isUpdatePending}
>
Update
@@ -203,71 +211,101 @@ function UpdateService({
/>
) : null}
-
-
-
-
- }
- >
- Upload File
-
-
-
-
-
- }
- onClick={(event: React.MouseEvent) => {
- sendRequestRequest({ event: event });
- }}
- loading={updateServiceRequest.isPending}
- >
- Update
-
-
-
-
-
- {yamlSyntaxValidationStatus === 'completed' ||
- yamlSyntaxValidationStatus === 'error' ? (
-
- ) : null}
-
-
-
-
+
+
+
+
+ }
+ >
+ Upload File
+
+
+
+
+
+ }
+ onClick={(event: React.MouseEvent) => {
+ sendRequestRequest({ event: event });
+ }}
+ loading={updateServiceRequest.isPending}
+ >
+ Update
+
+
+
+
+
+ {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