Skip to content

Commit 0d010fd

Browse files
feat(auto-setup): add fields for auth in auto setup (#1457)
eclipse-tractusx/portal-backend#1151
1 parent 64d9d86 commit 0d010fd

File tree

6 files changed

+232
-116
lines changed

6 files changed

+232
-116
lines changed

src/assets/locales/de/main.json

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,13 +1529,38 @@
15291529
"message": "The terms of use, as well as the data models and further information can be viewed by clicking on the documents shared below."
15301530
},
15311531
"register": {
1532-
"heading": "Configuration Autosetup URL",
1533-
"message": "The company autosetup URL configuration feature allows operators to set up a custom URL that will be used to automatically submit subscription requests to the service provider when app subscriptions are triggered on the marketplace. This feature also enables operators to retrieve technical configuration elements and activate the subscription.",
1534-
"endpointConfigured": "Configured Provider Endpoint",
1535-
"autosetupURL": "Set a new endpoint URL",
1536-
"inputPlaceholder": "...enter your setup url",
1537-
"providerErrorMessage": "Something went wrong!",
1538-
"providerSuccessMessage": "Details updated successfully."
1532+
"heading": "Konfiguration Auto-Setup URL",
1533+
"message": "Die Auto-Setup URL Konfiguration des Unternehmens ermöglicht es eine benutzerdefinierte URL einzurichten, die verwendet wird, um automatisch Abonnementanfragen an den Dienstanbieter zu übermitteln, wenn App-Abonnements auf dem Marketplace ausgelöst werden. \n\n Diese Auto-Setup URL Konfiguration ermöglicht auch dem Betreiber technische Konfigurationselemente abzurufen und das Abonnement zu aktivieren.",
1534+
"endpointConfigured": "Konfigurierter Anbieter-Endpunkt",
1535+
"inputPlaceholder": "...Geben Sie Ihre Auto-Setup URL ein",
1536+
"deleteAutoSetup": "Löschen Sie die bestehende Auto-Setup Konfiguration",
1537+
"providerErrorMessage": "Es ist ein Fehler aufgetreten! Bitte versuchen Sie es später noch einmal.",
1538+
"providerSuccessMessage": "Details erfolgreich aktualisiert.",
1539+
"autoSetupURL": {
1540+
"name": "Auto-Setup URL einrichten",
1541+
"hint": "Geben Sie gültige Auto-Setup URL ein, um die Abonnementdetails des Benutzers zu erhalten.",
1542+
"error": "Geben Sie das gültige URL-Format ein"
1543+
},
1544+
"callbackUrl": {
1545+
"name": "Callback-URL für das Auto-Setup",
1546+
"hint": "Geben Sie die gültige Callback-URL ein, um die technischen Benutzerdaten zu erhalten.",
1547+
"error": "Geben Sie das gültige URL-Format ein"
1548+
},
1549+
"authUrl": {
1550+
"name": "Auth-URL",
1551+
"hint": "Geben Sie die von Ihrem IdP bereitgestellte URL für das Authentifizierungstoken ein.",
1552+
"error": "Geben Sie das gültige URL-Format ein"
1553+
},
1554+
"clientId": {
1555+
"name": "Client ID",
1556+
"hint": "Geben Sie die von Ihrem IdP bereitgestellte Client-ID ein.",
1557+
"error": "Geben Sie die gültige Client-ID ein"
1558+
},
1559+
"clientSecret": {
1560+
"name": "Client Secret",
1561+
"hint": "Geben Sie das von Ihrem IdP bereitgestellte Client-Secret ein.",
1562+
"error": "Geben Sie das gültige Client-Secret ein"
1563+
}
15391564
},
15401565
"activation": {
15411566
"heading": "Activate App Subscription",

src/assets/locales/en/main.json

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,13 +1529,38 @@
15291529
"message": "The terms of use, as well as the data models and further information can be viewed by clicking on the documents shared below."
15301530
},
15311531
"register": {
1532-
"heading": "Configuration Autosetup URL",
1533-
"message": "The company autosetup URL configuration feature allows operators to set up a custom URL that will be used to automatically submit subscription requests to the service provider when app subscriptions are triggered on the marketplace. This feature also enables operators to retrieve technical configuration elements and activate the subscription.",
1532+
"heading": "Configuration Auto Setup URL",
1533+
"message": "The company's auto setup URL configuration to set up a custom URL that will be used to automatically submit subscription requests to the service provider when app subscriptions are triggered on the marketplace. \n\n This auto setup callback URL configuration also enables the operator to retrieve technical configuration elements and activate the subscription.",
15341534
"endpointConfigured": "Configured Provider Endpoint",
1535-
"autosetupURL": "Set a new endpoint URL",
15361535
"inputPlaceholder": "...enter your setup url",
1536+
"deleteAutoSetup": "Delete the existing configuration of auto setup",
15371537
"providerErrorMessage": "Something went wrong! Please try it later again.",
1538-
"providerSuccessMessage": "Details updated successfully."
1538+
"providerSuccessMessage": "Details updated successfully.",
1539+
"autoSetupURL": {
1540+
"name": "Auto setup URL",
1541+
"hint": "Enter the auto setup valid URL to receive the subscription details of user",
1542+
"error": "Enter the valid URL format"
1543+
},
1544+
"callbackUrl": {
1545+
"name": "Auto setup callback URL",
1546+
"hint": "Enter the auto setup callback valid URL to receive technical user details",
1547+
"error": "Enter the valid URL format"
1548+
},
1549+
"authUrl": {
1550+
"name": "Auth URL",
1551+
"hint": "Enter the auth token valid URL provided by your IdP",
1552+
"error": "Enter the valid URL format"
1553+
},
1554+
"clientId": {
1555+
"name": "Client ID",
1556+
"hint": "Enter the client ID provided by your IdP",
1557+
"error": "Enter the valid client ID"
1558+
},
1559+
"clientSecret": {
1560+
"name": "Client Secret",
1561+
"hint": "Enter the client secret provided by your IdP",
1562+
"error": "Enter the valid client secret"
1563+
}
15391564
},
15401565
"activation": {
15411566
"heading": "Activate App Subscription",

src/components/overlays/AddServiceProvider/index.tsx

Lines changed: 142 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ import {
2424
DialogActions,
2525
DialogContent,
2626
DialogHeader,
27-
Input,
28-
LoadingButton,
2927
PageSnackbar,
30-
Typography,
3128
} from '@catena-x/portal-shared-components'
3229
import { closeOverlay } from 'features/control/overlay'
3330
import { useEffect, useState } from 'react'
@@ -36,51 +33,89 @@ import { useTranslation } from 'react-i18next'
3633
import './style.scss'
3734
import {
3835
useAddServiceProviderMutation,
36+
useDeleteServiceProviderMutation,
3937
useFetchServiceProviderQuery,
4038
} from 'features/serviceProvider/serviceProviderApiSlice'
41-
import Patterns from 'types/Patterns'
39+
import type { ServiceRequest } from 'features/serviceProvider/serviceProviderApiSlice'
40+
import { isIDPClientID, isIDPClientSecret, isURL } from 'types/Patterns'
4241
import { setSuccessType } from 'features/serviceProvider/slice'
42+
import ValidatingInput from 'components/shared/basic/Input/ValidatingInput'
4343
import DeleteIcon from '@mui/icons-material/DeleteOutlineOutlined'
44+
import { InputType } from 'components/shared/basic/Input/BasicInput'
4445

4546
export default function AddServiceProvider() {
4647
const { t } = useTranslation()
4748
const dispatch = useDispatch()
48-
const [inputURL, setInputURL] = useState<string | null>(null)
49-
const [loading, setLoading] = useState(false)
50-
const [deleteLoading, setDeleteLoading] = useState(false)
51-
const [UrlErrorMsg, setUrlErrorMessage] = useState('')
5249
const [saveErrorMsg, setSaveErrorMessage] = useState(false)
50+
const [invalidFields, setInvalidFields] = useState<Set<string>>(new Set())
51+
const [callbackData, setCallbackData] = useState<ServiceRequest>({
52+
url: '',
53+
callbackUrl: undefined,
54+
clientId: '',
55+
clientSecret: '',
56+
authUrl: '',
57+
})
5358

5459
const { data, refetch } = useFetchServiceProviderQuery()
5560
const [addServiceProvider] = useAddServiceProviderMutation()
61+
const [deleteServiceProvider] = useDeleteServiceProviderMutation()
5662
useEffect(() => {
5763
refetch()
5864
dispatch(setSuccessType(false))
5965
}, [refetch, dispatch])
66+
useEffect(() => {
67+
const newInvalidFields = new Set<string>()
68+
const requiredFields: (keyof ServiceRequest)[] = [
69+
'authUrl',
70+
'url',
71+
'clientId',
72+
'clientSecret',
73+
]
74+
requiredFields.forEach((field) => {
75+
if (!(data as Partial<ServiceRequest>)?.[field]) {
76+
newInvalidFields.add(field)
77+
}
78+
})
79+
setInvalidFields(newInvalidFields)
80+
}, [data])
6081

61-
const addInputURL = (value: string) => {
62-
setInputURL(value ?? null)
63-
if (!value) return
64-
if (!Patterns.URL.test(value.trim())) {
65-
setUrlErrorMessage(t('content.appSubscription.pleaseEnterValidURL'))
66-
} else {
67-
setUrlErrorMessage('')
82+
const submitAutoSetup = async () => {
83+
if (!callbackData || !invalidFields) return
84+
try {
85+
const requestData: ServiceRequest = {
86+
...callbackData,
87+
callbackUrl: callbackData.callbackUrl?.trim()
88+
? callbackData.callbackUrl
89+
: undefined,
90+
}
91+
await addServiceProvider(requestData).unwrap()
92+
dispatch(setSuccessType(true))
93+
dispatch(closeOverlay())
94+
} catch (error) {
95+
console.error(error)
96+
setSaveErrorMessage(true)
6897
}
6998
}
7099

71-
const addURL = async () => {
72-
if (inputURL) setLoading(true)
73-
else setDeleteLoading(true)
100+
const deleteAutoSetup = async () => {
74101
try {
75-
await addServiceProvider({ url: inputURL }).unwrap()
102+
await deleteServiceProvider().unwrap()
76103
dispatch(setSuccessType(true))
77104
dispatch(closeOverlay())
78105
} catch (error) {
79-
setLoading(false)
106+
console.error(error)
80107
setSaveErrorMessage(true)
81108
}
82109
}
83110

111+
const handleInputChange = (field: string, value: string) => {
112+
if (invalidFields?.has(field)) invalidFields.delete(field)
113+
setCallbackData((prev) => ({
114+
...prev,
115+
[field]: value,
116+
}))
117+
}
118+
84119
return (
85120
<div className="registerUrlMain">
86121
<DialogHeader
@@ -96,55 +131,78 @@ export default function AddServiceProvider() {
96131
<div className="manageInputURL">
97132
{data ? (
98133
<>
99-
<div className="urlListMain">
100-
<Typography variant="body2">
101-
{t('content.appSubscription.register.endpointConfigured')}
102-
</Typography>
103-
<div className="urlList">
104-
{data?.url ? (
105-
<>
106-
{deleteLoading ? (
107-
<CircleProgress
108-
colorVariant="primary"
109-
interval={800}
110-
iteration
111-
size={20}
112-
step={100}
113-
thickness={1}
114-
variant="indeterminate"
115-
/>
116-
) : (
117-
<DeleteIcon
118-
onClick={() => {
119-
addURL()
120-
}}
121-
className="deleteIcon"
122-
/>
123-
)}
124-
<Typography variant="label2" className="urlDetail">
125-
{data.url}
126-
</Typography>
127-
</>
128-
) : (
129-
'-'
130-
)}
131-
</div>
132-
</div>
133-
<Input
134-
label={
135-
<Typography variant="body2">
136-
{t('content.appSubscription.register.autosetupURL')}
137-
</Typography>
138-
}
139-
placeholder={t(
140-
'content.appSubscription.register.inputPlaceholder'
134+
<ValidatingInput
135+
name={'url' as keyof ServiceRequest}
136+
label={t('content.appSubscription.register.autoSetupURL.name')}
137+
value={data?.url}
138+
hint={t('content.appSubscription.register.autoSetupURL.hint')}
139+
errorMessage={t(
140+
'content.appSubscription.register.autoSetupURL.error'
141+
)}
142+
onValid={handleInputChange}
143+
onInvalid={(name, _) => {
144+
setInvalidFields((prev) => new Set(prev).add(name))
145+
}}
146+
validate={(expr) => isURL(expr)}
147+
/>
148+
149+
<ValidatingInput
150+
name={'callbackUrl' as keyof ServiceRequest}
151+
label={t('content.appSubscription.register.callbackUrl.name')}
152+
value={data?.callbackUrl}
153+
hint={t('content.appSubscription.register.callbackUrl.hint')}
154+
errorMessage={t(
155+
'content.appSubscription.register.callbackUrl.error'
156+
)}
157+
validate={(expr) => !expr || isURL(expr)}
158+
onValid={handleInputChange}
159+
onInvalid={(name, _) => {
160+
setInvalidFields((prev) => new Set(prev).add(name))
161+
}}
162+
/>
163+
<ValidatingInput
164+
name={'authUrl' as keyof ServiceRequest}
165+
label={t('content.appSubscription.register.authUrl.name')}
166+
value={data?.authUrl}
167+
hint={t('content.appSubscription.register.authUrl.hint')}
168+
errorMessage={t(
169+
'content.appSubscription.register.authUrl.error'
141170
)}
142-
onChange={(e) => {
143-
addInputURL(e.target.value)
171+
validate={(expr) => isURL(expr)}
172+
onValid={handleInputChange}
173+
onInvalid={(name, _) => {
174+
setInvalidFields((prev) => new Set(prev).add(name))
175+
}}
176+
/>
177+
<ValidatingInput
178+
name={'clientId' as keyof ServiceRequest}
179+
label={t('content.appSubscription.register.clientId.name')}
180+
value={data?.clientId}
181+
hint={t('content.appSubscription.register.clientId.hint')}
182+
errorMessage={t(
183+
'content.appSubscription.register.clientId.error'
184+
)}
185+
validate={isIDPClientID}
186+
onValid={handleInputChange}
187+
onInvalid={(name, _) => {
188+
setInvalidFields((prev) => new Set(prev).add(name))
189+
}}
190+
/>
191+
<ValidatingInput
192+
name={'clientSecret' as keyof ServiceRequest}
193+
type={InputType.password}
194+
label={t('content.appSubscription.register.clientSecret.name')}
195+
value={data?.clientSecret}
196+
hint={t('content.appSubscription.register.clientSecret.hint')}
197+
errorMessage={t(
198+
'content.appSubscription.register.clientSecret.error'
199+
)}
200+
validate={isIDPClientSecret}
201+
onValid={handleInputChange}
202+
onInvalid={(name, _) => {
203+
setInvalidFields((prev) => new Set(prev).add(name))
144204
}}
145-
value={inputURL}
146205
/>
147-
<p className="error">{UrlErrorMsg}</p>
148206
</>
149207
) : (
150208
<div className="progress">
@@ -163,34 +221,30 @@ export default function AddServiceProvider() {
163221
</DialogContent>
164222

165223
<DialogActions>
166-
<Button variant="outlined" onClick={() => dispatch(closeOverlay())}>
167-
{t('global.actions.cancel')}
168-
</Button>
169-
{loading ? (
170-
<LoadingButton
171-
color="primary"
172-
helperText=""
173-
helperTextColor="success"
174-
label=""
175-
loadIndicator="Loading ..."
176-
loading
177-
size="medium"
178-
onButtonClick={() => {
179-
// do nothing
180-
}}
181-
sx={{ marginLeft: '10px' }}
182-
/>
183-
) : (
224+
{data?.url && (
184225
<Button
185-
variant="contained"
226+
variant="outlined"
227+
title={t('content.appSubscription.register.deleteAutoSetup')}
186228
onClick={() => {
187-
void addURL()
229+
deleteAutoSetup()
188230
}}
189-
disabled={UrlErrorMsg !== '' || !inputURL}
190231
>
191-
{t('global.actions.confirm')}
232+
<DeleteIcon className="deleteIcon" /> {t('global.actions.delete')}
192233
</Button>
193234
)}
235+
236+
<Button variant="outlined" onClick={() => dispatch(closeOverlay())}>
237+
{t('global.actions.cancel')}
238+
</Button>
239+
<Button
240+
variant="contained"
241+
onClick={() => {
242+
void submitAutoSetup()
243+
}}
244+
disabled={invalidFields?.size > 0}
245+
>
246+
{t('global.actions.confirm')}
247+
</Button>
194248
</DialogActions>
195249
<PageSnackbar
196250
open={saveErrorMsg}

0 commit comments

Comments
 (0)