@ouroboros/mouth-mui 2.1.1 → 2.1.3

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.
Files changed (29) hide show
  1. package/README.md +80 -10
  2. package/lib/components/pages/Locales.d.ts +2 -2
  3. package/lib/components/pages/Locales.js +62 -48
  4. package/lib/components/pages/Templates/Create.d.ts +2 -2
  5. package/lib/components/pages/Templates/Create.js +17 -14
  6. package/lib/components/pages/Templates/Template/Content/Create/index.d.ts +1 -1
  7. package/lib/components/pages/Templates/Template/Content/Create/index.js +44 -32
  8. package/lib/components/pages/Templates/Template/Content/Preview/index.d.ts +2 -2
  9. package/lib/components/pages/Templates/Template/Content/Preview/index.js +15 -2
  10. package/lib/components/pages/Templates/Template/Content/Update/index.d.ts +1 -1
  11. package/lib/components/pages/Templates/Template/Content/Update/index.js +36 -26
  12. package/lib/components/pages/Templates/Template/Content/View/index.d.ts +2 -2
  13. package/lib/components/pages/Templates/Template/Content/View/index.js +1 -1
  14. package/lib/components/pages/Templates/Template/index.d.ts +2 -2
  15. package/lib/components/pages/Templates/Template/index.js +18 -10
  16. package/lib/components/pages/Templates/index.d.ts +4 -4
  17. package/lib/components/pages/Templates/index.js +16 -8
  18. package/lib/locales.js +18 -15
  19. package/package.json +9 -10
  20. package/releases.md +21 -0
  21. package/src/components/pages/Locales.tsx +61 -46
  22. package/src/components/pages/Templates/Create.tsx +21 -17
  23. package/src/components/pages/Templates/Template/Content/Create/index.tsx +48 -38
  24. package/src/components/pages/Templates/Template/Content/Preview/index.tsx +20 -5
  25. package/src/components/pages/Templates/Template/Content/Update/index.tsx +38 -28
  26. package/src/components/pages/Templates/Template/Content/View/index.tsx +2 -2
  27. package/src/components/pages/Templates/Template/index.tsx +20 -13
  28. package/src/components/pages/Templates/index.tsx +20 -12
  29. package/src/locales.ts +25 -22
package/README.md CHANGED
@@ -1,15 +1,85 @@
1
1
  # @ouroboros/mouth-mui
2
+ [![npm version](https://img.shields.io/npm/v/@ouroboros/mouth-mui.svg)](https://www.npmjs.com/package/@ouroboros/mouth-mui) ![Custom License](https://img.shields.io/npm/l/@ouroboros/mouth-mui.svg)
2
3
 
3
- [![npm version](https://img.shields.io/npm/v/@ouroboros/mouth-mui.svg)](https://www.npmjs.com/package/@ouroboros/mouth-mui)
4
+ Material-UI Components for interacting with the
5
+ [mouth2_oc](https://pypi.org/project/mouth2_oc/) service. It uses
6
+ [@ouroboros/mouth](https://npmjs.com/package/@ouroboros/mouth) to handle the
7
+ actual connections.
4
8
 
5
- Shared Material-UI Components for interacting with the mouth service created by
6
- Ouroboros Coding Inc.
7
-
8
- This code comes without documentation as it's not meant to be used by anyone
9
- outside of Ouroboros Coding Inc. Please see LICENSE for further information.
9
+ See [Releases](https://github.com/ouroboroscoding/mouth-mui/blob/main/releases.md)
10
+ for changes from release to release.
10
11
 
11
12
  ## Installation
12
- npm
13
- ```bash
14
- npm install @ouroboros/mouth-mui
15
- ```
13
+ ```console
14
+ foo@bar:~$ npm install @ouroboros/mouth-mui
15
+ ```
16
+
17
+ ## Using mouth-mui
18
+ If you're using react with material-ui, this library provides components for
19
+ creating and editing locales and templates.
20
+
21
+ ### Components
22
+ - [Locales](#locales)
23
+ - [Templates](#templates)
24
+
25
+ ### Locales
26
+ `Locales` is used to setup allowable locales on the system, as well as to make
27
+ it easier to look up what locales can be chosen. It handles all C.R.U.D.
28
+ operations.
29
+
30
+ ```jsx
31
+ import { Locales } from '@ouroboros/mouth-mui';
32
+ import React from 'react';
33
+ import { addError, addMessage } from 'your_module';
34
+ function MyLocalesPage(props) {
35
+ return <Locales
36
+ onError={addError}
37
+ onSuccess={(type) => {
38
+ /* type includes [
39
+ 'create', 'delete', 'update',
40
+ ] */
41
+ addMessage(`${type} successful!`)
42
+ }}
43
+ />
44
+ }
45
+ ```
46
+
47
+ | Prop | Type | Optional | Description |
48
+ | ---- | ---- | -------- | ----------- |
49
+ | onError | <nobr>`error => void`</nobr> | yes | Callback for when an error occurs. `error` is a `responseErrorStruct` from [@ouroboros/body](https://www.npmjs.com/package/@ouroboros/body). |
50
+ | onSuccess | <nobr>`type => void`</nobr> | yes | Callback for when any of the following `type`s happen: 'create', 'delete', and 'update'. |
51
+
52
+ [ [top](#ouroborosmouth-mui) / [components](#components) ]
53
+
54
+ ### Templates
55
+ `Templates` is used to setup named templates with individual versions per locale
56
+ and method (content). For example, you could make a template with both email
57
+ content and sms content so that depending on the user's preference you have
58
+ both. Or you could have an email with both English and Spanish content. Or you
59
+ could have all instances and have multiple locales setup for both email and sms.
60
+ The component handles creating and updating for all these variations.
61
+
62
+ ```jsx
63
+ import { Templates } from '@ouroboros/mouth-mui';
64
+ import React from 'react';
65
+ import { addError, addMessage } from 'your_module';
66
+ function MyTemplatesPage(props) {
67
+ return <Templates
68
+ onError={addError}
69
+ onSuccess={(type) => {
70
+ /* type includes [
71
+ 'template_create', 'template_update',
72
+ 'content_create', 'content_update'
73
+ ] */
74
+ addMessage(`${type} successful!`)
75
+ }}
76
+ />
77
+ }
78
+ ```
79
+
80
+ | Prop | Type | Optional | Description |
81
+ | ---- | ---- | -------- | ----------- |
82
+ | onError | <nobr>`error => void`</nobr> | yes | Callback for when an error occurs. `error` is a `responseErrorStruct` from [@ouroboros/body](https://www.npmjs.com/package/@ouroboros/body). |
83
+ | onSuccess | <nobr>`type => void`</nobr> | yes | Callback for when any of the following `type`s happen: 'template_create', 'template_update', 'content_create','content_update'. |
84
+
85
+ [ [top](#ouroborosmouth-mui) / [components](#components) ]
@@ -26,8 +26,8 @@ export type LocalesProps = {
26
26
  declare function Locales({ onError, onSuccess }: LocalesProps): React.JSX.Element;
27
27
  declare namespace Locales {
28
28
  var propTypes: {
29
- onError: PropTypes.Validator<(...args: any[]) => any>;
30
- onSuccess: PropTypes.Validator<(...args: any[]) => any>;
29
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
30
+ onSuccess: PropTypes.Requireable<(...args: any[]) => any>;
31
31
  };
32
32
  }
33
33
  export default Locales;
@@ -54,7 +54,7 @@ export default function Locales({ onError, onSuccess }) {
54
54
  useEffect(() => {
55
55
  // If we have read rights
56
56
  if (rights.read) {
57
- mouth.read('locales').then(recordsSet);
57
+ mouth.read('locales').then((res) => recordsSet(res.data));
58
58
  }
59
59
  else {
60
60
  recordsSet([]);
@@ -69,11 +69,31 @@ export default function Locales({ onError, onSuccess }) {
69
69
  // Create a new Promise and return it
70
70
  return new Promise((resolve, reject) => {
71
71
  // Create the new locale
72
- mouth.create('locale', locale).then((data) => {
72
+ mouth.create('locale', locale).then((res) => {
73
+ // If we failed
74
+ if (res.error) {
75
+ if (res.error.code === errors.body.DB_NO_RECORD) {
76
+ return reject([['_id', 'Already in use']]);
77
+ }
78
+ else if (res.error.code === errors.body.DATA_FIELDS) {
79
+ return reject(res.error.msg);
80
+ }
81
+ else {
82
+ if (onError) {
83
+ onError(res.error);
84
+ return reject([]);
85
+ }
86
+ else {
87
+ throw new Error(JSON.stringify(res.error));
88
+ }
89
+ }
90
+ }
73
91
  // If we were successful
74
- if (data) {
92
+ if (res.data) {
75
93
  // Notify the parent
76
- onSuccess('create');
94
+ if (onSuccess) {
95
+ onSuccess('create');
96
+ }
77
97
  // Close the create form
78
98
  createSet(false);
79
99
  // Clone the records, add the new one to the start, and set
@@ -84,33 +104,29 @@ export default function Locales({ onError, onSuccess }) {
84
104
  locales.set(lRecords);
85
105
  }
86
106
  // Resolve with the form
87
- resolve(data ? true : false);
88
- }, (error) => {
89
- if (error.code === errors.body.DB_NO_RECORD) {
90
- reject([['_id', 'Already in use']]);
91
- }
92
- else if (error.code === errors.body.DATA_FIELDS) {
93
- reject(error.msg);
94
- }
95
- else {
96
- if (onError) {
97
- onError(error);
98
- }
99
- else {
100
- throw new Error(JSON.stringify(error));
101
- }
102
- }
107
+ resolve(res.data ? true : false);
103
108
  });
104
109
  });
105
110
  }
106
111
  // Called when the delete button on a locale was clicked
107
112
  function deleteClick(key) {
108
113
  // Delete the existing locale
109
- mouth.delete('locale', { _id: key }).then((data) => {
114
+ mouth.delete('locale', { _id: key }).then((res) => {
115
+ // If we failed
116
+ if (res.error) {
117
+ if (onError) {
118
+ return onError(res.error);
119
+ }
120
+ else {
121
+ throw new Error(JSON.stringify(res.error));
122
+ }
123
+ }
110
124
  // If it was successful
111
- if (data) {
125
+ if (res.data) {
112
126
  // Notify the parent
113
- onSuccess('delete');
127
+ if (onSuccess) {
128
+ onSuccess('delete');
129
+ }
114
130
  // Look for the record
115
131
  const i = afindi(records, '_id', key);
116
132
  // If it exists
@@ -124,13 +140,6 @@ export default function Locales({ onError, onSuccess }) {
124
140
  locales.set(lRecords);
125
141
  }
126
142
  }
127
- }, (error) => {
128
- if (onError) {
129
- onError(error);
130
- }
131
- else {
132
- throw new Error(JSON.stringify(error));
133
- }
134
143
  });
135
144
  }
136
145
  // Called when an update form is submitted
@@ -140,11 +149,28 @@ export default function Locales({ onError, onSuccess }) {
140
149
  // Create a new Promise and return it
141
150
  return new Promise((resolve, reject) => {
142
151
  // Update the locale on the server
143
- mouth.update('locale', locale).then((data) => {
152
+ mouth.update('locale', locale).then((res) => {
153
+ // If we failed
154
+ if (res.error) {
155
+ if (res.error.code === errors.body.DATA_FIELDS) {
156
+ return reject(res.error.msg);
157
+ }
158
+ else {
159
+ if (onError) {
160
+ onError(res.error);
161
+ return reject([]);
162
+ }
163
+ else {
164
+ throw new Error(JSON.stringify(res.error));
165
+ }
166
+ }
167
+ }
144
168
  // If we were successful
145
- if (data) {
169
+ if (res.data) {
146
170
  // Notify the parent
147
- onSuccess('update');
171
+ if (onSuccess) {
172
+ onSuccess('update');
173
+ }
148
174
  // Look for the record
149
175
  const i = afindi(records, '_id', key);
150
176
  // If it exists
@@ -159,19 +185,7 @@ export default function Locales({ onError, onSuccess }) {
159
185
  }
160
186
  }
161
187
  // Resolve with the Form
162
- resolve(data);
163
- }, (error) => {
164
- if (error.code === errors.body.DATA_FIELDS) {
165
- reject(error.msg);
166
- }
167
- else {
168
- if (onError) {
169
- onError(error);
170
- }
171
- else {
172
- throw new Error(JSON.stringify(error));
173
- }
174
- }
188
+ resolve(res.data);
175
189
  });
176
190
  });
177
191
  }
@@ -192,6 +206,6 @@ export default function Locales({ onError, onSuccess }) {
192
206
  }
193
207
  // Valid props
194
208
  Locales.propTypes = {
195
- onError: PropTypes.func.isRequired,
196
- onSuccess: PropTypes.func.isRequired
209
+ onError: PropTypes.func,
210
+ onSuccess: PropTypes.func
197
211
  };
@@ -13,7 +13,7 @@ import { templateStruct } from './Template';
13
13
  export interface CreateProps {
14
14
  onCancel?: () => void;
15
15
  onCreated: (template: templateStruct) => void;
16
- onError: (error: responseErrorStruct) => void;
16
+ onError?: (error: responseErrorStruct) => void;
17
17
  }
18
18
  /**
19
19
  * Create
@@ -30,7 +30,7 @@ declare namespace Create {
30
30
  var propTypes: {
31
31
  onCancel: PropTypes.Requireable<(...args: any[]) => any>;
32
32
  onCreated: PropTypes.Validator<(...args: any[]) => any>;
33
- onError: PropTypes.Validator<(...args: any[]) => any>;
33
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
34
34
  };
35
35
  }
36
36
  export default Create;
@@ -51,23 +51,26 @@ export default function Create({ onCancel, onCreated, onError }) {
51
51
  // Called to create the template
52
52
  function create() {
53
53
  // Create the data in the system
54
- mouth.create('template', record).then((data) => {
55
- // Add the ID to the record
56
- record._id = data;
57
- // Let the parent know
58
- onCreated({ ...record });
59
- }, (error) => {
60
- if (error.code === errors.body.DB_DUPLICATE) {
61
- refName.current?.error('Duplicate');
62
- }
63
- else {
64
- if (onError) {
65
- onError(error);
54
+ mouth.create('template', record).then((res) => {
55
+ // If we failed
56
+ if (res.error) {
57
+ if (res.error.code === errors.body.DB_DUPLICATE) {
58
+ refName.current?.error('Duplicate');
66
59
  }
67
60
  else {
68
- throw new Error(JSON.stringify(error));
61
+ if (onError) {
62
+ onError(res.error);
63
+ return;
64
+ }
65
+ else {
66
+ throw new Error(JSON.stringify(res.error));
67
+ }
69
68
  }
70
69
  }
70
+ // Add the ID to the record
71
+ record._id = res.data;
72
+ // Let the parent know
73
+ onCreated({ ...record });
71
74
  });
72
75
  }
73
76
  // Render
@@ -91,5 +94,5 @@ export default function Create({ onCancel, onCreated, onError }) {
91
94
  Create.propTypes = {
92
95
  onCancel: PropTypes.func,
93
96
  onCreated: PropTypes.func.isRequired,
94
- onError: PropTypes.func.isRequired,
97
+ onError: PropTypes.func,
95
98
  };
@@ -13,7 +13,7 @@ import { responseErrorStruct } from '@ouroboros/body';
13
13
  export type TemplateContentCreateProps = {
14
14
  locales: Record<string, string>;
15
15
  onCreated: (content: contentStruct) => void;
16
- onError: (error: responseErrorStruct) => void;
16
+ onError?: (error: responseErrorStruct) => void;
17
17
  template: string;
18
18
  };
19
19
  /**
@@ -50,43 +50,52 @@ export default function Create({ locales, onCreated, onError, template }) {
50
50
  // Called to create the new content record
51
51
  function create() {
52
52
  // Send the record data to the server
53
- mouth.create(`template/${type}`, record).then((data) => {
54
- // Add the type and ID
55
- const oRecord = { ...record, type, _id: data };
56
- // Tell the parent about the new record
57
- onCreated(oRecord);
58
- }, (error) => {
59
- if (error.code === errors.body.DATA_FIELDS) {
60
- fieldErrorsSet(errorTree(error.msg));
61
- }
62
- else if (error.code === errors.body.DB_DUPLICATE) {
63
- fieldErrorsSet({ locale: 'Already used' });
64
- }
65
- else if (error.code === errors.TEMPLATE_CONTENT_ERROR) {
66
- const oLines = { templates: [], variables: [] };
67
- for (const l of error.msg) {
68
- if (l[0] === 'template') {
69
- oLines.templates.push(l[1]);
53
+ mouth.create(`template/${type}`, record).then((res) => {
54
+ // If we failed
55
+ if (res.error) {
56
+ if (res.error.code === errors.body.DATA_FIELDS) {
57
+ fieldErrorsSet(errorTree(res.error.msg));
58
+ }
59
+ else if (res.error.code === errors.body.DB_DUPLICATE) {
60
+ fieldErrorsSet({ locale: 'Already used' });
61
+ }
62
+ else if (res.error.code === errors.TEMPLATE_CONTENT_ERROR) {
63
+ const oLines = { templates: [], variables: [] };
64
+ for (const l of res.error.msg) {
65
+ if (l[0] === 'template') {
66
+ oLines.templates.push(l[1]);
67
+ }
68
+ else if (l[0] === 'variable') {
69
+ oLines.variables.push(l[1]);
70
+ }
70
71
  }
71
- else if (l[0] === 'variable') {
72
- oLines.variables.push(l[1]);
72
+ const lLines = [];
73
+ if (oLines.templates.length) {
74
+ lLines.push('The following templates are invalid: ' + oLines.templates.join(', '));
75
+ }
76
+ if (oLines.variables.length) {
77
+ lLines.push('The following variables are invalid: ' + oLines.variables.join(', '));
78
+ }
79
+ // Show the errors
80
+ if (onError) {
81
+ onError({ code: 0, msg: lLines.join('\n') });
82
+ }
83
+ else {
84
+ throw new Error(JSON.stringify(res.error));
73
85
  }
74
86
  }
75
- const lLines = [];
76
- if (oLines.templates.length) {
77
- lLines.push('The following templates are invalid: ' + oLines.templates.join(', '));
78
- }
79
- if (oLines.variables.length) {
80
- lLines.push('The following variables are invalid: ' + oLines.variables.join(', '));
87
+ else if (onError) {
88
+ onError(res.error);
81
89
  }
82
- // Show the errors
83
- if (onError) {
84
- onError({ code: 0, msg: lLines.join('\n') });
90
+ else {
91
+ throw new Error(JSON.stringify(res.error));
85
92
  }
93
+ return;
86
94
  }
87
- else {
88
- onError(error);
89
- }
95
+ // Add the type and ID
96
+ const oRecord = { ...record, type, _id: res.data };
97
+ // Tell the parent about the new record
98
+ onCreated(oRecord);
90
99
  });
91
100
  }
92
101
  // Called when any fields in the record are changed
@@ -156,9 +165,12 @@ export default function Create({ locales, onCreated, onError, template }) {
156
165
  if (error.code === errors.body.DATA_FIELDS) {
157
166
  fieldErrorsSet(errorTree(error.msg));
158
167
  }
159
- else {
168
+ else if (onError) {
160
169
  onError(error);
161
170
  }
171
+ else {
172
+ throw new Error(JSON.stringify(error));
173
+ }
162
174
  previewSet(false);
163
175
  }, value: { ...record, type } }))));
164
176
  }
@@ -12,7 +12,7 @@ import { contentStruct } from '../..';
12
12
  import { responseErrorStruct } from '@ouroboros/body';
13
13
  export type PreviewProps = {
14
14
  onClose: () => void;
15
- onError: (error: responseErrorStruct) => void;
15
+ onError?: (error: responseErrorStruct) => void;
16
16
  value: contentStruct;
17
17
  };
18
18
  /**
@@ -29,7 +29,7 @@ declare function Preview({ onClose, onError, value }: PreviewProps): React.JSX.E
29
29
  declare namespace Preview {
30
30
  var propTypes: {
31
31
  onClose: PropTypes.Validator<(...args: any[]) => any>;
32
- onError: PropTypes.Validator<(...args: any[]) => any>;
32
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
33
33
  value: PropTypes.Requireable<PropTypes.InferProps<{
34
34
  locale: PropTypes.Validator<string>;
35
35
  template: PropTypes.Requireable<string>;
@@ -33,7 +33,20 @@ export default function Preview({ onClose, onError, value }) {
33
33
  const [preview, previewSet] = useState(false);
34
34
  // Value effect
35
35
  useEffect(() => {
36
- mouth.create(`template/${value.type}/generate`, value).then(previewSet, onError);
36
+ mouth.create(`template/${value.type}/generate`, value).then((res) => {
37
+ // If we failed
38
+ if (res.error) {
39
+ if (onError) {
40
+ onError(res.error);
41
+ return;
42
+ }
43
+ else {
44
+ throw new Error(JSON.stringify(res.error));
45
+ }
46
+ }
47
+ // Set the preview
48
+ previewSet(res.data);
49
+ });
37
50
  }, [value, onError]);
38
51
  // Render
39
52
  return (React.createElement(Dialog, { fullWidth: true, maxWidth: "lg", onClose: onClose, open: true, "aria-labelledby": "template-content-preview-title" },
@@ -51,7 +64,7 @@ export default function Preview({ onClose, onError, value }) {
51
64
  // Valid props
52
65
  Preview.propTypes = {
53
66
  onClose: PropTypes.func.isRequired,
54
- onError: PropTypes.func.isRequired,
67
+ onError: PropTypes.func,
55
68
  value: PropTypes.shape({
56
69
  locale: PropTypes.string.isRequired,
57
70
  template: PropTypes.string,
@@ -12,7 +12,7 @@ import { responseErrorStruct } from '@ouroboros/body';
12
12
  import { contentStruct } from '../..';
13
13
  export type updateStruct = Omit<contentStruct, 'type'>;
14
14
  export type UpdateProps = {
15
- onError: (error: responseErrorStruct) => void;
15
+ onError?: (error: responseErrorStruct) => void;
16
16
  onUpdated: (content: contentStruct) => void;
17
17
  value: contentStruct;
18
18
  };
@@ -38,37 +38,44 @@ export default function Update({ onError, onUpdated, value }) {
38
38
  // Called to create the new content record
39
39
  function update() {
40
40
  // Send the record data to the server
41
- mouth.update(`template/${value.type}`, record).then(() => {
42
- onUpdated({ type: value.type, ...record });
43
- }, (error) => {
44
- if (error.code === errors.body.DATA_FIELDS) {
45
- fieldErrorsSet(errorTree(error.msg));
46
- }
47
- else if (error.code === errors.TEMPLATE_CONTENT_ERROR) {
48
- const oLines = { templates: [], variables: [] };
49
- for (const l of error.msg) {
50
- if (l[0] === 'template') {
51
- oLines.templates.push(l[1]);
41
+ mouth.update(`template/${value.type}`, record).then((res) => {
42
+ // If we failed
43
+ if (res.error) {
44
+ if (res.error.code === errors.body.DATA_FIELDS) {
45
+ fieldErrorsSet(errorTree(res.error.msg));
46
+ }
47
+ else if (res.error.code === errors.TEMPLATE_CONTENT_ERROR) {
48
+ const oLines = { templates: [], variables: [] };
49
+ for (const l of res.error.msg) {
50
+ if (l[0] === 'template') {
51
+ oLines.templates.push(l[1]);
52
+ }
53
+ else if (l[0] === 'variable') {
54
+ oLines.variables.push(l[1]);
55
+ }
52
56
  }
53
- else if (l[0] === 'variable') {
54
- oLines.variables.push(l[1]);
57
+ const lLines = [];
58
+ if (oLines.templates.length) {
59
+ lLines.push('The following templates are invalid: ' + oLines.templates.join(', '));
60
+ }
61
+ if (oLines.variables.length) {
62
+ lLines.push('The following variables are invalid: ' + oLines.variables.join(', '));
63
+ }
64
+ // Show the errors
65
+ if (onError) {
66
+ onError({ code: 0, msg: lLines.join('\n') });
55
67
  }
56
68
  }
57
- const lLines = [];
58
- if (oLines.templates.length) {
59
- lLines.push('The following templates are invalid: ' + oLines.templates.join(', '));
60
- }
61
- if (oLines.variables.length) {
62
- lLines.push('The following variables are invalid: ' + oLines.variables.join(', '));
69
+ else if (onError) {
70
+ onError(res.error);
63
71
  }
64
- // Show the errors
65
- if (onError) {
66
- onError({ code: 0, msg: lLines.join('\n') });
72
+ else {
73
+ throw new Error(JSON.stringify(res.error));
67
74
  }
75
+ return;
68
76
  }
69
- else {
70
- onError(error);
71
- }
77
+ // Let the parent know it was updated
78
+ onUpdated({ type: value.type, ...record });
72
79
  });
73
80
  }
74
81
  // Called when any fields in the record are changed
@@ -94,9 +101,12 @@ export default function Update({ onError, onUpdated, value }) {
94
101
  if (error.code === errors.body.DATA_FIELDS) {
95
102
  fieldErrorsSet(errorTree(error.msg));
96
103
  }
97
- else {
104
+ else if (onError) {
98
105
  onError(error);
99
106
  }
107
+ else {
108
+ throw new Error(JSON.stringify(error));
109
+ }
100
110
  previewSet(false);
101
111
  }, value: { ...record, type: value.type } }))));
102
112
  }
@@ -11,7 +11,7 @@ import React from 'react';
11
11
  import { responseErrorStruct } from '@ouroboros/body';
12
12
  import { contentStruct } from '../..';
13
13
  export type ViewProps = {
14
- onError: (error: responseErrorStruct) => void;
14
+ onError?: (error: responseErrorStruct) => void;
15
15
  value: contentStruct;
16
16
  };
17
17
  /**
@@ -27,7 +27,7 @@ export type ViewProps = {
27
27
  declare function View({ onError, value }: ViewProps): React.JSX.Element;
28
28
  declare namespace View {
29
29
  var propTypes: {
30
- onError: PropTypes.Validator<(...args: any[]) => any>;
30
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
31
31
  value: PropTypes.Requireable<PropTypes.InferProps<{
32
32
  _id: PropTypes.Validator<string>;
33
33
  type: PropTypes.Validator<string>;
@@ -41,7 +41,7 @@ export default function View({ onError, value }) {
41
41
  }
42
42
  // Valid props
43
43
  View.propTypes = {
44
- onError: PropTypes.func.isRequired,
44
+ onError: PropTypes.func,
45
45
  value: PropTypes.shape({
46
46
  _id: PropTypes.string.isRequired,
47
47
  type: PropTypes.oneOf(['email', 'sms']).isRequired
@@ -33,7 +33,7 @@ export type typeOption = 'email' | 'sms';
33
33
  export type TemplateProps = {
34
34
  locales: Record<string, string>;
35
35
  onChange: (template: templateStruct) => void;
36
- onError: (error: responseErrorStruct) => void;
36
+ onError?: (error: responseErrorStruct) => void;
37
37
  onContent: (type: string) => void;
38
38
  rights: {
39
39
  template: idStruct;
@@ -58,7 +58,7 @@ declare namespace Template {
58
58
  [x: string]: string | null | undefined;
59
59
  }>;
60
60
  onChange: PropTypes.Validator<(...args: any[]) => any>;
61
- onError: PropTypes.Validator<(...args: any[]) => any>;
61
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
62
62
  onContent: PropTypes.Validator<(...args: any[]) => any>;
63
63
  rights: PropTypes.Requireable<Required<PropTypes.InferProps<{
64
64
  template: PropTypes.Validator<Required<PropTypes.InferProps<{