@uportal/form-builder 1.3.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/form-builder.js +699 -0
- package/dist/form-builder.js.map +1 -0
- package/dist/form-builder.min.js +317 -0
- package/dist/form-builder.min.js.map +1 -0
- package/package.json +35 -53
- package/src/form-builder.js +673 -0
- package/CHANGELOG.md +0 -219
- package/build/asset-manifest.json +0 -7
- package/build/favicon.ico +0 -0
- package/build/index.html +0 -1
- package/build/manifest.json +0 -15
- package/build/precache-manifest.bc02b68aae246724a7d787bc3e33c53d.js +0 -10
- package/build/sample/communication-preferences/form.json +0 -0
- package/build/service-worker.js +0 -34
- package/build/static/js/form-builder.js +0 -2
- package/build/static/js/form-builder.js.map +0 -1
- package/src/App.js +0 -301
- package/src/App.test.js +0 -9
- package/src/setupProxy.js +0 -8
package/src/App.js
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { Component } from 'react';
|
|
3
|
-
import Form from "react-jsonschema-form";
|
|
4
|
-
import PropTypes from 'prop-types';
|
|
5
|
-
import oidc from '@uportal/open-id-connect';
|
|
6
|
-
import get from 'lodash.get';
|
|
7
|
-
import { library } from '@fortawesome/fontawesome-svg-core';
|
|
8
|
-
import { faExclamationCircle, faCheckCircle } from '@fortawesome/free-solid-svg-icons';
|
|
9
|
-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
10
|
-
import 'regenerator-runtime/runtime';
|
|
11
|
-
|
|
12
|
-
library.add(faExclamationCircle, faCheckCircle);
|
|
13
|
-
|
|
14
|
-
// FIXME: remove this
|
|
15
|
-
const log = (type) => console.log.bind(console, type);
|
|
16
|
-
|
|
17
|
-
class App extends Component {
|
|
18
|
-
static propTypes = {
|
|
19
|
-
fbmsBaseUrl: PropTypes.string,
|
|
20
|
-
fbmsFormFname: PropTypes.string.isRequired,
|
|
21
|
-
oidcUrl: PropTypes.string,
|
|
22
|
-
showErrorList: PropTypes.bool,
|
|
23
|
-
styles: PropTypes.string
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
static defaultProps = {
|
|
27
|
-
fbmsBaseUrl: '/fbms',
|
|
28
|
-
showErrorList: true
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
state = {
|
|
32
|
-
schema: {},
|
|
33
|
-
uiSchema: {},
|
|
34
|
-
formData: {},
|
|
35
|
-
hasError: false,
|
|
36
|
-
submissionStatus: {},
|
|
37
|
-
hasSuccess: false,
|
|
38
|
-
fbmsFormFname: this.props.fbmsFormFname,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
handleOidcError = (err) => {
|
|
42
|
-
console.error(err);
|
|
43
|
-
this.setState({hasError: true, errorMessage: 'There was a problem authorizing this request.'});
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
handleFbmsError = (err) => {
|
|
47
|
-
if (err.type === 'submission') {
|
|
48
|
-
err.messageHeader = 'There was a problem submitting your form.';
|
|
49
|
-
} else {
|
|
50
|
-
err.messageHeader = 'There was a problem finding your form.';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.setState({hasError: true});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
handleChange = (data) => {
|
|
57
|
-
this.setState({formData: data.formData});
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
getToken = async () => {
|
|
61
|
-
const {oidcUrl} = this.props;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
return (await oidc({userInfoApiUrl: oidcUrl, timeout: 18000}));
|
|
65
|
-
} catch (err) {
|
|
66
|
-
console.error(err);
|
|
67
|
-
this.handleOidcError(err);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
fetchSchema = async () => {
|
|
72
|
-
const {fbmsBaseUrl} = this.props;
|
|
73
|
-
const {fbmsFormFname} = this.state;
|
|
74
|
-
try {
|
|
75
|
-
const response = await fetch(fbmsBaseUrl + '/api/v1/forms/' + fbmsFormFname, {
|
|
76
|
-
credentials: 'same-origin',
|
|
77
|
-
headers: {
|
|
78
|
-
'Authorization': 'Bearer ' + (await this.getToken()).encoded,
|
|
79
|
-
'content-type': 'application/jwt',
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
if (!response.ok) {
|
|
84
|
-
throw new Error(response.statusText);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const payload = await response.json();
|
|
88
|
-
const fbmsFormVersion = payload.version;
|
|
89
|
-
const uiSchema = payload.metadata;
|
|
90
|
-
const schema = payload.schema;
|
|
91
|
-
|
|
92
|
-
this.setState({fbmsFormVersion, schema, uiSchema});
|
|
93
|
-
this.fetchFormData();
|
|
94
|
-
} catch (err) {
|
|
95
|
-
// error
|
|
96
|
-
this.handleFbmsError(err);
|
|
97
|
-
console.error(err);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
fetchFormData = async () => {
|
|
102
|
-
const {fbmsBaseUrl} = this.props;
|
|
103
|
-
const {fbmsFormFname} = this.state;
|
|
104
|
-
|
|
105
|
-
// Add a random query string token to the URL to get around the way
|
|
106
|
-
// Safari caches content, despite explicit Cache-Control header settings.
|
|
107
|
-
const submissionUrl = fbmsBaseUrl + '/api/v1/submissions/' + fbmsFormFname + '?safarifix=' + Math.random();
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
const response = await fetch(submissionUrl, {
|
|
111
|
-
credentials: 'same-origin',
|
|
112
|
-
headers: {
|
|
113
|
-
'Authorization': 'Bearer ' + (await this.getToken()).encoded,
|
|
114
|
-
'content-type': 'application/jwt',
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!response.ok) {
|
|
119
|
-
if (response.status !== 404) {
|
|
120
|
-
throw new Error(response.statusText);
|
|
121
|
-
} else {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const payload = await response.json();
|
|
127
|
-
const formData = payload.answers;
|
|
128
|
-
this.setState({formData});
|
|
129
|
-
} catch (err) {
|
|
130
|
-
console.error(err);
|
|
131
|
-
this.handleFbmsError(err);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
transformBody = (formData, username) => {
|
|
136
|
-
const {fbmsFormFname, fbmsFormVersion} = this.state;
|
|
137
|
-
return {
|
|
138
|
-
username: username,
|
|
139
|
-
formFname: fbmsFormFname,
|
|
140
|
-
formVersion: fbmsFormVersion,
|
|
141
|
-
timestamp: Date.now(),
|
|
142
|
-
answers: formData
|
|
143
|
-
};
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
conditionallyHideSubmit = (schema) => {
|
|
147
|
-
if (schema.properties && Object.keys(schema.properties).length === 0) {
|
|
148
|
-
return (
|
|
149
|
-
' '
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
submitForm = async (userFormData) => {
|
|
155
|
-
const {fbmsBaseUrl} = this.props;
|
|
156
|
-
const {fbmsFormFname} = this.state;
|
|
157
|
-
const token = await this.getToken();
|
|
158
|
-
const body = this.transformBody(userFormData, token.decoded.sub);
|
|
159
|
-
this.setState({hasError: false});
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const response = await fetch(fbmsBaseUrl + '/api/v1/submissions/' + fbmsFormFname, {
|
|
163
|
-
method: 'POST',
|
|
164
|
-
credentials: 'same-origin',
|
|
165
|
-
headers: {
|
|
166
|
-
'Authorization': 'Bearer ' + token.encoded,
|
|
167
|
-
'content-type': 'application/json',
|
|
168
|
-
},
|
|
169
|
-
body: JSON.stringify(body)
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
let submissionStatus = await response.json();
|
|
173
|
-
this.setState({submissionStatus});
|
|
174
|
-
|
|
175
|
-
if (!response.ok) {
|
|
176
|
-
submissionStatus.type = 'submission';
|
|
177
|
-
this.handleFbmsError(submissionStatus);
|
|
178
|
-
throw new Error(response.statusText);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
this.fetchFormData();
|
|
182
|
-
|
|
183
|
-
/* Note: for...of was not used here because of IE */
|
|
184
|
-
const entries = response.headers.entries();
|
|
185
|
-
let formForward,
|
|
186
|
-
item = entries.next();
|
|
187
|
-
while (!item.done) {
|
|
188
|
-
let headerName = item.value[0],
|
|
189
|
-
headerValue = item.value[1];
|
|
190
|
-
if (headerName.toLowerCase() === 'x-fbms-formforward') {
|
|
191
|
-
formForward = headerValue;
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
item = entries.next();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (formForward) {
|
|
198
|
-
this.setState({fbmsFormFname: formForward});
|
|
199
|
-
this.getForm();
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
this.setState({hasSuccess: true});
|
|
203
|
-
this.scrollToNotification();
|
|
204
|
-
} catch (err) {
|
|
205
|
-
console.error(err);
|
|
206
|
-
this.scrollToNotification();
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
scrollToNotification = () => {
|
|
211
|
-
const element = document.getElementById('form-builder-notification');
|
|
212
|
-
if (element) {
|
|
213
|
-
element.scrollIntoView({behavior: 'smooth'});
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
getForm = () => {
|
|
218
|
-
this.fetchSchema();
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Allows any message from a validation rule to be overridden.
|
|
223
|
-
* Overrides come from a "messages" object, with a property matching the
|
|
224
|
-
* rule that will be overridden.
|
|
225
|
-
* For example to override a string pattern, that following schema could be
|
|
226
|
-
* used.
|
|
227
|
-
*
|
|
228
|
-
* "example": {
|
|
229
|
-
* "type": "string",
|
|
230
|
-
* "pattern": "^[A-Z]{3}$",
|
|
231
|
-
* "messages": {
|
|
232
|
-
* "pattern": "Must be three upper case letters"
|
|
233
|
-
* }
|
|
234
|
-
* }
|
|
235
|
-
*/
|
|
236
|
-
transformErrors = (errors) => errors.map((err) => {
|
|
237
|
-
const {property, name} = err;
|
|
238
|
-
const {schema} = this.state;
|
|
239
|
-
const pathParts = property.split('.');
|
|
240
|
-
const prefix = pathParts.join('.properties.').substring(1); // remove leading period (.)
|
|
241
|
-
const messageLocation = prefix + '.messages.' + name;
|
|
242
|
-
const customMessage = get(schema, messageLocation);
|
|
243
|
-
if (customMessage) {
|
|
244
|
-
err.message = customMessage;
|
|
245
|
-
}
|
|
246
|
-
return err;
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
componentDidMount = this.getForm;
|
|
250
|
-
|
|
251
|
-
render = () => {
|
|
252
|
-
const {schema, uiSchema, formData, hasError, hasSuccess, submissionStatus} = this.state;
|
|
253
|
-
const onSubmit = ({formData}) => this.submitForm(formData);
|
|
254
|
-
|
|
255
|
-
return (
|
|
256
|
-
<div>
|
|
257
|
-
{this.props.styles && <style>{this.props.styles}</style>}
|
|
258
|
-
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"></link>
|
|
259
|
-
{ hasError &&
|
|
260
|
-
<div id="form-builder-notification" className="alert alert-danger" role="alert">
|
|
261
|
-
<h3><FontAwesomeIcon icon="exclamation-circle" style={{width: '1em'}} /> {submissionStatus.messageHeader}</h3>
|
|
262
|
-
{submissionStatus && submissionStatus.messages && submissionStatus.messages.length > 0 &&
|
|
263
|
-
<ul>
|
|
264
|
-
{submissionStatus.messages.map((item, index) => (
|
|
265
|
-
<li key={index}>{item}</li>
|
|
266
|
-
))}
|
|
267
|
-
</ul>
|
|
268
|
-
}
|
|
269
|
-
</div>
|
|
270
|
-
}
|
|
271
|
-
{ hasSuccess &&
|
|
272
|
-
<div id="form-builder-notification" className="alert alert-success" role="alert">
|
|
273
|
-
<FontAwesomeIcon icon="check-circle" style={{width: '1em'}} /> Your form was successfully submitted.
|
|
274
|
-
{submissionStatus && submissionStatus.messages && submissionStatus.messages.length > 0 &&
|
|
275
|
-
<ul>
|
|
276
|
-
{submissionStatus.messages.map((item, index) => (
|
|
277
|
-
<li key={index}>{item}</li>
|
|
278
|
-
))}
|
|
279
|
-
</ul>
|
|
280
|
-
}
|
|
281
|
-
</div>
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
<Form
|
|
285
|
-
schema={schema}
|
|
286
|
-
uiSchema={uiSchema}
|
|
287
|
-
formData={formData}
|
|
288
|
-
onChange={this.handleChange}
|
|
289
|
-
onSubmit={onSubmit}
|
|
290
|
-
onError={log("errors")}
|
|
291
|
-
showErrorList={this.props.showErrorList}
|
|
292
|
-
transformErrors={this.transformErrors}
|
|
293
|
-
safeRenderCompletion={true}>
|
|
294
|
-
{this.conditionallyHideSubmit(schema)}
|
|
295
|
-
</Form>
|
|
296
|
-
</div>
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
export default App;
|
package/src/App.test.js
DELETED
package/src/setupProxy.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// See: https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
|
|
2
|
-
|
|
3
|
-
const proxy = require('http-proxy-middleware');
|
|
4
|
-
|
|
5
|
-
module.exports = function(app) {
|
|
6
|
-
app.use(proxy('/uPortal', { target: 'http://localhost:8080' }));
|
|
7
|
-
app.use(proxy('/fbms', { target: 'http://localhost:8080' }));
|
|
8
|
-
};
|