Skip to content

Commit b8e674e

Browse files
committed
fix: add back 42 changes
1 parent 5dbb36b commit b8e674e

File tree

4 files changed

+167
-52
lines changed

4 files changed

+167
-52
lines changed

src/oauth2-client-editor/ClientForm.js

Lines changed: 100 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import i18n from '@dhis2/d2-i18n'
22
import { Button, Modal, ModalTitle, ModalContent } from '@dhis2/ui'
33
import { getInstance as getD2 } from 'd2'
44
import FormBuilder from 'd2-ui/lib/forms/FormBuilder.component.js'
5-
import { isUrlArray, isRequired } from 'd2-ui/lib/forms/Validators.js'
5+
import { isRequired } from 'd2-ui/lib/forms/Validators.js'
66
import PropTypes from 'prop-types'
7-
import React from 'react'
7+
import React, { useState } from 'react'
88
import MultiToggle from '../form-fields/multi-toggle.js'
99
import TextField from '../form-fields/text-field.js'
1010
import styles from './ClientForm.module.css'
@@ -17,47 +17,107 @@ const validateClientID = async (v) => {
1717
const d2 = await getD2()
1818
const list = await d2.models.oAuth2Clients.list({
1919
paging: false,
20-
filter: [`cid:eq:${v}`],
20+
filter: [`clientId:eq:${v}`],
2121
})
2222
if (list.size > 0) {
2323
throw i18n.t('This client ID is already taken')
2424
}
2525
}
2626

2727
const ClientForm = ({ clientModel, onUpdate, onSave, onCancel }) => {
28-
const grantTypes = ((clientModel && clientModel.grantTypes) || []).reduce(
29-
(curr, prev) => {
30-
curr[prev] = true
31-
return curr
32-
},
33-
{}
34-
)
28+
const [formErrors, setFormErrors] = useState({
29+
clientId: false,
30+
redirectUris: false,
31+
})
32+
33+
// Handle both string and array types for authorizationGrantTypes
34+
let authGrantTypesArray = []
35+
36+
if (clientModel && clientModel.authorizationGrantTypes) {
37+
// If it's a string (from backend), split it
38+
if (typeof clientModel.authorizationGrantTypes === 'string') {
39+
authGrantTypesArray = clientModel.authorizationGrantTypes
40+
.split(',')
41+
.map((type) => type.trim())
42+
.filter(Boolean)
43+
}
44+
// If it's already an array (from form update)
45+
else if (Array.isArray(clientModel.authorizationGrantTypes)) {
46+
authGrantTypesArray = clientModel.authorizationGrantTypes
47+
}
48+
}
49+
50+
const grantTypes = authGrantTypesArray.reduce((curr, prev) => {
51+
curr[prev] = true
52+
return curr
53+
}, {})
54+
55+
// Format redirectUris for display in the form
56+
let formattedRedirectUris = ''
57+
if (clientModel && clientModel.redirectUris) {
58+
if (Array.isArray(clientModel.redirectUris)) {
59+
// If it's an array, join with newlines for display
60+
formattedRedirectUris = clientModel.redirectUris.join('\n')
61+
} else if (typeof clientModel.redirectUris === 'string') {
62+
// If it's a comma-separated string, replace commas with newlines for display
63+
formattedRedirectUris = clientModel.redirectUris
64+
.split(',')
65+
.map((uri) => uri.trim())
66+
.filter(Boolean)
67+
.join('\n')
68+
}
69+
}
70+
71+
const handleSave = () => {
72+
// Check fields and show errors if needed
73+
const clientIdEmpty =
74+
!clientModel.clientId || clientModel.clientId.trim() === ''
75+
const redirectUrisEmpty =
76+
!formattedRedirectUris || formattedRedirectUris.trim() === ''
77+
78+
setFormErrors({
79+
clientId: clientIdEmpty,
80+
redirectUris: redirectUrisEmpty,
81+
})
82+
83+
// Only save if both fields are valid
84+
if (!clientIdEmpty && !redirectUrisEmpty) {
85+
onSave()
86+
}
87+
}
88+
89+
// Handle field updates and clear errors
90+
const handleFieldUpdate = (fieldName, value) => {
91+
// Clear the error for this field if it has a value
92+
if (value) {
93+
// Check if value is a string before using trim()
94+
const isValid =
95+
typeof value === 'string'
96+
? value.trim().length > 0
97+
: Boolean(value)
98+
99+
if (isValid) {
100+
setFormErrors((prev) => ({
101+
...prev,
102+
[fieldName]: false,
103+
}))
104+
}
105+
}
106+
107+
// Call the original onUpdate function
108+
onUpdate(fieldName, value)
109+
}
35110

36111
const fields = [
37112
{
38-
name: 'name',
39-
value: clientModel.name,
40-
component: TextField,
41-
props: {
42-
floatingLabelText: i18n.t('Name'),
43-
style: formFieldStyle,
44-
changeEvent: 'onBlur',
45-
},
46-
validators: [
47-
{
48-
validator: isRequired,
49-
message: i18n.t('Required'),
50-
},
51-
],
52-
},
53-
{
54-
name: 'cid',
55-
value: clientModel.cid,
113+
name: 'clientId',
114+
value: clientModel.clientId,
56115
component: TextField,
57116
props: {
58117
floatingLabelText: i18n.t('Client ID'),
59118
style: formFieldStyle,
60119
changeEvent: 'onBlur',
120+
errorText: formErrors.clientId ? i18n.t('Required') : null,
61121
},
62122
validators: [
63123
{
@@ -82,17 +142,12 @@ const ClientForm = ({ clientModel, onUpdate, onSave, onCancel }) => {
82142
},
83143
},
84144
{
85-
name: 'grantTypes',
145+
name: 'authorizationGrantTypes',
86146
component: MultiToggle,
87147
style: formFieldStyle,
88148
props: {
89149
label: i18n.t('Grant Types'),
90150
items: [
91-
{
92-
name: 'password',
93-
text: i18n.t('Password'),
94-
value: grantTypes.password,
95-
},
96151
{
97152
name: 'refresh_token',
98153
text: i18n.t('Refresh token'),
@@ -108,18 +163,21 @@ const ClientForm = ({ clientModel, onUpdate, onSave, onCancel }) => {
108163
},
109164
{
110165
name: 'redirectUris',
111-
value: (clientModel.redirectUris || []).join('\n'),
166+
value: formattedRedirectUris,
112167
component: TextField,
113168
props: {
114169
hintText: i18n.t('One URL per line'),
115170
floatingLabelText: i18n.t('Redirect URIs'),
116171
multiLine: true,
117172
style: formFieldStyle,
118173
changeEvent: 'onBlur',
174+
errorText: formErrors.redirectUris
175+
? i18n.t('This field should contain a list of URLs')
176+
: null,
119177
},
120178
validators: [
121179
{
122-
validator: isUrlArray,
180+
validator: isRequired,
123181
message: i18n.t('This field should contain a list of URLs'),
124182
},
125183
],
@@ -130,13 +188,17 @@ const ClientForm = ({ clientModel, onUpdate, onSave, onCancel }) => {
130188
clientModel.id === undefined
131189
? i18n.t('Create new OAuth2 Client')
132190
: i18n.t('Edit OAuth2 Client')
191+
133192
return (
134193
<Modal onClose={onCancel}>
135194
<ModalTitle>{headerText}</ModalTitle>
136195
<ModalContent>
137-
<FormBuilder fields={fields} onUpdateField={onUpdate} />
196+
<FormBuilder
197+
fields={fields}
198+
onUpdateField={handleFieldUpdate}
199+
/>
138200
<div style={{ marginTop: '1rem' }}>
139-
<Button primary onClick={onSave}>
201+
<Button primary onClick={handleSave}>
140202
{i18n.t('Save')}
141203
</Button>
142204
<Button

src/oauth2-client-editor/ClientsList.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ const ClientsList = ({ clients, onClientEdit, onClientDelete }) => {
2929
<Table>
3030
<TableHead>
3131
<TableRowHead>
32-
<TableCellHead>{i18n.t('Name')}</TableCellHead>
33-
<TableCellHead>{i18n.t('Password')}</TableCellHead>
32+
<TableCellHead>{i18n.t('Client ID')}</TableCellHead>
3433
<TableCellHead>{i18n.t('Refresh token')}</TableCellHead>
3534
<TableCellHead>
3635
{i18n.t('Authorization code')}
@@ -41,8 +40,7 @@ const ClientsList = ({ clients, onClientEdit, onClientDelete }) => {
4140
<TableBody>
4241
{clients.map((client) => (
4342
<TableRow key={client.authorization_code}>
44-
<TableCell>{client.name}</TableCell>
45-
<TableCell>{client.password}</TableCell>
43+
<TableCell>{client.clientId}</TableCell>
4644
<TableCell>{client.refresh_token}</TableCell>
4745
<TableCell>{client.authorization_code}</TableCell>
4846
<TableCell>

src/oauth2-client-editor/OAuth2ClientEditor.component.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,39 @@ class OAuth2ClientEditor extends Component {
7676
}
7777

7878
saveAction = () => {
79+
// Validation is now handled in the ClientForm component
80+
7981
this.clientModel.name = this.clientModel.name || ''
8082
this.clientModel.cid = this.clientModel.cid || ''
83+
84+
// Ensure authorizationGrantTypes is a comma-separated string
85+
if (
86+
this.clientModel.authorizationGrantTypes &&
87+
Array.isArray(this.clientModel.authorizationGrantTypes)
88+
) {
89+
this.clientModel.authorizationGrantTypes =
90+
this.clientModel.authorizationGrantTypes.join(',')
91+
}
92+
93+
// First ensure redirectUris is an array
94+
if (
95+
this.clientModel.redirectUris &&
96+
typeof this.clientModel.redirectUris === 'string'
97+
) {
98+
this.clientModel.redirectUris = this.clientModel.redirectUris
99+
.split('\n')
100+
.map((uri) => uri.trim())
101+
.filter(Boolean)
102+
} else if (!this.clientModel.redirectUris) {
103+
this.clientModel.redirectUris = []
104+
}
105+
106+
// Then convert the array to a comma-separated string
107+
if (Array.isArray(this.clientModel.redirectUris)) {
108+
this.clientModel.redirectUris =
109+
this.clientModel.redirectUris.join(',')
110+
}
111+
81112
this.setState({ saving: true })
82113
this.clientModel
83114
.save()
@@ -103,7 +134,23 @@ class OAuth2ClientEditor extends Component {
103134
formUpdateAction = (field, v) => {
104135
let value = v
105136
if (field === 'redirectUris') {
106-
value = v.split('\n').filter((a) => a.trim().length > 0)
137+
if (typeof v === 'string') {
138+
// Convert newline-separated string to array, then to comma-separated string
139+
const uriArray = v
140+
.split('\n')
141+
.map((uri) => uri.trim())
142+
.filter(Boolean)
143+
value = uriArray.join(',')
144+
} else if (Array.isArray(v)) {
145+
// If it's already an array, convert to comma-separated string
146+
value = v.join(',')
147+
} else {
148+
// Default to empty string
149+
value = ''
150+
}
151+
}
152+
if (field === 'authorizationGrantTypes' && Array.isArray(v)) {
153+
value = v.join(',')
107154
}
108155
this.clientModel[field] = value
109156
this.forceUpdate()

src/oauth2-client-editor/oauth2Client.actions.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,32 @@ oa2Actions.load.subscribe(() => {
1515
const no = i18n.t('No')
1616
// Map grant types to object props in order to display them in the data table
1717
oa2Store.setState(
18-
oa2ClientCollection.toArray().map((oa2c) =>
19-
Object.assign(oa2c, {
20-
password:
21-
oa2c.grantTypes.indexOf('password') !== -1
22-
? yes
23-
: no,
18+
oa2ClientCollection.toArray().map((oa2c) => {
19+
// Ensure redirectUris is a string, not an array
20+
if (
21+
oa2c.redirectUris &&
22+
Array.isArray(oa2c.redirectUris)
23+
) {
24+
oa2c.redirectUris = oa2c.redirectUris.join(',')
25+
}
26+
27+
return Object.assign(oa2c, {
2428
refresh_token:
25-
oa2c.grantTypes.indexOf('refresh_token') !== -1
29+
oa2c.authorizationGrantTypes &&
30+
oa2c.authorizationGrantTypes.indexOf(
31+
'refresh_token'
32+
) !== -1
2633
? yes
2734
: no,
2835
authorization_code:
29-
oa2c.grantTypes.indexOf(
36+
oa2c.authorizationGrantTypes &&
37+
oa2c.authorizationGrantTypes.indexOf(
3038
'authorization_code'
3139
) !== -1
3240
? yes
3341
: no,
3442
})
35-
)
43+
})
3644
)
3745
})
3846
})

0 commit comments

Comments
 (0)