From dc7e80355135649685128eae6e8707930bdcb829 Mon Sep 17 00:00:00 2001 From: "ajithkumar.s" Date: Wed, 20 Mar 2024 16:42:00 +0530 Subject: [PATCH 1/5] changelog updated --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e485a2..b955535f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ New features, fixed bugs, known defects and other noteworthy changes to each release of the Simple Data Exchanger Frontend. +## [Unreleased] +### Added +- Dedicated page to manage policies. +- Policies will be dynamically fetched from policy hub based on the selected/available use-cases. +- Frontend components will be dynamically rendered based on the policy type. +- New policies can be created and already created policies will be selected and modified while uploading a data. +- Re-usable page loading handlers for api calls. +- Notes and info texts added in create data page. +- Policy related documentations updated. + +### Changed +- Upload data api implemetation moved to RTK query for better performance. + ## [2.3.6] - 2024-03-08 ### Added - Policy overlay descriptions. From 6e162ac74c82b195b25c2dd3172380cbd7e1e769 Mon Sep 17 00:00:00 2001 From: AjayRaturi123 Date: Thu, 21 Mar 2024 22:11:42 +0530 Subject: [PATCH 2/5] Update document with policy hub changes images. --- docs/user-guide/README.md | 59 +++++-------------- docs/user-guide/images/add-policy.svg | 4 ++ docs/user-guide/images/manual-entry.svg | 4 ++ docs/user-guide/images/policy.svg | 4 ++ docs/user-guide/images/sde-about.svg | 2 +- .../images/sde-assembly-tabular.svg | 4 -- docs/user-guide/images/sde-batch-tabular.svg | 4 -- .../images/sde-configure-policy.svg | 2 +- .../images/sde-consume-data-page.svg | 2 +- .../images/sde-consumer-contracts.svg | 2 +- docs/user-guide/images/sde-create-data.svg | 2 +- docs/user-guide/images/sde-help-page.svg | 2 +- docs/user-guide/images/sde-home.svg | 2 +- .../images/sde-part-planned-tabular.svg | 4 -- .../images/sde-part-site-info-tabular.svg | 4 -- .../images/sde-product-carbon-footprint.svg | 4 -- .../images/sde-provider-contracts.svg | 2 +- .../images/sde-serial-part-tabular.svg | 4 -- docs/user-guide/images/sde-sidemenu.svg | 2 +- .../images/sde-single-bom-tabular.svg | 4 -- .../images/sde-single-level-usage-table.svg | 4 -- .../images/sde-upload-error-logs.svg | 2 +- docs/user-guide/images/sde-upload-history.svg | 2 +- 23 files changed, 39 insertions(+), 86 deletions(-) create mode 100644 docs/user-guide/images/add-policy.svg create mode 100644 docs/user-guide/images/manual-entry.svg create mode 100644 docs/user-guide/images/policy.svg delete mode 100644 docs/user-guide/images/sde-assembly-tabular.svg delete mode 100644 docs/user-guide/images/sde-batch-tabular.svg delete mode 100644 docs/user-guide/images/sde-part-planned-tabular.svg delete mode 100644 docs/user-guide/images/sde-part-site-info-tabular.svg delete mode 100644 docs/user-guide/images/sde-product-carbon-footprint.svg delete mode 100644 docs/user-guide/images/sde-serial-part-tabular.svg delete mode 100644 docs/user-guide/images/sde-single-bom-tabular.svg delete mode 100644 docs/user-guide/images/sde-single-level-usage-table.svg diff --git a/docs/user-guide/README.md b/docs/user-guide/README.md index f0b4f1aa..f22d4856 100644 --- a/docs/user-guide/README.md +++ b/docs/user-guide/README.md @@ -25,14 +25,7 @@ This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LIC - [Create Data](#create-data) - [Upload File](#upload-file) - [Manual Entry](#manual-entry) - - [Serial Part](#serial-part-typization) - - [Batch](#batch) - - [Single Level BoM As Built](#single-level-bom-asbuilt) - - [Part As Planned](#part-as-planned) - - [Single Level Bom As Planned](#single-level-bom-as-planned) - - [Part Site Information As Planned](#part-site-information-as-planned) - - [Single Level Usage As Built](#single-level-usage-as-built) - - [Product Carbon Footprint](#product-carbon-footprint) + - [Policies](#policies) - [Upload history](#upload-history) - [Contracts](#provider-contracts) - [Help](#help) @@ -44,7 +37,7 @@ This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LIC ## **Accessing the app** -[SDE](https://dft.int.demo.catena-x.net/) can be accessed via the internet. The recommended browser is Google Chrome. You need to request an account to access it. +SDE can be accessed via the internet. The recommended browser is Google Chrome. You need to request an account to access it. ### **Login** @@ -52,7 +45,7 @@ This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LIC -1. Open **S**imple **D**ata **E**xchanger application via the [URL](https://dft.int.demo.catena-x.net/) (recommended browser Google Chrome). +1. Open **S**imple **D**ata **E**xchanger application via the URL (recommended browser Google Chrome). 2. Select the organization from the list or search the organization by typing name in input textbox and select the organization from the search results to login to the Simple Data Exchanger application. After selecting the organization from the list, it will redirect to the CatenaX keycloak login page. 3. On Keycloak login page of the selected organization, enter login details i.e. Username or email and Password. Click on Sign In button to login to the Simple Data Exchanger application. @@ -89,6 +82,7 @@ On the left side menu, it is possible to navigate the Simple Data Exchanger appl **Provider** - Create Data +- Policies - Upload History - Contracts - Help @@ -154,51 +148,31 @@ You can click on the button "Choose a file" and select the proper CSV file prese After successful file upload of the supported file format i.e. CSV, the button "Next Step - Configure Policies" will be enabled and after clicking on the same, Policy selection dialog will be shown where we need to configure Access and Usage policy. -User can configure access policy accordingly and select company name or bpn number to add. +User can create new or choose existing policy. -User can add usage policy accordingly and select framework. +User can configure access and usage policy accordingly to use case selection. Once configuring both the policies, we need to click on "SUBMIT" button and wait for upload to finish. This is the process of creating new data offer through SDE application by uploading CSV file. - ### Manual entry -#### Serial Part + - - -#### Batch - - - -#### Single Level BoM AsBuilt - - - -#### Part AsPlanned - - - -#### Single Level Bom AsPlanned - - - -#### Part Site Information AsPlanned - - +You can add and submit multiple data offers via Manual entry option for particular submodel by clicking on "Add Row" button to bulk upload the multiple data offers in one go. Once you enter details in all of the required fields for a particular row, you need to select which offers we need to upload by ticking the checkboxes for the respective rows and then we need to click on "Next Step - Configure Policies" button to configure Access and Usage policies and then you need to click on Submit button from policy dialog to upload the data. You can upload the data for multiple submodels by selecting the respective submodel from the top level Select submodel dropdown. +We also can delete multiple rows by selecting which rows we want to delete and then click on Delete Row(s) button. -#### Single Level Usage AsBuilt +Then you need to configure Access and Usage policies by clicking on "Next Step - Configure Policies" button and after successful configuration, click on Submit button from policy dialog to upload bulk data offers at once. - +You can add other sub-model similarly. -#### Product Carbon Footprint +## Policies - + -You can add and submit multiple data offers via Manual entry option for particular submodel by clicking on "Add Row" button to bulk upload the multiple data offers in one go. Once you enter details in all of the required fields for a particular row, you need to select which offers we need to upload by ticking the checkboxes for the respective rows and then we need to click on "Next Step - Configure Policies" button to configure Access and Usage policies and then you need to click on Submit button from policy dialog to upload the data. You can upload the data for multiple submodels by selecting the respective submodel from the top level Select submodel dropdown. -We also can delete multiple rows by selecting which rows we want to delete and then click on Delete Row(s) button. +User can add and edit the policies in this page by clicking add policy button. So that policies for manual upload process is possible. -Then you need to configure Access and Usage policies by clicking on "Next Step - Configure Policies" button and after successful configuration, click on Submit button from policy dialog to upload bulk data offers at once. + ## Upload history @@ -238,14 +212,13 @@ The table includes below columns: - Asset ID (ID of the Asset); - Consumer Counter Party Address (Counter party address of the contract agreement); - Signing Date (Signing date of the contract agreement); -- End Date (End date of the contract agreement, if duration restriction under usage policies is unrestricted while creating data then there is no end date and its unlimited); - Status (FINALIZED or TERMINATED or ERROR or DECLINED); ## Help -This dynamic help page provides the submodel informations of selected use case in the home page. If no use case selected, it will show all available submodels. User can see the the order of the fields and details of each field by hovering the info icon in each row. User can download the sample csv and csv template for any submodels as well from this page. +This dynamic help page provides the submodel informations of selected use case in the home page. If no use case selected, it will show all available submodels. User can see the the order of the fields and details of each field by hovering the info icon in each row. User can download the sample csv and csv template for any submodels as well from this page. User can use quick link to navigate on any sub model. # **Consumer** diff --git a/docs/user-guide/images/add-policy.svg b/docs/user-guide/images/add-policy.svg new file mode 100644 index 00000000..becd2dc8 --- /dev/null +++ b/docs/user-guide/images/add-policy.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/user-guide/images/manual-entry.svg b/docs/user-guide/images/manual-entry.svg new file mode 100644 index 00000000..2f4f610b --- /dev/null +++ b/docs/user-guide/images/manual-entry.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/user-guide/images/policy.svg b/docs/user-guide/images/policy.svg new file mode 100644 index 00000000..5fc78e7c --- /dev/null +++ b/docs/user-guide/images/policy.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/user-guide/images/sde-about.svg b/docs/user-guide/images/sde-about.svg index 622cd10e..6935681a 100644 --- a/docs/user-guide/images/sde-about.svg +++ b/docs/user-guide/images/sde-about.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-assembly-tabular.svg b/docs/user-guide/images/sde-assembly-tabular.svg deleted file mode 100644 index 5a86b92b..00000000 --- a/docs/user-guide/images/sde-assembly-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-batch-tabular.svg b/docs/user-guide/images/sde-batch-tabular.svg deleted file mode 100644 index 3c5781e5..00000000 --- a/docs/user-guide/images/sde-batch-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-configure-policy.svg b/docs/user-guide/images/sde-configure-policy.svg index e522803d..a9eefca0 100644 --- a/docs/user-guide/images/sde-configure-policy.svg +++ b/docs/user-guide/images/sde-configure-policy.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-consume-data-page.svg b/docs/user-guide/images/sde-consume-data-page.svg index f3927ecb..9f012ff6 100644 --- a/docs/user-guide/images/sde-consume-data-page.svg +++ b/docs/user-guide/images/sde-consume-data-page.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-consumer-contracts.svg b/docs/user-guide/images/sde-consumer-contracts.svg index 4a95adff..431e829f 100644 --- a/docs/user-guide/images/sde-consumer-contracts.svg +++ b/docs/user-guide/images/sde-consumer-contracts.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-create-data.svg b/docs/user-guide/images/sde-create-data.svg index 8b2e30bf..f83a36bd 100644 --- a/docs/user-guide/images/sde-create-data.svg +++ b/docs/user-guide/images/sde-create-data.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-help-page.svg b/docs/user-guide/images/sde-help-page.svg index fdb7df92..232ebcc0 100644 --- a/docs/user-guide/images/sde-help-page.svg +++ b/docs/user-guide/images/sde-help-page.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-home.svg b/docs/user-guide/images/sde-home.svg index d7b3b0c0..1271610f 100644 --- a/docs/user-guide/images/sde-home.svg +++ b/docs/user-guide/images/sde-home.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-part-planned-tabular.svg b/docs/user-guide/images/sde-part-planned-tabular.svg deleted file mode 100644 index b67260ec..00000000 --- a/docs/user-guide/images/sde-part-planned-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-part-site-info-tabular.svg b/docs/user-guide/images/sde-part-site-info-tabular.svg deleted file mode 100644 index a90579e9..00000000 --- a/docs/user-guide/images/sde-part-site-info-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-product-carbon-footprint.svg b/docs/user-guide/images/sde-product-carbon-footprint.svg deleted file mode 100644 index e801acc8..00000000 --- a/docs/user-guide/images/sde-product-carbon-footprint.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-provider-contracts.svg b/docs/user-guide/images/sde-provider-contracts.svg index f9b96502..6f09e093 100644 --- a/docs/user-guide/images/sde-provider-contracts.svg +++ b/docs/user-guide/images/sde-provider-contracts.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-serial-part-tabular.svg b/docs/user-guide/images/sde-serial-part-tabular.svg deleted file mode 100644 index 685cb726..00000000 --- a/docs/user-guide/images/sde-serial-part-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-sidemenu.svg b/docs/user-guide/images/sde-sidemenu.svg index 2eaf8cb7..f4e71677 100644 --- a/docs/user-guide/images/sde-sidemenu.svg +++ b/docs/user-guide/images/sde-sidemenu.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-single-bom-tabular.svg b/docs/user-guide/images/sde-single-bom-tabular.svg deleted file mode 100644 index e1bf7833..00000000 --- a/docs/user-guide/images/sde-single-bom-tabular.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-single-level-usage-table.svg b/docs/user-guide/images/sde-single-level-usage-table.svg deleted file mode 100644 index e9a73fac..00000000 --- a/docs/user-guide/images/sde-single-level-usage-table.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/docs/user-guide/images/sde-upload-error-logs.svg b/docs/user-guide/images/sde-upload-error-logs.svg index d2747ae0..cde7b826 100644 --- a/docs/user-guide/images/sde-upload-error-logs.svg +++ b/docs/user-guide/images/sde-upload-error-logs.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/user-guide/images/sde-upload-history.svg b/docs/user-guide/images/sde-upload-history.svg index b8fc3781..f3739147 100644 --- a/docs/user-guide/images/sde-upload-history.svg +++ b/docs/user-guide/images/sde-upload-history.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + \ No newline at end of file From 32ef5b3fa3b2fb9caa10fb869c3c4943f3d294bb Mon Sep 17 00:00:00 2001 From: "ajithkumar.s" Date: Wed, 3 Apr 2024 16:06:52 +0530 Subject: [PATCH 3/5] Fetching policy information from EDC for offer details overlay --- src/assets/locales/de/main.json | 6 + src/assets/locales/en/main.json | 6 + src/components/dialogs/ConfirmTermsDialog.tsx | 75 ++++---- src/components/dialogs/OfferDetailsDialog.tsx | 84 +++----- src/features/consumer/apiSlice.ts | 39 ++++ src/features/consumer/slice.ts | 14 +- src/features/consumer/types.ts | 4 +- src/pages/ConsumeData.tsx | 181 ++++++++---------- src/tests/ConfirmTermsDialog.test.tsx | 8 +- src/tests/OfferDetailsDialog.test.tsx | 9 +- src/utils/utils.tsx | 5 + 11 files changed, 221 insertions(+), 210 deletions(-) create mode 100644 src/features/consumer/apiSlice.ts diff --git a/src/assets/locales/de/main.json b/src/assets/locales/de/main.json index e8a6a482..ffc3fe83 100644 --- a/src/assets/locales/de/main.json +++ b/src/assets/locales/de/main.json @@ -127,6 +127,8 @@ "title": "Titel", "assetId": "Asset ID", "created": "erstellt am", + "sematicVersion": "Sematic Version", + "publisher": "Publisher", "description": "Beschreibung" } }, @@ -182,6 +184,7 @@ "value": "Wert", "titleText": "Titel", "created": "Erstellt am", + "sematicVersion": "Sematic Version", "dataFormat": "Datenformat", "description": "Beschreibung", "publisher": "Anbieter", @@ -194,6 +197,9 @@ "point1": "Sie sind befugt, Ihre Organisation in diesem Fall zu vertreten.", "point2": "Sie haben die Zugangs- und Nutzungspolicies gelesen und verstanden.", "point3": "Ihre Organisation ist verpflichtet, die Bedingungen der Zugangs- und Nutzungspolicy einzuhalten." + }, + "prompt": { + "confirm": "Bitte bestätigen" } }, "button": { diff --git a/src/assets/locales/en/main.json b/src/assets/locales/en/main.json index d223829b..38ffa695 100644 --- a/src/assets/locales/en/main.json +++ b/src/assets/locales/en/main.json @@ -130,6 +130,8 @@ "title": "Title", "assetId": "Asset ID", "created": "Created On", + "sematicVersion": "Sematic Version", + "publisher": "Publisher", "description": "Description" } }, @@ -185,6 +187,7 @@ "value": "Value", "titleText": "Title", "created": "Created on", + "sematicVersion": "Sematic Version", "dataFormat": "Data format", "description": "Description", "publisher": "Publisher", @@ -197,6 +200,9 @@ "point1": "You are entitled to represent your organization.", "point2": "You have read and understood the access/usage policy.", "point3": "Your organization will be responsible to adhere by the rules stated in the access/usage policy." + }, + "prompt": { + "confirm": "Please Confirm" } }, "button": { diff --git a/src/components/dialogs/ConfirmTermsDialog.tsx b/src/components/dialogs/ConfirmTermsDialog.tsx index 2645fc4c..90043dd2 100644 --- a/src/components/dialogs/ConfirmTermsDialog.tsx +++ b/src/components/dialogs/ConfirmTermsDialog.tsx @@ -1,6 +1,6 @@ /******************************************************************************** - * Copyright (c) 2021,2022,2023 T-Systems International GmbH - * Copyright (c) 2022,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2022,2024 T-Systems International GmbH + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -23,7 +23,10 @@ import { Button, Dialog, DialogActions, DialogContent, DialogHeader, LoadingButt import React, { useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; +import { setOpenOfferConfirmDialog } from '../../features/consumer/slice'; import { IConsumerDataOffers } from '../../features/consumer/types'; +import { useAppDispatch, useAppSelector } from '../../features/store'; +import { splitWithFirstOcc } from '../../utils/utils'; interface IntConfirmOffer { offers?: IConsumerDataOffers[] | []; @@ -31,61 +34,49 @@ interface IntConfirmOffer { provider: string; } interface IntDialogProps { - title?: string; - open: boolean; handleConfirm?: () => void; - handleClose?: (state: boolean) => void; isProgress?: boolean; offerObj?: IntConfirmOffer; } -const ConfirmTermsDialog: React.FC = ({ - title = 'Confirm', - open = false, - handleConfirm, - handleClose, - isProgress = false, - children, - offerObj, -}) => { +const ConfirmTermsDialog: React.FC = ({ handleConfirm, isProgress = false, offerObj }) => { + const { openOfferConfirmDialog } = useAppSelector(state => state.consumerSlice); const [isAgreed, setIsAgreed] = useState(false); const { t } = useTranslation(); - - function splitWithFirstOcc(str: string) { - const regX = /:(.*)/s; - return str.split(regX) ? `${str.split(regX)[0]}.` : '-.'; - } + const dispatch = useAppDispatch(); return ( - - handleClose(false)} title={title} /> + + dispatch(setOpenOfferConfirmDialog(false))} + title={t('dialog.prompt.confirm')} + /> - {children || ( - <> - - {offerObj?.offerCount !== 0 && ( - - - - )} + <> + + {offerObj?.offerCount > 1 && ( - {t('dialog.offerDetails.cofirmTermsSubtitle')} - {offerObj ? {splitWithFirstOcc(offerObj.provider)} : '-.'} + - {t('dialog.offerDetails.confirmHeading')} + )} + + {t('dialog.offerDetails.cofirmTermsSubtitle')} + {offerObj ? {splitWithFirstOcc(offerObj.provider)} : '-.'} - (1) {t('dialog.offerDetails.point1')} - (2) {t('dialog.offerDetails.point2')} - (3) {t('dialog.offerDetails.point3')} - setIsAgreed(!isAgreed)} name="gilad" />} - label={t('content.common.agree')} - /> - - )} + {t('dialog.offerDetails.confirmHeading')} + + (1) {t('dialog.offerDetails.point1')} + (2) {t('dialog.offerDetails.point2')} + (3) {t('dialog.offerDetails.point3')} + setIsAgreed(!isAgreed)} name="gilad" />} + label={t('content.common.agree')} + /> + - void; - handleClose?: (state: boolean) => void; isMultiple?: boolean; } -const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMultiple }: IntDialogProps) => { - const [offer] = useState(offerObj); +const OfferDetailsDialog = ({ offerObj, isMultiple }: IntDialogProps) => { const { title, - created, description, + sematicVersion, publisher, + connectorOfferUrl, policy: { Usage: usagePolicies }, - fileContentType, - } = offer; + } = offerObj ?? ({} as IConsumerDataOffers); + const { t } = useTranslation(); + const { openOfferDetailsDialog } = useAppSelector(state => state.consumerSlice); + + const dispatch = useAppDispatch(); - function splitWithFirstOcc(str: string) { - const regX = /:(.*)/s; - return str.split(regX); - } + const renderDetailItem = (label: string, value: string) => ( + + {label} + + {value || '-'} + + + ); return ( - - handleClose(false)} title={t('dialog.offerDetails.title')} /> + + dispatch(setOpenOfferDetailsDialog(false))} + title={t('dialog.offerDetails.title')} + /> {isMultiple ? ( @@ -69,42 +78,11 @@ const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMult ) : ( - - {t('dialog.offerDetails.titleText')} - - {title || '-'} - - - - {t('dialog.offerDetails.created')} - - {created || '-'} - - - - {t('dialog.offerDetails.dataFormat')} - - {fileContentType || '-'} - - - - {t('dialog.offerDetails.description')} - - {description || '-'} - - - - {t('dialog.offerDetails.publisher')} - - {splitWithFirstOcc(publisher)[0] || '-'} - - - - {t('dialog.offerDetails.publisherUrl')} - - {splitWithFirstOcc(publisher)[1] || '-'} - - + {renderDetailItem(t('dialog.offerDetails.titleText'), title)} + {renderDetailItem(t('dialog.offerDetails.sematicVersion'), sematicVersion)} + {renderDetailItem(t('dialog.offerDetails.description'), description)} + {renderDetailItem(t('dialog.offerDetails.publisher'), publisher)} + {renderDetailItem(t('dialog.offerDetails.publisherUrl'), connectorOfferUrl)} @@ -118,11 +96,11 @@ const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMult )} - - diff --git a/src/features/consumer/apiSlice.ts b/src/features/consumer/apiSlice.ts new file mode 100644 index 00000000..3ba6ba8a --- /dev/null +++ b/src/features/consumer/apiSlice.ts @@ -0,0 +1,39 @@ +/******************************************************************************** + * Copyright (c) 2024 T-Systems International GmbH + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +import { setLoadingHandler } from '../../helpers/ApiHelper'; +import { apiSlice } from '../app/apiSlice'; + +export const consumerApiSlice = apiSlice.injectEndpoints({ + endpoints: builder => ({ + getOfferPolicyDetails: builder.mutation({ + query: body => { + return { + url: '/offer-policy-details', + method: 'POST', + body, + }; + }, + onQueryStarted: setLoadingHandler, + }), + }), +}); + +export const { useGetOfferPolicyDetailsMutation } = consumerApiSlice; diff --git a/src/features/consumer/slice.ts b/src/features/consumer/slice.ts index 74ce7b65..610cd3ce 100644 --- a/src/features/consumer/slice.ts +++ b/src/features/consumer/slice.ts @@ -1,6 +1,6 @@ /******************************************************************************** - * Copyright (c) 2021,2022,2023 T-Systems International GmbH - * Copyright (c) 2022,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2022,2024 T-Systems International GmbH + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -41,6 +41,8 @@ const initialState: IConsumerSlice = { filterSelectedConnector: {}, contractAgreements: [], isContractAgreementsLoading: false, + openOfferDetailsDialog: false, + openOfferConfirmDialog: false, }; export const consumerSlice = createSlice({ @@ -109,6 +111,12 @@ export const consumerSlice = createSlice({ setIsContractAgreementsLoading: (state, action: PayloadAction) => { state.isContractAgreementsLoading = action.payload; }, + setOpenOfferDetailsDialog: (state, action: PayloadAction) => { + state.openOfferDetailsDialog = action.payload; + }, + setOpenOfferConfirmDialog: (state, action: PayloadAction) => { + state.openOfferConfirmDialog = action.payload; + }, }, }); @@ -128,5 +136,7 @@ export const { setFilterSelectedBPN, setContractAgreements, setIsContractAgreementsLoading, + setOpenOfferDetailsDialog, + setOpenOfferConfirmDialog, } = consumerSlice.actions; export default consumerSlice.reducer; diff --git a/src/features/consumer/types.ts b/src/features/consumer/types.ts index 408b92cd..11519964 100644 --- a/src/features/consumer/types.ts +++ b/src/features/consumer/types.ts @@ -20,7 +20,6 @@ ********************************************************************************/ export interface IUsageControl { - type: string; typeOfAccess: string; value?: string; durationUnit?: string | Record; @@ -51,6 +50,7 @@ export interface IConsumerDataOffers { usagePolicies: IUsageControl[]; fileName?: string; fileContentType?: string; + sematicVersion: string; } export interface ILegalEntityName { value?: string; @@ -128,4 +128,6 @@ export interface IConsumerSlice { filterSelectedConnector: Partial; contractAgreements: IContractAgreements[]; isContractAgreementsLoading: boolean; + openOfferDetailsDialog: boolean; + openOfferConfirmDialog: boolean; } diff --git a/src/pages/ConsumeData.tsx b/src/pages/ConsumeData.tsx index 418032b9..c30cd4b5 100644 --- a/src/pages/ConsumeData.tsx +++ b/src/pages/ConsumeData.tsx @@ -38,7 +38,7 @@ import { SelectList, Typography, } from 'cx-portal-shared-components'; -import { debounce, isEmpty } from 'lodash'; +import { debounce, isEmpty, isEqual, map, pick } from 'lodash'; import React, { ChangeEvent, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { v4 as uuid } from 'uuid'; @@ -47,6 +47,7 @@ import ConfirmTermsDialog from '../components/dialogs/ConfirmTermsDialog'; import OfferDetailsDialog from '../components/dialogs/OfferDetailsDialog'; import NoDataPlaceholder from '../components/NoDataPlaceholder'; import Permissions from '../components/Permissions'; +import { useGetOfferPolicyDetailsMutation } from '../features/consumer/apiSlice'; import { setContractOffers, setFfilterCompanyOptionsLoading, @@ -57,6 +58,8 @@ import { setFilterSelectedConnector, setIsMultipleContractSubscription, setOffersLoading, + setOpenOfferConfirmDialog, + setOpenOfferDetailsDialog, setSearchFilterByType, setSelectedFilterCompanyOption, setSelectedOffer, @@ -71,7 +74,7 @@ import { } from '../features/consumer/types'; import { setSnackbarMessage } from '../features/notifiication/slice'; import { useAppDispatch, useAppSelector } from '../features/store'; -import { arraysEqual, handleBlankCellValues, MAX_CONTRACTS_AGREEMENTS } from '../helpers/ConsumerOfferHelper'; +import { handleBlankCellValues, MAX_CONTRACTS_AGREEMENTS } from '../helpers/ConsumerOfferHelper'; import ConsumerService from '../services/ConsumerService'; const ITEMS: IntConnectorItem[] = [ @@ -106,10 +109,9 @@ export default function ConsumeData() { filterConnectors, filterSelectedConnector, filterSelectedBPN, + openOfferDetailsDialog, } = useAppSelector(state => state.consumerSlice); - const [isOpenOfferDialog, setIsOpenOfferDialog] = useState(false); - const [isOpenOfferConfirmDialog, setIsOpenOfferConfirmDialog] = useState(false); - const [isOfferSubLoading, setIsOfferSubLoading] = useState(false); + const [offerSubLoading, setOfferSubLoading] = useState(false); const [pageSize, setPageSize] = useState(10); const [selectionModel, setSelectionModel] = React.useState([]); const [searchOpen, setSearchOpen] = useState(false); @@ -119,24 +121,28 @@ export default function ConsumeData() { const dispatch = useAppDispatch(); const { t } = useTranslation(); + const [getPolicyDetails] = useGetOfferPolicyDetailsMutation(); + const columns: GridColDef[] = [ { field: 'title', flex: 1, headerName: t('content.consumeData.columns.title'), }, + { + field: 'publisher', + flex: 1, + headerName: t('content.consumeData.columns.publisher'), + }, { field: 'assetId', flex: 1, headerName: t('content.consumeData.columns.assetId'), }, { - field: 'created', + field: 'sematicVersion', flex: 1, - headerName: t('content.consumeData.columns.created'), - sortingOrder: ['desc', 'asc'], - sortComparator: (_v1: any, _v2: any, param1: any, param2: any) => param1.id - param2.id, - valueGetter: (params: GridValueGetterParams) => handleBlankCellValues(params.row.created), + headerName: t('content.consumeData.columns.sematicVersion'), }, { field: 'description', @@ -148,7 +154,7 @@ export default function ConsumeData() { ]; const toggleDialog = (flag: boolean) => { - setIsOpenOfferDialog(flag); + dispatch(setOpenOfferDetailsDialog(flag)); if (flag === false) { dispatch(setSelectedOffer(null)); } @@ -171,11 +177,11 @@ export default function ConsumeData() { const handleConfirmTermDialog = async () => { try { - setIsOfferSubLoading(true); + setOfferSubLoading(true); const handleSuccess = () => { - setIsOpenOfferDialog(false); - setIsOpenOfferConfirmDialog(false); + dispatch(setOpenOfferDetailsDialog(false)); + dispatch(setOpenOfferConfirmDialog(false)); dispatch(setIsMultipleContractSubscription(false)); dispatch(setSelectedOffer(null)); dispatch(setSelectedOffersList([])); @@ -188,22 +194,13 @@ export default function ConsumeData() { dispatch(setSnackbarMessage({ message: 'alerts.subscriptionSuccess', type: 'success' })); handleSuccess(); } - setIsOpenOfferDialog(false); - setIsOpenOfferConfirmDialog(false); - dispatch(setIsMultipleContractSubscription(false)); - dispatch(setSelectedOffer(null)); - dispatch(setSelectedOffersList([])); - setSelectionModel([]); } catch (e) { console.log(e); + } finally { + setOfferSubLoading(false); } }; - const onRowClick = (params: any) => { - dispatch(setSelectedOffer(params.row)); - toggleDialog(true); - }; - const fetchConsumerDataOffers = async () => { try { let providerUrl = ''; @@ -217,6 +214,7 @@ export default function ConsumeData() { } dispatch(setOffersLoading(true)); const response = await ConsumerService.getInstance().fetchConsumerDataOffers({ + bpnNumber: 'BPNL000MEHRAN010', providerUrl: providerUrl, offset: 0, maxLimit: MAX_CONTRACTS_AGREEMENTS, @@ -240,35 +238,44 @@ export default function ConsumeData() { setdialogOpen(prev => !prev); }; - const checkoutSelectedOffers = () => { - if (selectedOffersList.length === 1) { - dispatch(setSelectedOffer(selectedOffersList[0])); - toggleDialog(true); - return; - } - let isUsagePoliciesEqual = false; - const useCasesList: any[] = []; - selectedOffersList.forEach((offer: IConsumerDataOffers) => { - if (offer.usagePolicies.length > 0) { - useCasesList.push(offer.usagePolicies); + const checkoutSelectedOffers = async (offers: IConsumerDataOffers[]) => { + try { + const extractedData = map(offers, item => pick(item, ['assetId', 'connectorOfferUrl'])); + const offerDetails = await getPolicyDetails(extractedData).unwrap(); + const mergeSelectedOffers: IConsumerDataOffers[] = offerDetails.map((policyOffer: IConsumerDataOffers) => ({ + ...policyOffer, + ...offers.find((orgOffer: IConsumerDataOffers) => orgOffer.assetId === policyOffer.assetId), + })); + dispatch(setSelectedOffersList(mergeSelectedOffers)); + + if (offerDetails.length === 1) { + dispatch(setIsMultipleContractSubscription(false)); + dispatch(setSelectedOffer(mergeSelectedOffers[0])); + toggleDialog(true); + return; + } + + const usagePolicies: IConsumerDataOffers[] = offerDetails.map((offer: IConsumerDataOffers) => + isEmpty(offer.policy.Usage) ? [] : offer.policy.Usage, + ); + const isUsagePoliciesEqual = usagePolicies.every((item, index, array) => isEqual(item, array[0])); + if (isUsagePoliciesEqual) { + dispatch(setOpenOfferDetailsDialog(true)); + dispatch(setIsMultipleContractSubscription(true)); } else { - useCasesList.push([]); + dispatch(setOpenOfferDetailsDialog(false)); + showAddDialog(); + dispatch(setIsMultipleContractSubscription(false)); } - }); - useCasesList.forEach(useCase => { - if (arraysEqual(useCasesList[0], useCase)) isUsagePoliciesEqual = true; - else isUsagePoliciesEqual = false; - }); - if (isUsagePoliciesEqual) { - setIsOpenOfferDialog(true); - dispatch(setIsMultipleContractSubscription(true)); - } else { - showAddDialog(); - setIsOpenOfferDialog(false); - dispatch(setIsMultipleContractSubscription(false)); + } catch (error) { + console.log('getPolicyDetails', error); } }; + const onRowClick = (params: GridValidRowModel) => { + checkoutSelectedOffers([params.row]); + }; + // get company name oninput change const onChangeSearchInputValue = async (params: string) => { const searchStr = params.toLowerCase(); @@ -383,8 +390,23 @@ export default function ConsumeData() { else setBpnError(true); }, [filterSelectedBPN]); + const renderOfferDialogs = (offerObj: IConsumerDataOffers, offerCount: number) => ( + <> + 1} /> + 0 ? [offerObj] : [], + provider: offerObj?.publisher || '', + offerCount: offerCount, + }} + isProgress={offerSubLoading} + handleConfirm={handleConfirmTermDialog} + /> + + ); + return ( - + <> {t('pages.consumeData')} @@ -506,7 +528,7 @@ export default function ConsumeData() { checkoutSelectedOffers(selectedOffersList)} disabled={!selectedOffersList.length} > {t('button.subscribeSelected')} @@ -544,23 +566,18 @@ export default function ConsumeData() { rowsPerPageOptions={[10, 25, 50, 100]} onSelectionModelChange={newSelectionModel => handleSelectionModel(newSelectionModel)} selectionModel={selectionModel} + isRowSelectable={params => params.row.type !== 'PCFExchangeEndpoint'} components={{ Toolbar: GridToolbar, LoadingOverlay: LinearProgress, NoRowsOverlay: () => NoDataPlaceholder('content.common.noData'), NoResultsOverlay: () => NoDataPlaceholder('content.common.noResults'), }} - componentsProps={{ - toolbar: { - showQuickFilter: true, - quickFilterProps: { debounceMs: 500 }, - printOptions: { disableToolbarButton: true }, - }, - }} disableColumnMenu disableColumnSelector disableDensitySelector disableSelectionOnClick + disableColumnFilter sx={{ '& .MuiDataGrid-columnHeaderTitle': { textOverflow: 'clip', @@ -575,49 +592,7 @@ export default function ConsumeData() { /> - {isMultipleContractSubscription && ( - <> - - - - )} - {selectedOffer && ( - <> - - - - )} + {openOfferDetailsDialog && renderOfferDialogs(selectedOffersList[0], selectedOffersList.length)} {t('dialog.samePolicies.content')} @@ -627,6 +602,6 @@ export default function ConsumeData() { - + ); } diff --git a/src/tests/ConfirmTermsDialog.test.tsx b/src/tests/ConfirmTermsDialog.test.tsx index 50c5a250..3a3ecc13 100644 --- a/src/tests/ConfirmTermsDialog.test.tsx +++ b/src/tests/ConfirmTermsDialog.test.tsx @@ -1,6 +1,6 @@ /******************************************************************************** - * Copyright (c) 2021,2022,2023 T-Systems International GmbH - * Copyright (c) 2022,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 T-Systems International GmbH + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -38,6 +38,7 @@ const offerObj = { modified: '22/07/2022', offerInfo: 'offer extra info', typeOfAccess: 'restricted', + sematicVersion: 'urn:bamm:io.catenax.serial_part:1.0.0#SerialPart', usagePolicies: [ { type: 'Duration', @@ -52,8 +53,7 @@ const offerObj = { }; describe('ConfirmTermsDialog Component', () => { - const isOpen = true; - const { getByRole, getByText } = render(); + const { getByRole, getByText } = render(); const confirmButton = getByRole('button', { name: 'Confirm' }); const checkbox = getByRole('checkbox'); const heading = getByText('Confirm', { selector: 'h2' }); diff --git a/src/tests/OfferDetailsDialog.test.tsx b/src/tests/OfferDetailsDialog.test.tsx index 6a56041e..b6b7fa5d 100644 --- a/src/tests/OfferDetailsDialog.test.tsx +++ b/src/tests/OfferDetailsDialog.test.tsx @@ -1,6 +1,6 @@ /******************************************************************************** - * Copyright (c) 2021,2022,2023 T-Systems International GmbH - * Copyright (c) 2022,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2022,2024 T-Systems International GmbH + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -24,7 +24,6 @@ import OfferDetailsDialog from '../components/dialogs/OfferDetailsDialog'; import { IConsumerDataOffers } from '../features/consumer/types'; test('Snapshot OfferDetailsDialog - load and diaplay offer details component', () => { - const isOpen = true; const offerItem: IConsumerDataOffers = { bpnNumbers: ['BPN1', 'BPN2'], connectorOfferid: 'connector1', @@ -38,15 +37,15 @@ test('Snapshot OfferDetailsDialog - load and diaplay offer details component', ( modified: '22/07/2022', offerInfo: 'offer extra info', typeOfAccess: 'restricted', + sematicVersion: 'urn:bamm:io.catenax.serial_part:1.0.0#SerialPart', usagePolicies: [ { - type: 'Duration', typeOfAccess: 'Unrestricted', value: '1', }, ], }; - render(); + render(); const text = screen.getByText('Offer Details'); const titleText = screen.getByText(offerItem.title); expect(text).toBeInTheDocument(); diff --git a/src/utils/utils.tsx b/src/utils/utils.tsx index f3f7c949..9285497a 100644 --- a/src/utils/utils.tsx +++ b/src/utils/utils.tsx @@ -60,3 +60,8 @@ export const toReadableCapitalizedCase = (input: string): string => { const parts = input.replace(/\./g, ' ').split(' '); return parts.map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(' '); }; + +export function splitWithFirstOcc(str: string) { + const regX = /:(.*)/s; + return str.split(regX) ? `${str.split(regX)[0]}.` : '-.'; +} From f43d7889c0cf64dcb1479197b29227f417b271cd Mon Sep 17 00:00:00 2001 From: "ajithkumar.s" Date: Wed, 3 Apr 2024 16:13:49 +0530 Subject: [PATCH 4/5] hardcoded values removed --- src/pages/ConsumeData.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ConsumeData.tsx b/src/pages/ConsumeData.tsx index c30cd4b5..ce4435dd 100644 --- a/src/pages/ConsumeData.tsx +++ b/src/pages/ConsumeData.tsx @@ -214,7 +214,6 @@ export default function ConsumeData() { } dispatch(setOffersLoading(true)); const response = await ConsumerService.getInstance().fetchConsumerDataOffers({ - bpnNumber: 'BPNL000MEHRAN010', providerUrl: providerUrl, offset: 0, maxLimit: MAX_CONTRACTS_AGREEMENTS, From 0ff2070e9730712ef8f03d58ea5e09ecc918137d Mon Sep 17 00:00:00 2001 From: "ajithkumar.s" Date: Thu, 4 Apr 2024 17:07:19 +0530 Subject: [PATCH 5/5] changelog updated --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b955535f..ff768c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ New features, fixed bugs, known defects and other noteworthy changes to each rel ### Changed - Upload data api implemetation moved to RTK query for better performance. +- Consumer: Fetching policy information from EDC for offer details overlay ## [2.3.6] - 2024-03-08 ### Added