diff --git a/.conf/Dockerfile.full b/.conf/Dockerfile.full index c64a5540d..abf570fcb 100644 --- a/.conf/Dockerfile.full +++ b/.conf/Dockerfile.full @@ -29,7 +29,6 @@ FROM node:22-alpine as build-step ARG http_proxy=$http_proxy ARG https_proxy=$https_proxy ARG no_proxy=$no_proxy -RUN apk update && apk add --no-cache jq COPY . /app WORKDIR /app RUN yarn @@ -48,8 +47,6 @@ RUN ln -s /tmp/index.html /usr/share/nginx/html/index.html # Add env variables inject script and mark as executable COPY ./scripts/inject-dynamic-env.sh /docker-entrypoint.d/00-inject-dynamic-env.sh RUN chmod +x /docker-entrypoint.d/00-inject-dynamic-env.sh -# Install bash for env variables inject script -RUN apk update && apk add --no-cache bash # Make nginx owner of /usr/share/nginx/html/ and change to nginx user RUN chown -R 101:101 /usr/share/nginx/html/ # Change to nginx user diff --git a/.conf/Dockerfile.prebuilt b/.conf/Dockerfile.prebuilt index 916451381..b1b04e4f0 100644 --- a/.conf/Dockerfile.prebuilt +++ b/.conf/Dockerfile.prebuilt @@ -38,8 +38,6 @@ RUN ln -s /tmp/index.html /usr/share/nginx/html/index.html # Add env variables inject script and mark as executable COPY ./scripts/inject-dynamic-env.sh /docker-entrypoint.d/00-inject-dynamic-env.sh RUN chmod +x /docker-entrypoint.d/00-inject-dynamic-env.sh -# Install bash for env variables inject script -RUN apk update && apk add --no-cache bash # Make nginx owner of /usr/share/nginx/html/ and change to nginx user RUN chown -R 101:101 /usr/share/nginx/html/ # Change to nginx user diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ad07249..cb1390857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,49 @@ - **Onboarding Service Provider** - add missing fields to form legal name & company identifier[#1151](https://github.com/eclipse-tractusx/portal-frontend/pull/1151) -## 2.2.0-alpha.1 +### Feature + +- **Clearinghouse Self-Description** + - Admin UI for Managing SD Document Retriggering [#1141](https://github.com/eclipse-tractusx/portal-frontend/pull/1141) + +### Technical Support + +- **Injection of environment variables to Docker image** + - refactored to a more readable and typo resistant implementation using sh - bash and jq are no longer required in image [#914](https://github.com/eclipse-tractusx/portal-frontend/pull/914) + +### Change + +- **Service Subscriptions** + - rename 'Configure' button to 'Activate' button [#1150](https://github.com/eclipse-tractusx/portal-frontend/pull/1150) + +## 2.3.0-alpha.2 + +### Change + +- **Technical User Details** + - updated technical user details with user type and service endpoint fields. Also, updated copy icon color for better view and made copy icon available only when value is available [#1137](https://github.com/eclipse-tractusx/portal-frontend/pull/1137) +- **Company Subscriptions** + - update API query parameters and fix tab UI scroll [#1131](https://github.com/eclipse-tractusx/portal-frontend/pull/1131) +- **App & Service Subscription Management** + - updated search place holder text - showing only available offer names at the top - and implemented hover information on the status icon of service subscription [#1130](https://github.com/eclipse-tractusx/portal-frontend/pull/1130) +- **Customer Data** + - re-enabled CSV upload [#1144](https://github.com/eclipse-tractusx/portal-frontend/pull/1144) + - reverted manual intervention with ready state api [#1144](https://github.com/eclipse-tractusx/portal-frontend/pull/1144) +- **Onboarding Service Provider** + - enhanced permission and company role validation for Onboarding Service Provider [#1176](https://github.com/eclipse-tractusx/portal-frontend/pull/1176) + +### Bugfixes + +- **Connector Management** + - fixed overlay enabling on click of managed connectors(details) [#1142](https://github.com/eclipse-tractusx/portal-frontend/pull/1142) +- **Connector Management** + - fixed customer link selection and fixed resetting values [#1119](https://github.com/eclipse-tractusx/portal-frontend/pull/1119) +- **Technical User Management** + - fixed error message scenario post technical user deletion action [#1164](https://github.com/eclipse-tractusx/portal-frontend/pull/1164) +- **Company Subscriptions** + - fixed incorrect data display in service company subscriptions [#1191](https://github.com/eclipse-tractusx/portal-frontend/pull/1191) + +## 2.3.0-alpha.1 ### Bugfixes diff --git a/index.html b/index.html index ef42715e5..c0b7dec55 100644 --- a/index.html +++ b/index.html @@ -28,8 +28,26 @@
diff --git a/package.json b/package.json index 4e41e25fd..3a513be6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@catena-x/portal-frontend", - "version": "v2.3.0-alpha.1", + "version": "v2.3.0-alpha.2", "description": "Catena-X Portal Frontend", "author": "Catena-X Contributors", "license": "Apache-2.0", diff --git a/scripts/inject-dynamic-env.sh b/scripts/inject-dynamic-env.sh old mode 100644 new mode 100755 index dfa698eb2..cd33257b2 --- a/scripts/inject-dynamic-env.sh +++ b/scripts/inject-dynamic-env.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh ############################################################### # Copyright (c) 2022 Contributors to the Eclipse Foundation @@ -19,13 +19,41 @@ # SPDX-License-Identifier: Apache-2.0 ############################################################### -# Define custom variable -custom_env_vars='{REQUIRE_HTTPS_URL_PATTERN:"'$REQUIRE_HTTPS_URL_PATTERN'",PORTAL_ASSETS_URL:"'$PORTAL_ASSETS_URL'",PORTAL_BACKEND_URL:"'$PORTAL_BACKEND_URL'",CENTRALIDP_URL:"'$CENTRALIDP_URL'",SSI_CREDENTIAL_URL:"'$SSI_CREDENTIAL_URL'",BPDM_POOL_API_URL:"'$BPDM_POOL_API_URL'",BPDM_GATE_API_URL:"'$BPDM_GATE_API_URL'",SEMANTICS_URL:"'$SEMANTICS_URL'",MANAGED_IDENTITY_WALLETS_NEW_URL:"'$MANAGED_IDENTITY_WALLETS_NEW_URL'",REALM:"'$REALM'",CLIENT_ID:"'$CLIENT_ID'",CLIENT_ID_REGISTRATION:"'$CLIENT_ID_REGISTRATION'",CLIENT_ID_SEMANTIC:"'$CLIENT_ID_SEMANTIC'",CLIENT_ID_BPDM:"'$CLIENT_ID_BPDM'",CLIENT_ID_MIW:"'$CLIENT_ID_MIW'",CLIENT_ID_SSI_CREDENTIAL:"'$CLIENT_ID_SSI_CREDENTIAL'"}' -# Define anchor variable -custom_env_vars_anchor='{REQUIRE_HTTPS_URL_PATTERN:"true",PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",SSI_CREDENTIAL_URL:"https://ssi-credential-issuer.example.org",BPDM_POOL_API_URL:"https://business-partners.example.org/pool/v6",BPDM_GATE_API_URL:"https://business-partners.example.org/companies/test-company/v6",SEMANTICS_URL:"https://semantics.example.org",MANAGED_IDENTITY_WALLETS_NEW_URL:"https://managed-identity-wallets-new.example.org",REALM:"CX-Central",CLIENT_ID:"Cl2-CX-Portal",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration",CLIENT_ID_SEMANTIC:"Cl3-CX-Semantic",CLIENT_ID_BPDM:"Cl7-CX-BPDM",CLIENT_ID_MIW:"Cl5-CX-Custodian",CLIENT_ID_SSI_CREDENTIAL:"Cl24-CX-SSI-CredentialIssuer"}' -# Read content of the reference index.html file into the index_html_reference variable -index_html_reference=`cat /usr/share/nginx/html/index.html.reference` -# Replace the anchor variable with the custom variable in the index.html file -index_html=${index_html_reference//$custom_env_vars_anchor/$custom_env_vars} -# Write the modified index.html to tmp (to enable readOnlyRootFilesystem) -echo "$index_html" > /tmp/index.html +source_file=/usr/share/nginx/html/index.html.reference +target_file=/tmp/index.html + +# these environment variables should be set and match the ones in index.html +# sequence is irrelevant +vars=" \ +REQUIRE_HTTPS_URL_PATTERN \ +CLEARINGHOUSE_CONNECT_DISABLED \ +CENTRALIDP_URL \ +PORTAL_ASSETS_URL \ +PORTAL_BACKEND_URL \ +SEMANTICS_URL \ +BPDM_GATE_API_URL \ +BPDM_POOL_API_URL \ +SSI_CREDENTIAL_URL \ +MANAGED_IDENTITY_WALLETS_NEW_URL \ +REALM \ +CLIENT_ID \ +CLIENT_ID_REGISTRATION \ +CLIENT_ID_SEMANTIC \ +CLIENT_ID_BPDM \ +CLIENT_ID_MIW \ +CLIENT_ID_SSI_CREDENTIAL \ +" + +# base sed command: output source file and remove javascript comments +sed_command="cat ${source_file} | sed -e \"s@^\\\s*//.*@@g\"" + +set -- $vars +while [ -n "$1" ]; do + var=$1 + # add a replace expression for each variable + sed_command="${sed_command} -e \"s@${var}:\s*\\\".*\\\"@${var}: \\\"\${${var}}\\\"@g\"" + shift +done + +# execute the built replace command and write to target file +echo ${sed_command} | sh > ${target_file} diff --git a/src/assets/locales/de/main.json b/src/assets/locales/de/main.json index 9517608c6..f193e4f1e 100644 --- a/src/assets/locales/de/main.json +++ b/src/assets/locales/de/main.json @@ -624,7 +624,7 @@ "configureYourConnectorDetails": "Konfigurieren Sie die Connector-Details", "learnMore": "Learn More", "noDocumentAvailable": "Kein Dokument verfügbar", - "selfDescriptionDocument": "Selbstbeschreibungsdokument", + "selfDescriptionDocument": "Eigenerklärungsdokument", "deleteConnector": "Connector löschen", "urlUpdatedSuccessfully": "URL erfolgreich aktualisiert", "note": "Bitte beachten Sie:", @@ -676,7 +676,7 @@ "deletemodal": { "title": "EDC-Connector Löschen", "description": "Möchten Sie den ausgewählten Connector wirklich löschen? Die Löschung kann nicht rückgängig gemacht werden.", - "techUserdescription": "Möchten Sie den Connector wirklich löschen? Mit der Löschung wird der Connector automatisch vom Endpunkt „Connector Discovery“ gelöscht und das Selbstbeschreibungsdokument auf inaktiv gesetzt.\n Bitte beachten Sie, dass mit dem Connector ein technischer Benutzer verbunden ist. Der technische Benutzer kann gelöscht werden, wenn Sie das Kontrollkästchen unten aktivieren. Andernfalls wird nur die Zuordnung zwischen Connector und technischem Benutzer gelöscht.", + "techUserdescription": "Möchten Sie den Connector wirklich löschen? Mit der Löschung wird der Connector automatisch vom Endpunkt „Connector Discovery“ gelöscht und das Eigenerklärungsdokument auf inaktiv gesetzt.\n Bitte beachten Sie, dass mit dem Connector ein technischer Benutzer verbunden ist. Der technische Benutzer kann gelöscht werden, wenn Sie das Kontrollkästchen unten aktivieren. Andernfalls wird nur die Zuordnung zwischen Connector und technischem Benutzer gelöscht.", "techUserCheckBoxLabel": "Ja, ich möchte den Connector löschen, wodurch automatisch auch der erwähnte technische Benutzer gelöscht wird.", "techDetails": { "title": "Technical Details", @@ -1066,6 +1066,18 @@ "metadata_url_required_error": "Metadaten-URL ist erforderlich", "metadata_url_invalid_error": "Bitte geben Sie eine gültige Metadaten-URL ein" }, + "clearinghouseSelfDescription": { + "heading": "Status der Eigenerklärung", + "description": "Diese Seite bietet einen Überblick über den aktuellen Stand der Eigenerklärungen für Administratoren.", + "reprocess": "Nachverarbeiten", + "complianceStatus": "Compliance-Status:", + "legalPerson": "Juristische Person", + "legalPersonDesc": "Übersicht über Unternehmen mit fehlender Eigenerklärung einer juristischen Person", + "connectors": "Connectors", + "connectorsDesc": "Übersicht über Unternehmen mit fehlender Eigenerklärung der Konnektoren", + "errorMsg": "Fehler! Etwas ist schief gelaufen", + "noDataMsg": "Keine Datensätze gefunden." + }, "addUser": { "headline": "Erstelle einen neuen User", "subheadline": "Fügen Sie ein neues Benutzerkonto hinzu, indem Sie den Vor- und Nachnamen des Benutzers sowie die E-Mail-Adresse hinterlegen. Wählen Sie unterhalb der Eingabefelder die jeweiligen Benutzerrollen aus, die der Benutzer haben soll. Eine Rolle ist mindestens erforderlich, um dem Benutzer den Zugriff auf das Netzwerk zu ermöglichen.", @@ -1483,11 +1495,13 @@ "recommendations": "Recommendations", "allServices": "All Services", "viewDetails": "Display more details", - "activateBtn": "Activate", - "configureBtn": "Configure", + "activateBtn": "Aktivieren", "pleaseEnterValidURL": "Please enter a valid URL", "error": "Error", "success": "Success", + "pending": "Das Abonnement steht noch aus", + "active": "Das Abonnement ist aktiv", + "process": "Das Abonnement ist in Bearbeitung", "tabs": { "request": "Request", "active": "Active", @@ -1840,7 +1854,7 @@ }, "SKIPPED": { "title": "Von Ihrer Seite sind keine Maßnahmen erforderlich", - "description": "Die Erstellung der Selbstbeschreibung wurde absichtlich übersprungen. Dieser Prozess wird vom CX-Operator so bald wie möglich wieder ausgelöst." + "description": "Die Erstellung der Eigenerklärung wurde absichtlich übersprungen. Dieser Prozess wird vom CX-Operator so bald wie möglich wieder ausgelöst." } } }, diff --git a/src/assets/locales/en/main.json b/src/assets/locales/en/main.json index 06080b3b2..2a7e6ea43 100644 --- a/src/assets/locales/en/main.json +++ b/src/assets/locales/en/main.json @@ -21,6 +21,7 @@ "technicalSetup": "Technical Integration", "connectorManagement": "Connector Management", "applicationRequests": "Application Requests", + "clearinghouseSelfDescription": "Clearinghouse Self-Description", "admin": "Administration", "developer": "Development", "invite": "Invite Business Partner", @@ -1070,6 +1071,18 @@ "metadata_url_required_error": "Metadata url is required", "metadata_url_invalid_error": "Please enter valid metadata url" }, + "clearinghouseSelfDescription": { + "heading": "Self-Description Document Status", + "description": "This page provides an overview of the current status of self-descriptions for administrators.", + "reprocess": "Reprocess", + "complianceStatus": "Compliance Status:", + "legalPerson": "Legal Person", + "legalPersonDesc": "Overview of companies with missing legal person self-description", + "connectors": "Connectors", + "connectorsDesc": "Overview of companies with missing connector self-description", + "errorMsg": "Error! Something went wrong", + "noDataMsg": "No records found." + }, "addUser": { "headline": "Add User Account", "subheadline": "Add a new user account by adding the user first and last name as well as the email address. Below the input fields select the respective user roles which the user should have. One role is minimum needed to enable the user to access the network.", @@ -1452,10 +1465,12 @@ "allServices": "All Services", "viewDetails": "Display more details", "activateBtn": "Activate", - "configureBtn": "Configure", "pleaseEnterValidURL": "Please enter a valid URL", "error": "Error", "success": "Success", + "pending": "Subscription is Pending", + "active": "Subscription is Active", + "process": "Subscription is in Progress", "tabs": { "request": "Request", "active": "Active", diff --git a/src/components/overlays/AddTechnicalUser/TechnicalUserAddForm.scss b/src/components/overlays/AddTechnicalUser/TechnicalUserAddForm.scss index cadb2928b..4d2f7054a 100644 --- a/src/components/overlays/AddTechnicalUser/TechnicalUserAddForm.scss +++ b/src/components/overlays/AddTechnicalUser/TechnicalUserAddForm.scss @@ -37,7 +37,6 @@ display: grid; .roleDescription { - line-height: 0; - margin: 5px 27px 20px; + margin: -5px 27px 10px; } } diff --git a/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSD.scss b/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSD.scss new file mode 100644 index 000000000..5734acbbd --- /dev/null +++ b/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSD.scss @@ -0,0 +1,107 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +.admin-container { + padding: 50px 15px; + + .loading-progress { + display: flex; + justify-content: center; + align-items: center; + height: 50vh; + } + + .heading { + text-align: center; + } + + .description { + text-align: center; + margin: 34px auto 64px; + width: 70%; + } + + .company-list-container { + max-height: 350px; + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; + } + + .section { + margin-bottom: 20px; + + ul { + margin-top: 24px; + list-style-type: none; + padding-left: 0; + + li { + margin-bottom: 5px; + } + } + + .connectors-list { + gap: 10px; + margin-top: 24px; + max-height: 350px; + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; + + .connector { + display: flex; + gap: 80px; + padding: 5px; + border-radius: 5px; + } + } + + .btn-container { + display: flex; + margin-top: 20px; + align-items: flex-end; + justify-content: flex-end; + } + } + + .compliance-status { + display: flex; + align-items: center; + margin-bottom: 40px; + margin-top: 50px; + + label { + margin-right: 10px; + font-weight: bold; + } + + .switch-container { + display: flex; + align-items: center; + margin-left: 5px; + } + } + + .no-data-msg { + text-align: center; + margin-top: 24px; + margin-bottom: 24px; + } +} diff --git a/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSDElements.tsx b/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSDElements.tsx new file mode 100644 index 000000000..f37786ad9 --- /dev/null +++ b/src/components/pages/AdminClearingHouseSD/AdminClearingHouseSDElements.tsx @@ -0,0 +1,350 @@ +/******************************************************************************** + * 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 { useEffect, useState } from 'react' +import './AdminClearingHouseSD.scss' +import { Trans } from 'react-i18next' +import { t } from 'i18next' +import { + Button, + CircleProgress, + ToggleSwitch, + Typography, +} from '@catena-x/portal-shared-components' +import { + type ComapnyDataType, + useFetchCompanyDataQuery, + useFetchConnectorsQuery, + useTriggerCompanyDataMutation, + useTriggerConnectorsMutation, + PAGE_SIZE, +} from 'features/adminClearingHouseSD/adminClearingHouseSDApiSlice' +import { error } from 'services/NotifyService' +import { isClearinghouseConnectDisabled } from 'services/EnvironmentService' + +const AdminclearinghouseSDElements = () => { + const [checked, setChecked] = useState(isClearinghouseConnectDisabled()) + const [triggerCompanyData] = useTriggerCompanyDataMutation() + const [triggerConnectors] = useTriggerConnectorsMutation() + const [triggerCDLoading, setTriggerCDLoading] = useState(false) + const [triggerConnectorsLoading, setTriggerConnectorsLoading] = + useState(false) + const [currentCompanyPage, setCurrentCompanyPage] = useState(0) + const [currentConnectorPage, setCurrentConnectorPage] = useState(0) + const [isFetchingMoreCompanies, setIsFetchingMoreCompanies] = useState(false) + const [isFetchingMoreConnectors, setIsFetchingMoreConnectors] = + useState(false) + + const handleChange = (newChecked: boolean) => { + setChecked(newChecked) + } + + const { + data: companyData, + isFetching: isFetchingCompanyData, + refetch: refetchCompanyData, + } = useFetchCompanyDataQuery({ page: currentCompanyPage }) + + const { + data: connectors, + isFetching: isFetchingConnectors, + refetch: refetchConnectors, + } = useFetchConnectorsQuery({ page: currentConnectorPage }) + + const isCompanyDataAvailable = + !isFetchingCompanyData && (companyData?.content?.length ?? 0) > 0 + const isConnectorsDataAvailable = + !isFetchingConnectors && (connectors?.content?.length ?? 0) > 0 + + // Load more companies + const loadMoreCompanies = () => { + if ( + !isFetchingMoreCompanies && + (companyData?.meta?.page ?? 0) < (companyData?.meta?.totalPages ?? 1) - 1 + ) { + const currentItemCount = companyData?.content?.length ?? 0 + if (currentItemCount % PAGE_SIZE === 0) { + setIsFetchingMoreCompanies(true) + setCurrentCompanyPage((prev) => prev + 1) + } + } + } + + // Load more connectors + const loadMoreConnectors = () => { + if ( + !isFetchingMoreConnectors && + (connectors?.meta?.page ?? 0) < (connectors?.meta?.totalPages ?? 1) - 1 + ) { + const currentItemCount = connectors?.content?.length ?? 0 + if (currentItemCount % PAGE_SIZE === 0) { + setIsFetchingMoreConnectors(true) + setCurrentConnectorPage((prev) => prev + 1) + } + } + } + + useEffect(() => { + if (isFetchingMoreCompanies) { + refetchCompanyData().then(() => { + setIsFetchingMoreCompanies(false) + }) + } + }, [currentCompanyPage, isFetchingMoreCompanies]) + + useEffect(() => { + if (isFetchingMoreConnectors) { + refetchConnectors().then(() => { + setIsFetchingMoreConnectors(false) + }) + } + }, [currentConnectorPage, isFetchingMoreConnectors]) + + // Scroll event to load more data for company list + useEffect(() => { + const companyContainer = document.querySelector('.company-list-container') + + const handleCompanyScroll = () => { + if (companyContainer) { + const bottom = + companyContainer.scrollTop + companyContainer.clientHeight >= + companyContainer.scrollHeight - 10 + + if (bottom) { + loadMoreCompanies() + } + } + } + + companyContainer?.addEventListener('scroll', handleCompanyScroll) + + return () => + companyContainer?.removeEventListener('scroll', handleCompanyScroll) + }, [companyData]) + + // Scroll event to load more data for connector list + useEffect(() => { + const connectorContainer = document.querySelector('.connectors-list') + + const handleConnectorScroll = () => { + if (connectorContainer) { + const bottom = + connectorContainer.scrollHeight - connectorContainer.scrollTop <= + connectorContainer.clientHeight + 10 + if (bottom) { + loadMoreConnectors() + } + } + } + + connectorContainer?.addEventListener('scroll', handleConnectorScroll) + + return () => + connectorContainer?.removeEventListener('scroll', handleConnectorScroll) + }, [connectors]) + + const handleTriggerCompanyData = async () => { + setTriggerCDLoading(true) + try { + await triggerCompanyData().unwrap() + refetchCompanyData() + setTriggerCDLoading(false) + } catch (err) { + setTriggerCDLoading(false) + error( + t('content.clearinghouseSelfDescription.errorMsg'), + '', + err as object + ) + } + } + + const handleTriggerConnectors = async () => { + setTriggerConnectorsLoading(true) + try { + await triggerConnectors().unwrap() + refetchConnectors() + setTriggerConnectorsLoading(false) + } catch (err) { + setTriggerConnectorsLoading(false) + error( + t('content.clearinghouseSelfDescription.errorMsg'), + '', + err as object + ) + } + } + + const renderCompanyDataContent = () => { + return ( + <> + {isCompanyDataAvailable ? ( + + ) : ( + + {t('content.clearinghouseSelfDescription.noDataMsg')} + + )} + + ) + } + + const renderConnectorsContent = () => { + return ( + <> + {isConnectorsDataAvailable ? ( +
+ {connectors?.content?.map((connector) => ( +
+ {connector?.name} + {connector?.companyName} +
+ ))} +
+ ) : ( + + {t('content.clearinghouseSelfDescription.noDataMsg')} + + )} + + ) + } + + return ( +
+ + {t('content.clearinghouseSelfDescription.heading')} + + + + {t('content.clearinghouseSelfDescription.description')} + + + +
+ + {t('content.clearinghouseSelfDescription.complianceStatus')} + + +
+ +
+
+ +
+ + {t('content.clearinghouseSelfDescription.legalPerson')} + + + {t('content.clearinghouseSelfDescription.legalPersonDesc')} + + {isFetchingCompanyData ? ( +
+ +
+ ) : ( + renderCompanyDataContent() + )} +
+ +
+
+ +
+ + {t('content.clearinghouseSelfDescription.connectors')} + + + {t('content.clearinghouseSelfDescription.connectorsDesc')} + + + {isFetchingConnectors ? ( +
+ +
+ ) : ( + renderConnectorsContent() + )} +
+ +
+
+
+ ) +} + +export default AdminclearinghouseSDElements diff --git a/src/components/pages/AdminClearingHouseSD/index.tsx b/src/components/pages/AdminClearingHouseSD/index.tsx new file mode 100644 index 000000000..6343b20f1 --- /dev/null +++ b/src/components/pages/AdminClearingHouseSD/index.tsx @@ -0,0 +1,32 @@ +/******************************************************************************** + * 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 AdminclearinghouseSDElements from './AdminClearingHouseSDElements' + +export default function AdminclearinghouseSD() { + return ( +
+
+
+ +
+
+
+ ) +} diff --git a/src/components/pages/CompanyData/components/CompanyAddressList.tsx b/src/components/pages/CompanyData/components/CompanyAddressList.tsx index 1c490f1fc..1505ee887 100644 --- a/src/components/pages/CompanyData/components/CompanyAddressList.tsx +++ b/src/components/pages/CompanyData/components/CompanyAddressList.tsx @@ -46,6 +46,9 @@ import { } from 'features/companyData/slice' import { statusColorMap } from 'utils/dataMapper' import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline' +import { show } from 'features/control/overlay' +import { OVERLAYS } from 'types/Constants' +import UploadIcon from '@mui/icons-material/Upload' export const CompanyAddressList = ({ handleButtonClick, @@ -195,6 +198,11 @@ export const CompanyAddressList = ({ }, icon: , }, + { + title: t('content.companyData.csvUploadBtn'), + click: () => dispatch(show(OVERLAYS.CSV_UPLOAD_OVERLAY)), + icon: , + }, ]} autoFocus={false} onButtonClick={handleButtonClick} diff --git a/src/components/pages/CompanyData/components/EditForm.tsx b/src/components/pages/CompanyData/components/EditForm.tsx index 8fb21b180..37cee254b 100644 --- a/src/components/pages/CompanyData/components/EditForm.tsx +++ b/src/components/pages/CompanyData/components/EditForm.tsx @@ -35,7 +35,6 @@ import { type CompanyDataType, useUpdateCompanySiteAndAddressMutation, type CompanyDataFieldsType, - useUpdateCompanyStatusToReadyMutation, } from 'features/companyData/companyDataApiSlice' import { useSelector } from 'react-redux' import { @@ -68,7 +67,6 @@ export default function EditForm({ const [loading, setLoading] = useState(false) const [isValid, setIsValid] = useState(false) const [updateData] = useUpdateCompanySiteAndAddressMutation() - const [updateReadyState] = useUpdateCompanyStatusToReadyMutation() const companyData = useSelector(companyDataSelector) const [success, setSuccess] = useState(false) const [error, setError] = useState(false) @@ -123,11 +121,9 @@ export default function EditForm({ } } - const updateStateToReady = async (response: CompanyDataType[]) => { + const handleCreation = async () => { try { - await updateReadyState({ - externalIds: [response[0].externalId], - }) + await updateData([input]) .unwrap() .then(() => { setSuccess(true) @@ -138,19 +134,6 @@ export default function EditForm({ setLoading(false) } - const handleCreation = async () => { - try { - await updateData([input]) - .unwrap() - .then((response) => { - updateStateToReady(response) - }) - } catch (e) { - setError(true) - setLoading(false) - } - } - const getTitle = () => { if (newForm) { return isAddress diff --git a/src/components/pages/CompanySubscriptions/index.tsx b/src/components/pages/CompanySubscriptions/index.tsx index e41e53bc5..c121189c4 100644 --- a/src/components/pages/CompanySubscriptions/index.tsx +++ b/src/components/pages/CompanySubscriptions/index.tsx @@ -217,7 +217,7 @@ export default function CompanySubscriptions() { fetchHook={query} fetchHookArgs={fetchHookArgs} fetchHookRefresh={refresh} - getRowId={(row: { [key: string]: string }) => row.offerId} + getRowId={(row: { [key: string]: string }) => row.subscriptionId} columns={companySubscriptionsCols} /> @@ -252,7 +252,7 @@ export default function CompanySubscriptions() { { const { t } = useTranslation() const [selectedValue, setSelectedValue] = useState() const [serviceAccountUsers, setServiceAccountUsers] = useState([]) - const [selectedTechnicalUser, setSelectedTechnicalUser] = useState('') + const [selectedTechnicalUser, setSelectedTechnicalUser] = useState({}) + const [selectedCustomerLink, setSelectedCustomerLink] = useState({}) useEffect(() => { if (fetchServiceAccountUsers) @@ -274,10 +279,20 @@ any) => { i.serviceAccountId === getValues().ConnectorTechnicalUser ) if (selectedConnectorTechnicalUser.length > 0) { - setSelectedTechnicalUser(selectedConnectorTechnicalUser[0]?.name) + setSelectedTechnicalUser(selectedConnectorTechnicalUser[0]) } }, [serviceAccountUsers]) + useEffect(() => { + const selectedCustomer: EdcSubscriptionsType[] = subscriptions?.filter( + (item: { subscriptionId: string }) => + item.subscriptionId === getValues().ConnectorSubscriptionId + ) + if (selectedCustomer.length > 0) { + setSelectedCustomerLink(selectedCustomer[0]) + } + }, [subscriptions]) + const handleTechnicalUserSubmit = () => { if ( selectedValue === t('content.edcconnector.modal.createNewTechnicalUser') @@ -354,6 +369,12 @@ any) => { )} onChange={(event) => { setSelectedValue(event.target.value) + resetField('TechnicalUserName', { + defaultValue: '', + }) + resetField('TechnicalUserDescription', { + defaultValue: '', + }) }} size="small" sx={{ @@ -612,7 +633,7 @@ any) => { 'content.edcconnector.modal.insertform.subscription.error' ), items: subscriptions, - defaultSelectValue: {}, + defaultSelectValue: selectedCustomerLink ?? {}, keyTitle: 'name', }} /> diff --git a/src/components/pages/EdcConnector/AddConnectorOverlay/index.tsx b/src/components/pages/EdcConnector/AddConnectorOverlay/index.tsx index c0077f692..441539a13 100644 --- a/src/components/pages/EdcConnector/AddConnectorOverlay/index.tsx +++ b/src/components/pages/EdcConnector/AddConnectorOverlay/index.tsx @@ -109,6 +109,7 @@ const AddConnectorOverlay = ({ handleSubmit, getValues, control, + resetField, trigger, formState: { errors }, reset, @@ -120,8 +121,10 @@ const AddConnectorOverlay = ({ const [selected, setSelected] = useState({}) useEffect(() => { - if (openDialog) reset(formFields) - }, [openDialog, reset]) + if (openDialog || connectorStep === 0) { + reset(formFields) + } + }, [openDialog, reset, connectorStep]) useEffect(() => { if (serviceAccounts && serviceAccounts?.meta?.totalPages > page) { @@ -216,7 +219,14 @@ const AddConnectorOverlay = ({ setNewTechnicalUSer={setNewTechnicalUSer} newUserLoading={newUserLoading} newUserSuccess={newUserSuccess} - {...{ handleSubmit, control, errors, trigger, getValues }} + {...{ + handleSubmit, + control, + errors, + trigger, + getValues, + resetField, + }} /> )} @@ -225,12 +235,9 @@ const AddConnectorOverlay = ({ - + diff --git a/src/components/shared/frame/SlidingMainHeader/Header.tsx b/src/components/shared/frame/SlidingMainHeader/Header.tsx index a0b51dcf7..16064e7f3 100644 --- a/src/components/shared/frame/SlidingMainHeader/Header.tsx +++ b/src/components/shared/frame/SlidingMainHeader/Header.tsx @@ -31,6 +31,7 @@ export interface HeaderProps { subTitleTextVariant?: 'h1' | 'h2' | 'h3' buttonText?: string handleClick: () => void + hasAccess?: boolean } //TO-DO - Move this component to cx-shared repo after the yarn upgrade @@ -44,6 +45,7 @@ export const Header = ({ subTitleTextVariant = 'h2', buttonText, handleClick, + hasAccess, }: HeaderProps) => { return ( { handleClick() }} + disabled={!(hasAccess ?? true)} > {buttonText} diff --git a/src/components/shared/frame/SlidingMainHeader/SlidingMainHeader.tsx b/src/components/shared/frame/SlidingMainHeader/SlidingMainHeader.tsx index e74a3c919..552e59bc4 100644 --- a/src/components/shared/frame/SlidingMainHeader/SlidingMainHeader.tsx +++ b/src/components/shared/frame/SlidingMainHeader/SlidingMainHeader.tsx @@ -28,6 +28,7 @@ export interface SlidingMainHeaderProps { subTitle: string imagePath: string buttonText: string + hasAccess?: boolean handleClick: () => void }[] autoplay?: boolean diff --git a/src/components/shared/templates/Subscription/SubscriptionElements.tsx b/src/components/shared/templates/Subscription/SubscriptionElements.tsx index fbea6df5e..640948935 100644 --- a/src/components/shared/templates/Subscription/SubscriptionElements.tsx +++ b/src/components/shared/templates/Subscription/SubscriptionElements.tsx @@ -178,7 +178,15 @@ export default function SubscriptionElements({ subscription: CompanySubscriptionData ) => { if (subscription.offerSubscriptionStatus === SubscriptionStatus.ACTIVE) { - return + return ( + + + + ) } else if ( subscription.offerSubscriptionStatus === SubscriptionStatus.PENDING ) { @@ -187,7 +195,7 @@ export default function SubscriptionElements({ <> { @@ -211,7 +219,13 @@ export default function SubscriptionElements({ }) }} /> - + + + ) } else if ( @@ -226,16 +240,28 @@ export default function SubscriptionElements({ variant="filled" onClick={() => handleActivate(subscription.subscriptionId)} /> - + + + ) } else { return ( - subscription process + + subscription process + ) } } else { diff --git a/src/features/admin/serviceApiSlice.ts b/src/features/admin/serviceApiSlice.ts index 6a9f18203..56b11ef62 100644 --- a/src/features/admin/serviceApiSlice.ts +++ b/src/features/admin/serviceApiSlice.ts @@ -54,18 +54,13 @@ export enum ServiceAccountStatus { PENDING_DELETION = 'PENDING_DELETION', } -export enum UserType { - INTERNAL = 'internal', - EXTERNAL = 'external', -} - export interface ServiceAccountListEntry { serviceAccountId: string clientId: string name: string status: ServiceAccountStatus isOwner?: boolean - usertype: UserType + usertype: string offer?: { name?: string } @@ -84,7 +79,7 @@ export interface ServiceAccountDetail extends ServiceAccountListEntry { connector: ConnectedObject offer: ConnectedObject companyServiceAccountTypeId: companyServiceAccountType - usertype: UserType + usertype: string authenticationServiceUrl: string } @@ -135,12 +130,6 @@ export const apiSlice = createApi({ url: `/api/administration/serviceaccount/owncompany/serviceaccounts/${id}`, method: 'DELETE', }), - // Add an ESLint exception until there is a solution - // eslint-disable-next-line - transformErrorResponse: (error: any) => - error?.errors?.[ - 'Org.Eclipse.TractusX.Portal.Backend.Administration.Service' - ]?.[0] ?? i18next.t('error.deleteTechUserNotificationErrorDescription'), }), fetchServiceAccountList: builder.query< PaginResult, diff --git a/src/features/adminClearingHouseSD/adminClearingHouseSDApiSlice.tsx b/src/features/adminClearingHouseSD/adminClearingHouseSDApiSlice.tsx new file mode 100644 index 000000000..c7d3aaaa3 --- /dev/null +++ b/src/features/adminClearingHouseSD/adminClearingHouseSDApiSlice.tsx @@ -0,0 +1,97 @@ +/******************************************************************************** + * 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 { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import { apiBaseQuery } from 'utils/rtkUtil' + +export const PAGE_SIZE = 15 + +export type PaginationData = { + totalElements: number + page: number + totalPages: number +} + +export type ComapnyDataType = { + companyId: string + name: string +} + +export type ConnectorsType = { + connectorId: string + name: string + companyId: string + companyName: string +} + +export type CompanyDataResponse = { + content: Array + meta: PaginationData +} + +export interface CompanyDataRequestType { + page: number +} + +export type ConnectorsResponse = { + content: Array + meta: PaginationData +} + +export interface ConnectorsRequestType { + page: number +} + +export const apiSlice = createApi({ + reducerPath: 'rtk/admin/clearingHouseSD', + baseQuery: fetchBaseQuery(apiBaseQuery()), + endpoints: (builder) => ({ + fetchCompanyData: builder.query< + CompanyDataResponse, + CompanyDataRequestType + >({ + query: ({ page }) => + `/api/administration/companyData/missing-sd-document?page=${page}&size=${PAGE_SIZE}`, + keepUnusedDataFor: 5, + }), + fetchConnectors: builder.query({ + query: ({ page }) => + `/api/administration/connectors/missing-sd-document?page=${page}&size=${PAGE_SIZE}`, + }), + triggerCompanyData: builder.mutation({ + query: () => ({ + url: '/api/administration/companyData/trigger-self-description', + method: 'POST', + }), + }), + triggerConnectors: builder.mutation({ + query: () => ({ + url: '/api/administration/connectors/trigger-self-description', + method: 'POST', + }), + }), + }), +}) + +export const { + useFetchConnectorsQuery, + useFetchCompanyDataQuery, + useTriggerCompanyDataMutation, + useTriggerConnectorsMutation, +} = apiSlice diff --git a/src/features/apps/apiSlice.ts b/src/features/apps/apiSlice.ts index a6ef97de1..aefb1608c 100644 --- a/src/features/apps/apiSlice.ts +++ b/src/features/apps/apiSlice.ts @@ -176,11 +176,9 @@ export const apiSlice = createApi({ body.args.statusId !== CompanySubscriptionFilterType.SHOW_ALL ? `&status=${body.args.statusId}` : '' - const companyName = body.args.expr - ? `&companyName=${body.args.expr}` - : '' + const name = body.args.expr ? `&name=${body.args.expr}` : '' return { - url: `${url}${statusId}${companyName}`, + url: `${url}${statusId}${name}`, } }, }), diff --git a/src/features/serviceSubscription/serviceSubscriptionApiSlice.ts b/src/features/serviceSubscription/serviceSubscriptionApiSlice.ts index adc4524b6..eec4c2c5b 100644 --- a/src/features/serviceSubscription/serviceSubscriptionApiSlice.ts +++ b/src/features/serviceSubscription/serviceSubscriptionApiSlice.ts @@ -212,11 +212,9 @@ export const apiSlice = createApi({ body.args.statusId !== CompanySubscriptionFilterType.SHOW_ALL ? `&status=${body.args.statusId}` : '' - const companyName = body.args.expr - ? `&companyName=${body.args.expr}` - : '' + const name = body.args.expr ? `&name=${body.args.expr}` : '' return { - url: `${url}${statusId}${companyName}`, + url: `${url}${statusId}${name}`, } }, }), diff --git a/src/features/store.ts b/src/features/store.ts index 0c44cc82c..3145ed305 100644 --- a/src/features/store.ts +++ b/src/features/store.ts @@ -51,6 +51,7 @@ import { apiSlice as serviceMarketplaceApiSlice } from './serviceMarketplace/ser import { apiSlice as serviceProviderApiSlice } from './serviceProvider/serviceProviderApiSlice' import { apiSlice as appSubscriptionApiSlice } from './appSubscription/appSubscriptionApiSlice' import { apiSlice as adminBoardApiSlice } from './adminBoard/adminBoardApiSlice' +import { apiSlice as adminClearingHouseSDApiSlice } from './adminClearingHouseSD/adminClearingHouseSDApiSlice' import { apiSlice as inviteApiSlice } from './admin/inviteApiSlice' import { apiSlice as networkApiSlice } from './admin/networkApiSlice' import { apiSlice as applicationRequestApiSlice } from './admin/applicationRequestApiSlice' @@ -110,6 +111,8 @@ export const reducers = { [serviceProviderApiSlice.reducerPath]: serviceProviderApiSlice.reducer, [appSubscriptionApiSlice.reducerPath]: appSubscriptionApiSlice.reducer, [adminBoardApiSlice.reducerPath]: adminBoardApiSlice.reducer, + [adminClearingHouseSDApiSlice.reducerPath]: + adminClearingHouseSDApiSlice.reducer, [inviteApiSlice.reducerPath]: inviteApiSlice.reducer, [networkApiSlice.reducerPath]: networkApiSlice.reducer, [applicationRequestApiSlice.reducerPath]: applicationRequestApiSlice.reducer, @@ -148,6 +151,7 @@ export const store = configureStore({ .concat(serviceProviderApiSlice.middleware) .concat(appSubscriptionApiSlice.middleware) .concat(adminBoardApiSlice.middleware) + .concat(adminClearingHouseSDApiSlice.middleware) .concat(inviteApiSlice.middleware) .concat(networkApiSlice.middleware) .concat(applicationRequestApiSlice.middleware) diff --git a/src/services/EnvironmentService.ts b/src/services/EnvironmentService.ts index ef7debf74..5fe93a9ff 100644 --- a/src/services/EnvironmentService.ts +++ b/src/services/EnvironmentService.ts @@ -19,9 +19,11 @@ declare const ENV: Record -// get the value of REQUIRE_HTTPS_URL_PATTERN environment variable, defaulting to 'true' if not set -export const getRequireHttpsUrlPattern = () => - ENV.REQUIRE_HTTPS_URL_PATTERN ?? 'true' +export const isRequireHttpsUrlPattern = () => + ENV.REQUIRE_HTTPS_URL_PATTERN !== 'false' + +export const isClearinghouseConnectDisabled = () => + ENV.CLEARINGHOUSE_CONNECT_DISABLED === 'true' export const getRealm = () => ENV.REALM ?? '' @@ -56,7 +58,8 @@ export const getMiwBase = () => ENV.MANAGED_IDENTITY_WALLETS_NEW_URL ?? '' export const getSSICredentialBase = () => ENV.SSI_CREDENTIAL_URL ?? '' const EnvironmentService = { - getRequireHttpsUrlPattern, + isRequireHttpsUrlPattern, + isClearinghouseConnectDisabled, getRealm, getClientId, getClientIdRegistration, diff --git a/src/types/Config.tsx b/src/types/Config.tsx index c0cdda614..aba7be626 100644 --- a/src/types/Config.tsx +++ b/src/types/Config.tsx @@ -95,6 +95,7 @@ import { userHasSsiCredentialRole, } from 'services/AccessService' import OnboardingServiceProvider from 'components/pages/OnboardingServiceProvider/OnboardingServiceProvider' +import AdminclearinghouseSD from 'components/pages/AdminClearingHouseSD' /** * ALL_PAGES @@ -397,6 +398,11 @@ export const ALL_PAGES: IPage[] = [ allowTo: () => userHasPortalRole(ROLES.SUBMITTED_APPLICATION), element: , }, + { + name: PAGES.CLEARINGHOUSE_SELF_DESCRIPTION, + allowTo: () => userHasPortalRole(ROLES.APPROVE_NEW_PARTNER), + element: , + }, { name: PAGES.CONTACT, element: }, { name: PAGES.IMPRINT, element: }, { name: PAGES.PRIVACY, element: }, @@ -599,6 +605,7 @@ export const ALL_PAGES: IPage[] = [ }, { name: PAGES.MANAGEMENT_ONBOARDING_SERVICE_PROVIDER, + allowTo: () => userHasPortalRole(ROLES.CONFIGURE_PARTNER_REGISTRATION), element: , }, ] @@ -829,6 +836,7 @@ export const userMenuFull = [ PAGES.IDP_MANAGEMENT, PAGES.CONNECTOR_MANAGEMENT, PAGES.APPLICATION_REQUESTS, + PAGES.CLEARINGHOUSE_SELF_DESCRIPTION, PAGES.INVITE, PAGES.COMPANY_ROLE, PAGES.USECASE_PARTICIPATION, @@ -849,6 +857,7 @@ export const userMenuCompany = [ PAGES.IDP_MANAGEMENT, PAGES.CONNECTOR_MANAGEMENT, PAGES.APPLICATION_REQUESTS, + PAGES.CLEARINGHOUSE_SELF_DESCRIPTION, PAGES.INVITE, PAGES.COMPANY_ROLE, PAGES.USECASE_PARTICIPATION, diff --git a/src/types/Constants.ts b/src/types/Constants.ts index 40d9e282f..3f3628bb0 100644 --- a/src/types/Constants.ts +++ b/src/types/Constants.ts @@ -49,6 +49,7 @@ export enum PAGES { TECH_USER_DETAILS = 'techUserDetails', IDP_MANAGEMENT = 'idpManagement', APPLICATION_REQUESTS = 'applicationRequests', + CLEARINGHOUSE_SELF_DESCRIPTION = 'clearinghouseSelfDescription', APP_USER_MANAGEMENT = 'appUserManagement', INVITE = 'invite', ADMINISTRATION = 'admin', @@ -233,6 +234,8 @@ export enum ROLES { REVOKE_CREDENTIALS_ISSUER = 'revoke_credentials_issuer', VIEW_REGISTRATION = 'view_registration', READ_PARTNER = 'read_partner', + APPROVE_NEW_PARTNER = 'approve_new_partner', + CONFIGURE_PARTNER_REGISTRATION = 'configure_partner_registration', } export enum HINTS { diff --git a/src/types/Patterns.ts b/src/types/Patterns.ts index 168946180..5449c77bd 100644 --- a/src/types/Patterns.ts +++ b/src/types/Patterns.ts @@ -18,16 +18,13 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import { getRequireHttpsUrlPattern } from '../services/EnvironmentService' - -// check the REQUIRE_HTTPS_URL_PATTERN environment variable, defaulting to !== 'false' if not set -const requireHttpsUrlPattern = getRequireHttpsUrlPattern() !== 'false' +import { isRequireHttpsUrlPattern } from '../services/EnvironmentService' const DOMAIN = /([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9])(\.([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9])){1,10}/i const URLPATH = /(\/[a-z0-9-._~:/?#[\]@!$&'()*+,;=%]{0,500}){0,20}/ // construct regex patterns for URL based on the REQUIRE_HTTPS_URL_PATTERN environment variable -const urlProtocol = requireHttpsUrlPattern ? 'https' : 'https?' +const urlProtocol = isRequireHttpsUrlPattern() ? 'https' : 'https?' const urlPattern = new RegExp( `^(${urlProtocol})://(${DOMAIN.source})(:\\d{1,5})?(${URLPATH.source})?$`, 'i'