diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43cc1d0ab..3d6ed7b74 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
## Unreleased
+### Feature
+
+- **Onboarding Service Provider Management**:
+ - Create new page for onboarding service provider management [#1052](https://github.com/eclipse-tractusx/portal-frontend/pull/1052)
- Company data
- Disable confirm button if input value is not matching with the regular expression
- Fix infinite loop issue in add New Address Modal
diff --git a/src/assets/locales/de/main.json b/src/assets/locales/de/main.json
index 0430cd789..4c34a1faf 100644
--- a/src/assets/locales/de/main.json
+++ b/src/assets/locales/de/main.json
@@ -69,7 +69,8 @@
"companySubscriptions": "Firmenabonnements",
"mycompany": "My Company",
"mynotifications": "My Notifications",
- "companyData": "Company Data"
+ "companyData": "Company Data",
+ "ManagementOnboardingServiceProvider": "Onboarding Service Provider"
},
"overlays": {
"invite": "Neuen Geschäftspartner einladen",
@@ -2144,6 +2145,37 @@
"title": "Create {name}",
"description": "The changes could not be saved. Please try again"
}
+ },
+ "onboardingServiceProvider": {
+ "headertitle": "Onboarding-Dienstleister-Management",
+ "desc": "[description] lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
+ "subDesc1": "OSP-Callback konfiguriert",
+ "subDesc2": "https://url.lorem.ipsum.dolor.sit.amet",
+ "tabletitle1": "OSP-Identitätsanbieter (IDPs)",
+ "tabletitle2": "Kundenübersicht",
+ "userList": "Benutzerliste",
+ "addIdentityProvider": "Identitätsanbieter hinzufügen",
+ "dialogTitle": "IdP-Metadaten konfigurieren",
+ "table": {
+ "customerName": "Kundenname",
+ "status": "Status",
+ "idpName": "IDP-Name",
+ "users": "Anzahl der Benutzer"
+ },
+ "success": "OSP-Rückruf erfolgreich konfiguriert",
+ "callbackUrlError": "Fehler beim Konfigurieren des OSP-Rückrufs",
+ "callbackUrl": {
+ "name": "Rückruf-URL",
+ "hint": "Geben Sie die Rückruf-URL Ihres IDP ein, die mit „/.well-known/openid-configuration“ endet'"
+ },
+ "clientId": {
+ "name": "Kunden-ID",
+ "hint": "Geben Sie die von Ihrem IdP bereitgestellte Client-ID ein"
+ },
+ "clientSecret": {
+ "name": "Client-Geheimnis",
+ "hint": "Geben Sie das von Ihrem IdP bereitgestellte Client-Geheimnis ein"
+ }
}
},
"navigation": {
diff --git a/src/assets/locales/en/main.json b/src/assets/locales/en/main.json
index 5170555f0..86952ed00 100644
--- a/src/assets/locales/en/main.json
+++ b/src/assets/locales/en/main.json
@@ -68,7 +68,8 @@
"companySubscriptions": "Company Subscriptions",
"mycompany": "My Company",
"mynotifications": "My Notifications",
- "companyData": "Company Data"
+ "companyData": "Company Data",
+ "ManagementOnboardingServiceProvider": "Onboarding Service Provider"
},
"overlays": {
"invite": "Invite new Business Partner",
@@ -2116,6 +2117,37 @@
"title": "Create {name}",
"description": "The changes could not be saved. Please try again"
}
+ },
+ "onboardingServiceProvider": {
+ "headertitle": "Onboarding Service Provider Management",
+ "desc": "[description] lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
+ "subDesc1": "OSP Callback configured",
+ "subDesc2": "https://url.lorem.ipsum.dolor.sit.amet",
+ "tabletitle1": "OSP Identity Provider (IDPs)",
+ "tabletitle2": "Customer Overview",
+ "userList": "User List",
+ "addIdentityProvider": "Add Identity Provider",
+ "dialogTitle": "Configure IdP Metadata",
+ "table": {
+ "customerName": "Customer Name",
+ "status": "Status",
+ "idpName": "IDP name",
+ "users": "# of users"
+ },
+ "success": "Successfully configured OSP callback",
+ "callbackUrlError": "Failed configuring OSP callback",
+ "callbackUrl": {
+ "name": "Callback URL",
+ "hint": "Enter the callback URL from your IDP that ends with '/.well-known/openid-configuration'"
+ },
+ "clientId": {
+ "name": "Client ID",
+ "hint": "Enter the client ID provided by your IdP"
+ },
+ "clientSecret": {
+ "name": "Client Secret",
+ "hint": "Enter the client secret provided by your IdP"
+ }
}
},
"navigation": {
diff --git a/src/components/pages/EdcConnector/EdcConnector.scss b/src/components/pages/EdcConnector/EdcConnector.scss
index e0cecec46..aad104ecd 100644
--- a/src/components/pages/EdcConnector/EdcConnector.scss
+++ b/src/components/pages/EdcConnector/EdcConnector.scss
@@ -26,10 +26,6 @@
margin: 0;
padding: 0;
width: 100%;
-
- .picture-with-text-section {
- margin-top: 50px;
- }
}
.connector-type-selector-container {
diff --git a/src/components/pages/IDPManagement/IDPList.tsx b/src/components/pages/IDPManagement/IDPList.tsx
index 567b2051a..3f5b54d38 100644
--- a/src/components/pages/IDPManagement/IDPList.tsx
+++ b/src/components/pages/IDPManagement/IDPList.tsx
@@ -78,7 +78,7 @@ const MenuItemOpenOverlay = ({
)
}
-export const IDPList = () => {
+export const IDPList = ({ isManagementOSP }: { isManagementOSP?: boolean }) => {
const { t } = useTranslation()
const ti = useTranslation('idp').t
@@ -252,6 +252,92 @@ export const IDPList = () => {
)
}
+ const renderManagementOSPMenu = (idp: IdentityProvider) => {
+ const isManagedIdp = idp.identityProviderTypeId === IDPCategory.MANAGED
+ const menuItems = {
+ edit: (
+
+ ),
+ delete: isManagedIdp ? (
+
+ ) : (
+
+ ),
+ enableToggle:
+ isManagedIdp && idp.enabled ? (
+
+ ) : (
+
+ ),
+ }
+
+ return (
+
+
+ {menuItems.edit}
+ {menuItems.enableToggle}
+ {menuItems.delete}
+
+
+ )
+ }
+
return (
{
headerName: t('global.field.action'),
flex: 2,
sortable: false,
- renderCell: ({ row }: { row: IdentityProvider }) => renderMenu(row),
+ renderCell: ({ row }: { row: IdentityProvider }) =>
+ isManagementOSP ? renderManagementOSPMenu(row) : renderMenu(row),
},
]}
- rows={idpsData ?? []}
+ rows={
+ (isManagementOSP
+ ? idpsData?.filter(
+ (a) => a.identityProviderTypeId === IDPCategory.MANAGED
+ )
+ : idpsData) ?? []
+ }
getRowId={(row: { [key: string]: string }) => row.identityProviderId}
hasBorder={false}
/>
diff --git a/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.scss b/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.scss
new file mode 100644
index 000000000..fd5ecb96e
--- /dev/null
+++ b/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.scss
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * 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
+ ********************************************************************************/
+
+.onboarding-service-page-container {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+.onboarding-service-header {
+ text-align: center;
+ width: 100%;
+ margin: 0 auto;
+
+ .onboarding-service-title {
+ text-align: center;
+ padding-bottom: 20px;
+ position: relative;
+ }
+
+ .onboarding-service-title::after {
+ content: '';
+ width: 70px;
+ border-bottom: 2px solid;
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .onboarding-service-desc {
+ width: 74%;
+ margin: 50px auto;
+ }
+}
diff --git a/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.tsx b/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.tsx
new file mode 100644
index 000000000..507fb1014
--- /dev/null
+++ b/src/components/pages/OnboardingServiceProvider/OnboardingServiceProvider.tsx
@@ -0,0 +1,422 @@
+/********************************************************************************
+ * 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 { type SyntheticEvent, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ Typography,
+ IconButton,
+ Tabs,
+ Tab,
+ TabPanel,
+ PageLoadingTable,
+ DialogActions,
+ Button,
+ DialogHeader,
+ DialogContent,
+ Dialog,
+ LoadingButton,
+} from '@catena-x/portal-shared-components'
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
+import { Box } from '@mui/material'
+import './OnboardingServiceProvider.scss'
+import { IDPList } from '../IDPManagement/IDPList'
+import {
+ type networkCompany,
+ type OIDCSignatureAlgorithm,
+ type RegistartionStatusCallbackType,
+ useFetchCompaniesListQuery,
+ useFetchRegistartionStatusCallbackQuery,
+ useUpdateRegistartionStatusCallbackMutation,
+} from 'features/admin/idpApiSlice'
+import ValidatingInput from 'components/shared/basic/Input/ValidatingInput'
+import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'
+import { useDispatch } from 'react-redux'
+import { show } from 'features/control/overlay'
+import { OVERLAYS } from 'types/Constants'
+import { isIDPClientID, isIDPClientSecret, isURL } from 'types/Patterns'
+import { InputType } from 'components/shared/basic/Input/BasicInput'
+import { type IHashMap } from 'types/MainTypes'
+import { success } from 'services/NotifyService'
+import WarningAmberIcon from '@mui/icons-material/WarningAmber'
+
+const OnboardingServiceProvider = () => {
+ const { t } = useTranslation()
+ const [activeTab, setActiveTab] = useState(0)
+ const [overlayOpen, setOverlayOpen] = useState(false)
+ const dispatch = useDispatch()
+ const { data } = useFetchRegistartionStatusCallbackQuery()
+ const [loading, setLoading] = useState(false)
+ const [updateRegistartionStatusCallback] =
+ useUpdateRegistartionStatusCallbackMutation()
+ const [formData, setFormData] = useState>({})
+ const [showError, setShowError] = useState(false)
+ const [callbackData, setCallbackData] = useState<
+ RegistartionStatusCallbackType | undefined
+ >(undefined)
+
+ const handleTabChange = (
+ _e: SyntheticEvent,
+ value: number
+ ) => {
+ setActiveTab(value)
+ }
+
+ const getTabsIcon = (step: number) => {
+ return (
+
+ {step}
+
+ )
+ }
+
+ const isWellknownMetadata = (expr: string) =>
+ isURL(expr) && expr.endsWith('.well-known/openid-configuration')
+
+ const updateCallbackIDP = async () => {
+ if (!(data && callbackData)) return
+ setLoading(true)
+ try {
+ await updateRegistartionStatusCallback(callbackData).unwrap()
+ success(t('content.onboardingServiceProvider.success'))
+ setOverlayOpen(false)
+ } catch (err) {
+ setShowError(true)
+ }
+ setLoading(false)
+ }
+
+ const checkValidData = (key: string, value: string | undefined): boolean => {
+ const current: IHashMap = { ...formData }
+ current[key] = value as OIDCSignatureAlgorithm
+ setFormData(current)
+ const formValid =
+ current.callbackUrl && current.clientId && current.clientSecret
+ setCallbackData(
+ formValid
+ ? {
+ callbackUrl: current.callbackUrl,
+ clientId: current.clientId,
+ clientSecret: current.clientSecret,
+ authUrl: '',
+ }
+ : undefined
+ )
+ return true
+ }
+
+ return (
+
+
+
+
+
+
+ {t('content.onboardingServiceProvider.headertitle')}
+
+
+ {t('content.onboardingServiceProvider.desc')}
+
+
+
+
+ {t('content.onboardingServiceProvider.subDesc1')}
+
+
+ {t('content.onboardingServiceProvider.subDesc2')}
+
+
+ {
+ setOverlayOpen(true)
+ }}
+ sx={{
+ right: '0',
+ position: 'absolute',
+ top: '50%',
+ msTransform: 'translateY(-50%)',
+ transform: 'translateY(-50%)',
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('content.onboardingServiceProvider.userList')}
+
+ }
+ onClick={() => dispatch(show(OVERLAYS.ADD_IDP))}
+ className="add-idp-btn"
+ >
+ {t('content.onboardingServiceProvider.addIdentityProvider')}
+
+
+
+
+
+
+
+
+ toolbarVariant="premium"
+ title={t('content.onboardingServiceProvider.tabletitle2')}
+ loadLabel={t('global.actions.more')}
+ fetchHook={useFetchCompaniesListQuery}
+ getRowId={(row: { [key: string]: string }) =>
+ row.applicationStatus
+ }
+ columns={[
+ {
+ field: 'companyName',
+ headerName: t(
+ 'content.onboardingServiceProvider.table.customerName'
+ ),
+ flex: 1,
+ sortable: false,
+ },
+ {
+ field: 'applicationStatus',
+ headerName: t(
+ 'content.onboardingServiceProvider.table.status'
+ ),
+ flex: 1,
+ sortable: false,
+ },
+ {
+ field: 'identityProvider',
+ headerName: t(
+ 'content.onboardingServiceProvider.table.idpName'
+ ),
+ flex: 1,
+ sortable: false,
+ renderCell: ({ row }: { row: networkCompany }) =>
+ row?.identityProvider?.[0].alias,
+ },
+ {
+ field: 'activeUsers',
+ headerName: t(
+ 'content.onboardingServiceProvider.table.users'
+ ),
+ flex: 1,
+ sortable: false,
+ },
+ ]}
+ />
+
+
+
+
+ )
+}
+
+export default OnboardingServiceProvider
diff --git a/src/features/admin/idpApiSlice.ts b/src/features/admin/idpApiSlice.ts
index e86514ea9..611e7c9e2 100644
--- a/src/features/admin/idpApiSlice.ts
+++ b/src/features/admin/idpApiSlice.ts
@@ -18,6 +18,10 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
+import {
+ type PaginFetchArgs,
+ type PaginResult,
+} from '@catena-x/portal-shared-components'
import { type PayloadAction, createSlice } from '@reduxjs/toolkit'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { type RootState } from 'features/store'
@@ -177,6 +181,32 @@ export interface ManagedIDPNetworkType {
| null
}
+export type networkCompany = {
+ companyId: string
+ externalId: string
+ applicationId: string
+ applicationStatus: string
+ applicationDateCreated: string
+ dateCreated: string
+ lastChangedDate: string
+ companyName: string
+ companyRoles?: string[] | null
+ identityProvider?: IdentityProviderEntity[] | null
+ bpn: string
+ activeUsers: number
+}
+export interface IdentityProviderEntity {
+ identityProviderId: string
+ alias: string
+}
+
+export interface RegistartionStatusCallbackType {
+ callbackUrl: string
+ authUrl?: string
+ clientId: string
+ clientSecret: string
+}
+
enum TAGS {
IDP = 'idp',
}
@@ -280,6 +310,29 @@ export const apiSlice = createApi({
query: (id: string) =>
`/api/administration/identityprovider/network/identityproviders/managed/${id}`,
}),
+ fetchCompaniesList: builder.query<
+ PaginResult,
+ PaginFetchArgs
+ >({
+ query: (filters) =>
+ `/api/administration/registration/network/companies?page=${filters.page}&size=10`,
+ }),
+ fetchRegistartionStatusCallback: builder.query<
+ RegistartionStatusCallbackType,
+ void
+ >({
+ query: () => '/api/administration/RegistrationStatus/callback',
+ }),
+ updateRegistartionStatusCallback: builder.mutation<
+ void,
+ RegistartionStatusCallbackType
+ >({
+ query: (data: RegistartionStatusCallbackType) => ({
+ url: '/api/administration/RegistrationStatus/callback',
+ method: 'POST',
+ body: data,
+ }),
+ }),
}),
})
@@ -296,6 +349,9 @@ export const {
useEnableIDPMutation,
useUpdateUserIDPMutation,
useFetchManagedIDPNetworkQuery,
+ useFetchCompaniesListQuery,
+ useFetchRegistartionStatusCallbackQuery,
+ useUpdateRegistartionStatusCallbackMutation,
} = apiSlice
export default slice
diff --git a/src/types/Config.tsx b/src/types/Config.tsx
index 387b73f24..02a48c5bf 100644
--- a/src/types/Config.tsx
+++ b/src/types/Config.tsx
@@ -87,6 +87,7 @@ import { OSPConsent } from 'components/pages/OSPConsent'
import CompanySubscriptions from 'components/pages/CompanySubscriptions'
import CompanySubscriptionDetail from 'components/pages/CompanySubscriptions/CompanySubscriptionDetail'
import CompanyData from 'components/pages/CompanyData'
+import OnboardingServiceProvider from 'components/pages/OnboardingServiceProvider/OnboardingServiceProvider'
/**
* ALL_PAGES
@@ -579,6 +580,10 @@ export const ALL_PAGES: IPage[] = [
role: ROLES.MY_ORGANIZATION_VIEW,
element: ,
},
+ {
+ name: PAGES.MANAGEMENT_ONBOARDING_SERVICE_PROVIDER,
+ element: ,
+ },
]
export const ALL_OVERLAYS: IOverlay[] = [
@@ -812,6 +817,7 @@ export const userMenuFull = [
PAGES.COMPANY_CERTIFICATE,
PAGES.COMPANY_WALLET,
PAGES.COMPANY_DATA,
+ PAGES.MANAGEMENT_ONBOARDING_SERVICE_PROVIDER,
PAGES.LOGOUT,
]
diff --git a/src/types/Constants.ts b/src/types/Constants.ts
index 6b54a64aa..6fb5b4605 100644
--- a/src/types/Constants.ts
+++ b/src/types/Constants.ts
@@ -109,6 +109,7 @@ export enum PAGES {
COMPANY_SUBSCRIPTIONS = 'companySubscriptions',
COMPANY_SUBSCRIPTIONS_DETAIL = 'companySubscriptionsDetail',
COMPANY_DATA = 'companyData',
+ MANAGEMENT_ONBOARDING_SERVICE_PROVIDER = 'ManagementOnboardingServiceProvider',
}
export enum OVERLAYS {