@ouroboros/mouth-mui 1.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.
Files changed (60) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +15 -0
  3. package/package.json +55 -0
  4. package/src/components/pages/Locales.d.ts +35 -0
  5. package/src/components/pages/Locales.js +188 -0
  6. package/src/components/pages/Locales.tsx +254 -0
  7. package/src/components/pages/Templates/Create.d.ts +36 -0
  8. package/src/components/pages/Templates/Create.js +98 -0
  9. package/src/components/pages/Templates/Create.tsx +139 -0
  10. package/src/components/pages/Templates/Template/Content/Create/Email.d.ts +39 -0
  11. package/src/components/pages/Templates/Template/Content/Create/Email.js +51 -0
  12. package/src/components/pages/Templates/Template/Content/Create/Email.tsx +96 -0
  13. package/src/components/pages/Templates/Template/Content/Create/SMS.d.ts +37 -0
  14. package/src/components/pages/Templates/Template/Content/Create/SMS.js +42 -0
  15. package/src/components/pages/Templates/Template/Content/Create/SMS.tsx +68 -0
  16. package/src/components/pages/Templates/Template/Content/Create/index.d.ts +42 -0
  17. package/src/components/pages/Templates/Template/Content/Create/index.js +177 -0
  18. package/src/components/pages/Templates/Template/Content/Create/index.tsx +257 -0
  19. package/src/components/pages/Templates/Template/Content/Preview/Email.d.ts +37 -0
  20. package/src/components/pages/Templates/Template/Content/Preview/Email.js +51 -0
  21. package/src/components/pages/Templates/Template/Content/Preview/Email.tsx +78 -0
  22. package/src/components/pages/Templates/Template/Content/Preview/SMS.d.ts +32 -0
  23. package/src/components/pages/Templates/Template/Content/Preview/SMS.js +38 -0
  24. package/src/components/pages/Templates/Template/Content/Preview/SMS.tsx +59 -0
  25. package/src/components/pages/Templates/Template/Content/Preview/index.d.ts +42 -0
  26. package/src/components/pages/Templates/Template/Content/Preview/index.js +63 -0
  27. package/src/components/pages/Templates/Template/Content/Preview/index.tsx +107 -0
  28. package/src/components/pages/Templates/Template/Content/Update/Email.d.ts +39 -0
  29. package/src/components/pages/Templates/Template/Content/Update/Email.js +51 -0
  30. package/src/components/pages/Templates/Template/Content/Update/Email.tsx +96 -0
  31. package/src/components/pages/Templates/Template/Content/Update/SMS.d.ts +37 -0
  32. package/src/components/pages/Templates/Template/Content/Update/SMS.js +42 -0
  33. package/src/components/pages/Templates/Template/Content/Update/SMS.tsx +68 -0
  34. package/src/components/pages/Templates/Template/Content/Update/index.d.ts +42 -0
  35. package/src/components/pages/Templates/Template/Content/Update/index.js +117 -0
  36. package/src/components/pages/Templates/Template/Content/Update/index.tsx +162 -0
  37. package/src/components/pages/Templates/Template/Content/View/Email.d.ts +43 -0
  38. package/src/components/pages/Templates/Template/Content/View/Email.js +57 -0
  39. package/src/components/pages/Templates/Template/Content/View/Email.tsx +80 -0
  40. package/src/components/pages/Templates/Template/Content/View/SMS.d.ts +41 -0
  41. package/src/components/pages/Templates/Template/Content/View/SMS.js +46 -0
  42. package/src/components/pages/Templates/Template/Content/View/SMS.tsx +64 -0
  43. package/src/components/pages/Templates/Template/Content/View/index.d.ts +39 -0
  44. package/src/components/pages/Templates/Template/Content/View/index.js +50 -0
  45. package/src/components/pages/Templates/Template/Content/View/index.tsx +78 -0
  46. package/src/components/pages/Templates/Template/Variables.d.ts +34 -0
  47. package/src/components/pages/Templates/Template/Variables.js +91 -0
  48. package/src/components/pages/Templates/Template/Variables.tsx +138 -0
  49. package/src/components/pages/Templates/Template/index.d.ts +90 -0
  50. package/src/components/pages/Templates/Template/index.js +207 -0
  51. package/src/components/pages/Templates/Template/index.tsx +337 -0
  52. package/src/components/pages/Templates/index.d.ts +35 -0
  53. package/src/components/pages/Templates/index.js +112 -0
  54. package/src/components/pages/Templates/index.tsx +165 -0
  55. package/src/index.d.ts +5 -0
  56. package/src/index.js +5 -0
  57. package/src/index.ts +8 -0
  58. package/src/locales.d.ts +72 -0
  59. package/src/locales.js +160 -0
  60. package/src/locales.ts +200 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Communications Templates Variables
3
+ *
4
+ * Variables component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-20
8
+ */
9
+ // Ouroboros modules
10
+ import clone from '@ouroboros/clone';
11
+ import { Node } from '@ouroboros/define';
12
+ import { DefineNode } from '@ouroboros/define-mui';
13
+ import { omap } from '@ouroboros/tools';
14
+ // NPM modules
15
+ import PropTypes from 'prop-types';
16
+ import React, { useRef } from 'react';
17
+ // Material UI
18
+ import Box from '@mui/material/Box';
19
+ import Grid from '@mui/material/Grid';
20
+ import IconButton from '@mui/material/IconButton';
21
+ import TextField from '@mui/material/TextField';
22
+ import Tooltip from '@mui/material/Tooltip';
23
+ // Create hash node
24
+ const oNameNode = new Node({
25
+ __type__: 'string',
26
+ __regex__: '^[a-z_]+$'
27
+ });
28
+ /**
29
+ * Variables
30
+ *
31
+ * Handles template locale management
32
+ *
33
+ * @name Variables
34
+ * @access public
35
+ * @param Object props Properties passed to the component
36
+ * @returns React.Component
37
+ */
38
+ export default function Variables(props) {
39
+ // Refs
40
+ const refName = useRef(null);
41
+ const refValue = useRef(null);
42
+ // Called when a new variable is added
43
+ function add() {
44
+ // Clone the current value
45
+ const oValue = clone(props.value);
46
+ // If we have references to the inputs
47
+ if (refName.current && refValue.current) {
48
+ // Add the new item to it
49
+ oValue[refName.current.value] = refValue.current.value;
50
+ // Reset the name and value
51
+ refName.current.reset();
52
+ refValue.current.value = '';
53
+ }
54
+ // Let the parent know
55
+ props.onChange(oValue);
56
+ }
57
+ // Called when an existing variables needs to be removed
58
+ function remove(name) {
59
+ // Clone the current value
60
+ const oValue = clone(props.value);
61
+ // Delete the given key if it exists
62
+ if (name in oValue) {
63
+ delete oValue[name];
64
+ }
65
+ // Let the parent know
66
+ props.onChange(oValue);
67
+ }
68
+ // Render
69
+ return (React.createElement(Box, null,
70
+ React.createElement(Grid, { container: true, spacing: 1 },
71
+ omap(props.value, (v, k) => React.createElement(React.Fragment, null,
72
+ React.createElement(Grid, { item: true, xs: 5 }, k),
73
+ React.createElement(Grid, { item: true, xs: 5 }, v),
74
+ React.createElement(Grid, { item: true, xs: 2 },
75
+ React.createElement(Tooltip, { title: "More" },
76
+ React.createElement(IconButton, { className: "icon", onClick: ev => remove(k) },
77
+ React.createElement("i", { className: "fa-solid fa-trash-alt" })))))),
78
+ React.createElement(Grid, { item: true, xs: 5, className: "field" },
79
+ React.createElement(DefineNode, { label: "placeholder", name: "name", node: oNameNode, placeholder: "Name", ref: refName, type: "create", variant: "outlined" })),
80
+ React.createElement(Grid, { item: true, xs: 5, className: "field" },
81
+ React.createElement(TextField, { inputRef: refValue, placeholder: "testing value" })),
82
+ React.createElement(Grid, { item: true, xs: 2 },
83
+ React.createElement(Tooltip, { title: "More" },
84
+ React.createElement(IconButton, { className: "icon", onClick: add },
85
+ React.createElement("i", { className: "fa-solid fa-plus" })))))));
86
+ }
87
+ // Valid props
88
+ Variables.propTypes = {
89
+ onChange: PropTypes.func.isRequired,
90
+ value: PropTypes.objectOf(PropTypes.string).isRequired
91
+ };
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Communications Templates Variables
3
+ *
4
+ * Variables component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-20
8
+ */
9
+
10
+ // Ouroboros modules
11
+ import clone from '@ouroboros/clone';
12
+ import { Node } from '@ouroboros/define';
13
+ import { DefineNode } from '@ouroboros/define-mui';
14
+ import { omap } from '@ouroboros/tools';
15
+
16
+ // NPM modules
17
+ import PropTypes from 'prop-types';
18
+ import React, { useRef } from 'react';
19
+
20
+ // Material UI
21
+ import Box from '@mui/material/Box';
22
+ import Grid from '@mui/material/Grid';
23
+ import IconButton from '@mui/material/IconButton';
24
+ import TextField from '@mui/material/TextField';
25
+ import Tooltip from '@mui/material/Tooltip';
26
+
27
+ // Create hash node
28
+ const oNameNode = new Node({
29
+ __type__: 'string',
30
+ __regex__: '^[a-z_]+$'
31
+ })
32
+
33
+ // Types
34
+ export type VariablesProps = {
35
+ onChange: (variables: Record<string, string>) => void,
36
+ value: Record<string, string>
37
+ }
38
+
39
+ /**
40
+ * Variables
41
+ *
42
+ * Handles template locale management
43
+ *
44
+ * @name Variables
45
+ * @access public
46
+ * @param Object props Properties passed to the component
47
+ * @returns React.Component
48
+ */
49
+ export default function Variables(props: VariablesProps) {
50
+
51
+ // Refs
52
+ const refName = useRef<DefineNode>(null);
53
+ const refValue = useRef<HTMLInputElement>(null);
54
+
55
+ // Called when a new variable is added
56
+ function add() {
57
+
58
+ // Clone the current value
59
+ const oValue: Record<string, string> = clone(props.value);
60
+
61
+ // If we have references to the inputs
62
+ if(refName.current && refValue.current) {
63
+
64
+ // Add the new item to it
65
+ oValue[refName.current.value] = refValue.current.value;
66
+
67
+ // Reset the name and value
68
+ refName.current.reset();
69
+ refValue.current.value = '';
70
+ }
71
+
72
+ // Let the parent know
73
+ props.onChange(oValue);
74
+ }
75
+
76
+ // Called when an existing variables needs to be removed
77
+ function remove(name: string) {
78
+
79
+ // Clone the current value
80
+ const oValue = clone(props.value);
81
+
82
+ // Delete the given key if it exists
83
+ if(name in oValue) {
84
+ delete oValue[name];
85
+ }
86
+
87
+ // Let the parent know
88
+ props.onChange(oValue);
89
+ }
90
+
91
+ // Render
92
+ return (
93
+ <Box>
94
+ <Grid container spacing={1}>
95
+ {omap(props.value, (v,k) =>
96
+ <React.Fragment>
97
+ <Grid item xs={5}>{k}</Grid>
98
+ <Grid item xs={5}>{v}</Grid>
99
+ <Grid item xs={2}>
100
+ <Tooltip title="More">
101
+ <IconButton className="icon" onClick={ev => remove(k)}>
102
+ <i className="fa-solid fa-trash-alt" />
103
+ </IconButton>
104
+ </Tooltip>
105
+ </Grid>
106
+ </React.Fragment>
107
+ )}
108
+ <Grid item xs={5} className="field">
109
+ <DefineNode
110
+ label="placeholder"
111
+ name="name"
112
+ node={oNameNode}
113
+ placeholder="Name"
114
+ ref={refName}
115
+ type="create"
116
+ variant="outlined"
117
+ />
118
+ </Grid>
119
+ <Grid item xs={5} className="field">
120
+ <TextField inputRef={refValue} placeholder="testing value" />
121
+ </Grid>
122
+ <Grid item xs={2}>
123
+ <Tooltip title="More">
124
+ <IconButton className="icon" onClick={add}>
125
+ <i className="fa-solid fa-plus" />
126
+ </IconButton>
127
+ </Tooltip>
128
+ </Grid>
129
+ </Grid>
130
+ </Box>
131
+ );
132
+ }
133
+
134
+ // Valid props
135
+ Variables.propTypes = {
136
+ onChange: PropTypes.func.isRequired,
137
+ value: PropTypes.objectOf(PropTypes.string).isRequired
138
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Communications Templates Template
3
+ *
4
+ * Template component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-20
8
+ */
9
+ /// <reference types="react" />
10
+ import PropTypes from 'prop-types';
11
+ import { responseErrorStruct } from '@ouroboros/body';
12
+ import { rightsStruct } from '@ouroboros/brain-mui';
13
+ export type contentStruct = {
14
+ _id?: string;
15
+ _created?: number;
16
+ _updated?: number;
17
+ template: string;
18
+ locale: string;
19
+ content?: string;
20
+ subject?: string;
21
+ text?: string;
22
+ type: typeOption;
23
+ html?: string;
24
+ };
25
+ export type templateStruct = {
26
+ _id?: string;
27
+ _created?: number;
28
+ _updated?: number;
29
+ name: string;
30
+ variables: Record<string, string>;
31
+ };
32
+ export type typeOption = 'email' | 'sms';
33
+ export type TemplateProps = {
34
+ locales: Record<string, string>;
35
+ mobile: boolean;
36
+ onChange: (template: templateStruct) => void;
37
+ onError: (error: responseErrorStruct) => void;
38
+ onContent: (type: string) => void;
39
+ rights: {
40
+ template: rightsStruct;
41
+ content: rightsStruct;
42
+ };
43
+ value: templateStruct;
44
+ };
45
+ /**
46
+ * Template
47
+ *
48
+ * Handles a single template
49
+ *
50
+ * @name Template
51
+ * @access public
52
+ * @param Object props Properties passed to the component
53
+ * @returns React.Component
54
+ */
55
+ declare function Template(props: TemplateProps): JSX.Element;
56
+ declare namespace Template {
57
+ var propTypes: {
58
+ locales: PropTypes.Validator<{
59
+ [x: string]: string | null | undefined;
60
+ }>;
61
+ mobile: PropTypes.Validator<boolean>;
62
+ onChange: PropTypes.Validator<(...args: any[]) => any>;
63
+ onError: PropTypes.Validator<(...args: any[]) => any>;
64
+ onContent: PropTypes.Validator<(...args: any[]) => any>;
65
+ rights: PropTypes.Requireable<Required<PropTypes.InferProps<{
66
+ template: PropTypes.Validator<Required<PropTypes.InferProps<{
67
+ create: PropTypes.Requireable<boolean>;
68
+ delete: PropTypes.Requireable<boolean>;
69
+ read: PropTypes.Requireable<boolean>;
70
+ update: PropTypes.Requireable<boolean>;
71
+ }>>>;
72
+ content: PropTypes.Validator<Required<PropTypes.InferProps<{
73
+ create: PropTypes.Requireable<boolean>;
74
+ delete: PropTypes.Requireable<boolean>;
75
+ read: PropTypes.Requireable<boolean>;
76
+ update: PropTypes.Requireable<boolean>;
77
+ }>>>;
78
+ }>>>;
79
+ value: PropTypes.Validator<Required<PropTypes.InferProps<{
80
+ _id: PropTypes.Validator<string>;
81
+ _created: PropTypes.Requireable<number>;
82
+ _updated: PropTypes.Requireable<number>;
83
+ name: PropTypes.Validator<string>;
84
+ variables: PropTypes.Validator<{
85
+ [x: string]: string | null | undefined;
86
+ }>;
87
+ }>>>;
88
+ };
89
+ }
90
+ export default Template;
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Communications Templates Template
3
+ *
4
+ * Template component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-20
8
+ */
9
+ // Ouroboros modules
10
+ import clone from '@ouroboros/clone';
11
+ import { Node } from '@ouroboros/define';
12
+ import { DefineNode } from '@ouroboros/define-mui';
13
+ import mouth, { errors } from '@ouroboros/mouth';
14
+ import TemplateDef from '@ouroboros/mouth/definitions/template.json';
15
+ import { afindi, omap, ucfirst } from '@ouroboros/tools';
16
+ // NPM modules
17
+ import PropTypes from 'prop-types';
18
+ import React, { useRef, useState } from 'react';
19
+ // Material UI
20
+ import Box from '@mui/material/Box';
21
+ import Button from '@mui/material/Button';
22
+ import Grid from '@mui/material/Grid';
23
+ import IconButton from '@mui/material/IconButton';
24
+ import Paper from '@mui/material/Paper';
25
+ import Tab from '@mui/material/Tab';
26
+ import Tabs from '@mui/material/Tabs';
27
+ import Tooltip from '@mui/material/Tooltip';
28
+ import Typography from '@mui/material/Typography';
29
+ // Local components
30
+ import ContentCreate from './Content/Create';
31
+ import ContentUpdate from './Content/Update';
32
+ import ContentView from './Content/View';
33
+ import Variables from './Variables';
34
+ // Format Node
35
+ const oNameNode = new Node(TemplateDef.name);
36
+ /**
37
+ * Template
38
+ *
39
+ * Handles a single template
40
+ *
41
+ * @name Template
42
+ * @access public
43
+ * @param Object props Properties passed to the component
44
+ * @returns React.Component
45
+ */
46
+ export default function Template(props) {
47
+ // State
48
+ const [contents, contentsSet] = useState(false);
49
+ const [tab, tabSet] = useState(0);
50
+ const [edit, editSet] = useState(false);
51
+ const [view, viewSet] = useState(false);
52
+ // Refs
53
+ const refName = useRef(null);
54
+ // Called when the update record changes
55
+ function change(field, value) {
56
+ // Set the new record
57
+ editSet(o => {
58
+ const oRecord = clone(o);
59
+ oRecord[field] = value;
60
+ return oRecord;
61
+ });
62
+ }
63
+ // Called when a single conent record is created
64
+ function contentCreated(content) {
65
+ // Notify the parent
66
+ props.onContent('create');
67
+ // Clone the current contents
68
+ const lContents = clone(contents);
69
+ // Add the new record to the end of the array
70
+ lContents.push(content);
71
+ // Set the new contents
72
+ contentsSet(lContents);
73
+ }
74
+ // Called when a single content record is updated
75
+ function contentUpdated(content) {
76
+ // Notify the parent
77
+ props.onContent('update');
78
+ // Find the index of the record
79
+ const i = afindi(contents, '_id', content._id);
80
+ // If we got an index
81
+ if (i > -1) {
82
+ // Clone the current contents, merge the current record with the
83
+ // new one, and set the new contents
84
+ const lContents = clone(contents);
85
+ lContents[i] = { ...lContents[i], ...content };
86
+ contentsSet(lContents);
87
+ }
88
+ }
89
+ // Called to delete the template
90
+ function remove() {
91
+ throw new Error('Remove template not implemented');
92
+ }
93
+ // Called to update the template
94
+ function update() {
95
+ // Create the data in the system
96
+ mouth.update('template', edit).then((data) => {
97
+ // Hide the form
98
+ editSet(false);
99
+ // Let the parent know
100
+ props.onChange(edit);
101
+ }, (error) => {
102
+ if (error.code === errors.body.DB_DUPLICATE) {
103
+ refName.current?.error('Duplicate');
104
+ }
105
+ else {
106
+ return false;
107
+ }
108
+ });
109
+ }
110
+ // View toggle
111
+ function viewToggle() {
112
+ if (view) {
113
+ viewSet(false);
114
+ }
115
+ else {
116
+ if (contents === false) {
117
+ mouth.read('template/contents', {
118
+ template: props.value._id
119
+ }).then(contentsSet);
120
+ }
121
+ viewSet(true);
122
+ }
123
+ }
124
+ // Render
125
+ return (React.createElement(Paper, { className: "template padding" },
126
+ React.createElement(Box, { className: "flexColumns" },
127
+ React.createElement(Box, { className: "flexGrow link", onClick: viewToggle },
128
+ React.createElement("h2", null,
129
+ ucfirst(props.value.name.replace(/_/g, ' ')),
130
+ "\u00A0\u00A0",
131
+ React.createElement("i", { className: 'fa-solid fa-angle-' + (view ? 'up' : 'down') }))),
132
+ React.createElement(Box, { className: "flexStatic" },
133
+ props.rights.template.update &&
134
+ React.createElement(Tooltip, { title: "Edit the Template" },
135
+ React.createElement(IconButton, { className: "icon", onClick: ev => editSet(edit ? false : clone(props.value)) },
136
+ React.createElement("i", { className: 'fa-solid fa-edit ' + (edit ? 'open' : 'closed') }))),
137
+ props.rights.template.delete &&
138
+ React.createElement(Tooltip, { title: "Delete the Template" },
139
+ React.createElement(IconButton, { className: "icon", onClick: remove },
140
+ React.createElement("i", { className: "fa-solid fa-trash-alt" }))))),
141
+ edit &&
142
+ React.createElement(React.Fragment, null,
143
+ React.createElement("hr", null),
144
+ React.createElement("h3", null, "Update Template"),
145
+ React.createElement(Grid, { container: true, spacing: 2 },
146
+ React.createElement(Grid, { item: true, lg: 6, md: 12, className: "field" },
147
+ React.createElement(Typography, null,
148
+ React.createElement("strong", null, "Name")),
149
+ React.createElement(DefineNode, { label: "none", name: "name", node: oNameNode, onChange: value => change('name', value), onEnterPressed: update, ref: refName, type: "update", value: edit.name })),
150
+ React.createElement(Grid, { item: true, lg: 6, md: 12 },
151
+ React.createElement(Typography, null,
152
+ React.createElement("strong", null, "Variables")),
153
+ React.createElement(Variables, { onChange: value => change('variables', value), value: edit.variables || {} })),
154
+ React.createElement(Grid, { item: true, xs: 12, className: "actions" },
155
+ React.createElement(Button, { variant: "contained", color: "secondary", onClick: () => editSet(false) }, "Cancel"),
156
+ React.createElement(Button, { variant: "contained", color: "primary", onClick: update }, "Save")))),
157
+ !edit && view &&
158
+ React.createElement(React.Fragment, null,
159
+ React.createElement("hr", null),
160
+ React.createElement(Grid, { container: true, spacing: 1 },
161
+ React.createElement(Grid, { item: true, xs: 12, md: 9, xl: 10 },
162
+ React.createElement(Tabs, { onChange: (ev, val) => tabSet(val), scrollButtons: "auto", variant: "scrollable", value: tab },
163
+ contents && contents.map(o => React.createElement(Tab, { key: o._id, label: props.locales[o.locale] + ' ' + o.type })),
164
+ props.rights.content.create &&
165
+ React.createElement(Tab, { label: React.createElement("i", { className: "fa-solid fa-plus" }) })),
166
+ React.createElement(Box, { className: "padding" },
167
+ React.createElement("br", null),
168
+ (contents && tab < contents.length &&
169
+ (props.rights.content.update ?
170
+ React.createElement(ContentUpdate, { key: contents[tab]._id, mobile: props.mobile, onError: props.onError, onUpdated: contentUpdated, value: contents[tab] })
171
+ :
172
+ React.createElement(ContentView, { key: contents[tab]._id, mobile: props.mobile, onError: props.onError, value: contents[tab] }))) ||
173
+ ((props.rights.content.create && contents && tab === contents.length) &&
174
+ React.createElement(ContentCreate, { locales: props.locales, mobile: props.mobile, onCreated: contentCreated, onError: props.onError, template: props.value._id })))),
175
+ React.createElement(Grid, { item: true, xs: 12, md: 3, xl: 2 },
176
+ React.createElement("h4", null, "Available Variables"),
177
+ props.value && omap(props.value.variables, (v, k) => React.createElement(Typography, { key: k }, '{' + k + '}')))))));
178
+ }
179
+ // Valid props
180
+ Template.propTypes = {
181
+ locales: PropTypes.objectOf(PropTypes.string).isRequired,
182
+ mobile: PropTypes.bool.isRequired,
183
+ onChange: PropTypes.func.isRequired,
184
+ onError: PropTypes.func.isRequired,
185
+ onContent: PropTypes.func.isRequired,
186
+ rights: PropTypes.exact({
187
+ template: PropTypes.exact({
188
+ create: PropTypes.bool,
189
+ delete: PropTypes.bool,
190
+ read: PropTypes.bool,
191
+ update: PropTypes.bool
192
+ }).isRequired,
193
+ content: PropTypes.exact({
194
+ create: PropTypes.bool,
195
+ delete: PropTypes.bool,
196
+ read: PropTypes.bool,
197
+ update: PropTypes.bool
198
+ }).isRequired
199
+ }),
200
+ value: PropTypes.exact({
201
+ _id: PropTypes.string.isRequired,
202
+ _created: PropTypes.number,
203
+ _updated: PropTypes.number,
204
+ name: PropTypes.string.isRequired,
205
+ variables: PropTypes.objectOf(PropTypes.string).isRequired
206
+ }).isRequired
207
+ };