@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.
- package/LICENSE +8 -0
- package/README.md +15 -0
- package/package.json +55 -0
- package/src/components/pages/Locales.d.ts +35 -0
- package/src/components/pages/Locales.js +188 -0
- package/src/components/pages/Locales.tsx +254 -0
- package/src/components/pages/Templates/Create.d.ts +36 -0
- package/src/components/pages/Templates/Create.js +98 -0
- package/src/components/pages/Templates/Create.tsx +139 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.tsx +96 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.js +42 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.tsx +68 -0
- package/src/components/pages/Templates/Template/Content/Create/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Create/index.js +177 -0
- package/src/components/pages/Templates/Template/Content/Create/index.tsx +257 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.tsx +78 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.d.ts +32 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.js +38 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.tsx +59 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.js +63 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.tsx +107 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.tsx +96 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.js +42 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.tsx +68 -0
- package/src/components/pages/Templates/Template/Content/Update/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Update/index.js +117 -0
- package/src/components/pages/Templates/Template/Content/Update/index.tsx +162 -0
- package/src/components/pages/Templates/Template/Content/View/Email.d.ts +43 -0
- package/src/components/pages/Templates/Template/Content/View/Email.js +57 -0
- package/src/components/pages/Templates/Template/Content/View/Email.tsx +80 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.d.ts +41 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.js +46 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.tsx +64 -0
- package/src/components/pages/Templates/Template/Content/View/index.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/View/index.js +50 -0
- package/src/components/pages/Templates/Template/Content/View/index.tsx +78 -0
- package/src/components/pages/Templates/Template/Variables.d.ts +34 -0
- package/src/components/pages/Templates/Template/Variables.js +91 -0
- package/src/components/pages/Templates/Template/Variables.tsx +138 -0
- package/src/components/pages/Templates/Template/index.d.ts +90 -0
- package/src/components/pages/Templates/Template/index.js +207 -0
- package/src/components/pages/Templates/Template/index.tsx +337 -0
- package/src/components/pages/Templates/index.d.ts +35 -0
- package/src/components/pages/Templates/index.js +112 -0
- package/src/components/pages/Templates/index.tsx +165 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +5 -0
- package/src/index.ts +8 -0
- package/src/locales.d.ts +72 -0
- package/src/locales.js +160 -0
- package/src/locales.ts +200 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Ouroboros Coding Inc. License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Ouroboros Coding Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, with limits, to any person using this software
|
|
6
|
+
within a project created by Ouroboros Coding Inc. Any attempt to modify this
|
|
7
|
+
code, or use it outside projects created by Ouroboros Coding Inc, will result
|
|
8
|
+
in legal action taken against the party using the code.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @ouroboros/mouth-mui
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ouroboros/mouth-mui)
|
|
4
|
+
|
|
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.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
npm
|
|
13
|
+
```bash
|
|
14
|
+
npm install @ouroboros/mouth-mui
|
|
15
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ouroboros/mouth-mui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Components for use with the Mouth service",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tslint -p tsconfig.json && tsc",
|
|
9
|
+
"clean": "cd src; find . -type f -name \"*.js\" -delete; find . -type f -name \"*.d.ts\" -delete",
|
|
10
|
+
"for_local": "npm install; tslint -p tsconfig.json && tsc; rm -Rf node_modules",
|
|
11
|
+
"test": "echo \"Error: no test specified.\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/ouroboroscoding/mouth-mui.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"@ouroboros/mouth",
|
|
19
|
+
"material-ui",
|
|
20
|
+
"mui",
|
|
21
|
+
"react"
|
|
22
|
+
],
|
|
23
|
+
"author": "Chris Nasr <chris@ouroboroscoding.com>",
|
|
24
|
+
"license": "CUSTOM",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/ouroboroscoding/mouth-mui/issues"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^18.14.0",
|
|
30
|
+
"@types/react": "^18.0.28",
|
|
31
|
+
"@types/uuid": "^9.0.0",
|
|
32
|
+
"tslint": "^6.1.3",
|
|
33
|
+
"tslint-config-prettier": "^1.18.0",
|
|
34
|
+
"typescript": "^4.8.3"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@ouroboros/clone": "^1.0.1",
|
|
38
|
+
"@ouroboros/define": "^1.0.2",
|
|
39
|
+
"@ouroboros/define-mui": "^1.0.3",
|
|
40
|
+
"@ouroboros/react-radiobuttons-mui": "^1.0.0",
|
|
41
|
+
"@ouroboros/subscribe": "^1.2.0",
|
|
42
|
+
"@ouroboros/tools": "^0.4.1",
|
|
43
|
+
"prop-types": "^15.8.1"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@emotion/react": "^11.8.2",
|
|
47
|
+
"@emotion/styled": "^11.8.1",
|
|
48
|
+
"@mui/material": "^5.5.1",
|
|
49
|
+
"@ouroboros/body": "^1.0.0",
|
|
50
|
+
"@ouroboros/brain-mui": "^1.0.0",
|
|
51
|
+
"@ouroboros/mouth": "^1.0.0",
|
|
52
|
+
"react": "^17.0.2",
|
|
53
|
+
"react-dom": "^17.0.2"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communications Locales
|
|
3
|
+
*
|
|
4
|
+
* Locales page
|
|
5
|
+
*
|
|
6
|
+
* @author Chris Nasr <chris@ouroboroscoding.com>
|
|
7
|
+
* @created 2023-01-19
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="react" />
|
|
10
|
+
import PropTypes from 'prop-types';
|
|
11
|
+
import { responseErrorStruct } from '@ouroboros/body';
|
|
12
|
+
export type LocalesProps = {
|
|
13
|
+
mobile: boolean;
|
|
14
|
+
onError: (error: responseErrorStruct) => void;
|
|
15
|
+
onSuccess: (type: string) => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Locales
|
|
19
|
+
*
|
|
20
|
+
* Handles template locale management
|
|
21
|
+
*
|
|
22
|
+
* @name Locales
|
|
23
|
+
* @access public
|
|
24
|
+
* @param Object props Properties passed to the component
|
|
25
|
+
* @returns React.Component
|
|
26
|
+
*/
|
|
27
|
+
declare function Locales(props: LocalesProps): JSX.Element;
|
|
28
|
+
declare namespace Locales {
|
|
29
|
+
var propTypes: {
|
|
30
|
+
mobile: PropTypes.Validator<boolean>;
|
|
31
|
+
onError: PropTypes.Validator<(...args: any[]) => any>;
|
|
32
|
+
onSuccess: PropTypes.Validator<(...args: any[]) => any>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export default Locales;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communications Locales
|
|
3
|
+
*
|
|
4
|
+
* Locales page
|
|
5
|
+
*
|
|
6
|
+
* @author Chris Nasr <chris@ouroboroscoding.com>
|
|
7
|
+
* @created 2023-01-19
|
|
8
|
+
*/
|
|
9
|
+
// Ouroboros modules
|
|
10
|
+
import { Myself } from '@ouroboros/brain-mui';
|
|
11
|
+
import clone from '@ouroboros/clone';
|
|
12
|
+
import { Tree } from '@ouroboros/define';
|
|
13
|
+
import { Form, Results } from '@ouroboros/define-mui';
|
|
14
|
+
import mouth, { errors } from '@ouroboros/mouth';
|
|
15
|
+
import LocaleDef from '@ouroboros/mouth/definitions/locale.json';
|
|
16
|
+
import { afindi, merge } from '@ouroboros/tools';
|
|
17
|
+
// NPM modules
|
|
18
|
+
import PropTypes from 'prop-types';
|
|
19
|
+
import React, { useEffect, useState } from 'react';
|
|
20
|
+
// Material UI
|
|
21
|
+
import Box from '@mui/material/Box';
|
|
22
|
+
import IconButton from '@mui/material/IconButton';
|
|
23
|
+
import Paper from '@mui/material/Paper';
|
|
24
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
25
|
+
// Local modules
|
|
26
|
+
import locales from '../../locales';
|
|
27
|
+
// Generate the user Tree
|
|
28
|
+
const LocaleTree = new Tree(LocaleDef);
|
|
29
|
+
/**
|
|
30
|
+
* Locales
|
|
31
|
+
*
|
|
32
|
+
* Handles template locale management
|
|
33
|
+
*
|
|
34
|
+
* @name Locales
|
|
35
|
+
* @access public
|
|
36
|
+
* @param Object props Properties passed to the component
|
|
37
|
+
* @returns React.Component
|
|
38
|
+
*/
|
|
39
|
+
export default function Locales(props) {
|
|
40
|
+
// State
|
|
41
|
+
const [create, createSet] = useState(false);
|
|
42
|
+
const [records, recordsSet] = useState([]);
|
|
43
|
+
// Hooks
|
|
44
|
+
const rights = Myself.useRights('mouth_locale');
|
|
45
|
+
// User / archived change effect
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
// If we have read rights
|
|
48
|
+
if (rights.read) {
|
|
49
|
+
mouth.read('locale').then(recordsSet);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
recordsSet([]);
|
|
53
|
+
}
|
|
54
|
+
// If we don't have create rights
|
|
55
|
+
if (!rights.create) {
|
|
56
|
+
createSet(false);
|
|
57
|
+
}
|
|
58
|
+
}, [rights]);
|
|
59
|
+
// Called when a create form is submitted
|
|
60
|
+
function createSubmit(locale) {
|
|
61
|
+
// Create a new Promise and return it
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
// Create the new locale
|
|
64
|
+
mouth.create('locale').then((data) => {
|
|
65
|
+
// If we were successful
|
|
66
|
+
if (data) {
|
|
67
|
+
// Notify the parent
|
|
68
|
+
props.onSuccess('create');
|
|
69
|
+
// Close the create form
|
|
70
|
+
createSet(false);
|
|
71
|
+
// Clone the records, add the new one to the start, and set the new
|
|
72
|
+
// records
|
|
73
|
+
const lRecords = clone(records);
|
|
74
|
+
lRecords.unshift(locale);
|
|
75
|
+
recordsSet(lRecords);
|
|
76
|
+
// Send the clone to the locales
|
|
77
|
+
locales.set(lRecords);
|
|
78
|
+
}
|
|
79
|
+
// Resolve with the form
|
|
80
|
+
resolve(data ? true : false);
|
|
81
|
+
}, (error) => {
|
|
82
|
+
if (error.code === errors.body.DB_NO_RECORD) {
|
|
83
|
+
reject([['_id', 'Already in use']]);
|
|
84
|
+
}
|
|
85
|
+
else if (error.code === errors.body.DATA_FIELDS) {
|
|
86
|
+
reject(error.msg);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
if (props.onError) {
|
|
90
|
+
props.onError(error);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw new Error(JSON.stringify(error));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// Called when the delete button on a locale was clicked
|
|
100
|
+
function deleteClick(key) {
|
|
101
|
+
// Delete the existing locale
|
|
102
|
+
mouth.delete('locale', { _id: key }).then((data) => {
|
|
103
|
+
// If it was successful
|
|
104
|
+
if (data) {
|
|
105
|
+
// Notify the parent
|
|
106
|
+
props.onSuccess('delete');
|
|
107
|
+
// Look for the record
|
|
108
|
+
const i = afindi(records, '_id', key);
|
|
109
|
+
// If it exists
|
|
110
|
+
if (i > -1) {
|
|
111
|
+
// Clone the records, delete the index, and set the new records
|
|
112
|
+
const lRecords = clone(records);
|
|
113
|
+
lRecords.splice(i, 1);
|
|
114
|
+
recordsSet(lRecords);
|
|
115
|
+
// Send the clone to the locales
|
|
116
|
+
locales.set(lRecords);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}, (error) => {
|
|
120
|
+
if (props.onError) {
|
|
121
|
+
props.onError(error);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new Error(JSON.stringify(error));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// Called when an update form is submitted
|
|
129
|
+
function updateSubmit(locale, key) {
|
|
130
|
+
// Add the ID to the locale
|
|
131
|
+
locale._id = key;
|
|
132
|
+
// Create a new Promise and return it
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
// Update the locale on the server
|
|
135
|
+
mouth.update('locale', locale).then((data) => {
|
|
136
|
+
// If we were successful
|
|
137
|
+
if (data) {
|
|
138
|
+
// Notify the parent
|
|
139
|
+
props.onSuccess('update');
|
|
140
|
+
// Look for the record
|
|
141
|
+
const i = afindi(records, '_id', key);
|
|
142
|
+
// If it exists
|
|
143
|
+
if (i > -1) {
|
|
144
|
+
// Clone the records, update the index, and set the new records
|
|
145
|
+
const lRecords = clone(records);
|
|
146
|
+
merge(lRecords[i], locale);
|
|
147
|
+
recordsSet(lRecords);
|
|
148
|
+
// Send the clone to the locales
|
|
149
|
+
locales.set(lRecords);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Resolve with the Form
|
|
153
|
+
resolve(data);
|
|
154
|
+
}, (error) => {
|
|
155
|
+
if (error.code === errors.body.DATA_FIELDS) {
|
|
156
|
+
reject(error.msg);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
if (props.onError) {
|
|
160
|
+
props.onError(error);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
throw new Error(JSON.stringify(error));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Render
|
|
170
|
+
return (React.createElement(Box, { id: "mouth_locales", className: "flexGrow padding" },
|
|
171
|
+
React.createElement(Box, { className: "flexColumns" },
|
|
172
|
+
React.createElement("h1", { className: "flexGrow" }, "Locales"),
|
|
173
|
+
rights.create &&
|
|
174
|
+
React.createElement(Box, { className: "flexStatic" },
|
|
175
|
+
React.createElement(Tooltip, { title: "Create new Locale", className: "page_action", onClick: () => createSet(b => !b) },
|
|
176
|
+
React.createElement(IconButton, null,
|
|
177
|
+
React.createElement("i", { className: 'fa-solid fa-plus' + (create ? ' open' : '') }))))),
|
|
178
|
+
create &&
|
|
179
|
+
React.createElement(Paper, { className: "padding" },
|
|
180
|
+
React.createElement(Form, { onCancel: () => createSet(false), onSubmit: createSubmit, tree: LocaleTree, type: "create" })),
|
|
181
|
+
React.createElement(Results, { data: records, orderBy: "name", onDelete: rights.delete ? deleteClick : false, onUpdate: rights.update ? updateSubmit : false, tree: LocaleTree })));
|
|
182
|
+
}
|
|
183
|
+
// Valid props
|
|
184
|
+
Locales.propTypes = {
|
|
185
|
+
mobile: PropTypes.bool.isRequired,
|
|
186
|
+
onError: PropTypes.func.isRequired,
|
|
187
|
+
onSuccess: PropTypes.func.isRequired
|
|
188
|
+
};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communications Locales
|
|
3
|
+
*
|
|
4
|
+
* Locales page
|
|
5
|
+
*
|
|
6
|
+
* @author Chris Nasr <chris@ouroboroscoding.com>
|
|
7
|
+
* @created 2023-01-19
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Ouroboros modules
|
|
11
|
+
import { Myself } from '@ouroboros/brain-mui';
|
|
12
|
+
import clone from '@ouroboros/clone';
|
|
13
|
+
import { Tree } from '@ouroboros/define'
|
|
14
|
+
import { Form, Results } from '@ouroboros/define-mui';
|
|
15
|
+
import mouth, { errors } from '@ouroboros/mouth';
|
|
16
|
+
import LocaleDef from '@ouroboros/mouth/definitions/locale.json';
|
|
17
|
+
import { afindi, merge } from '@ouroboros/tools';
|
|
18
|
+
|
|
19
|
+
// NPM modules
|
|
20
|
+
import PropTypes from 'prop-types';
|
|
21
|
+
import React, { useEffect, useState } from 'react';
|
|
22
|
+
|
|
23
|
+
// Material UI
|
|
24
|
+
import Box from '@mui/material/Box';
|
|
25
|
+
import IconButton from '@mui/material/IconButton';
|
|
26
|
+
import Paper from '@mui/material/Paper';
|
|
27
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
28
|
+
|
|
29
|
+
// Local modules
|
|
30
|
+
import locales from '../../locales';
|
|
31
|
+
|
|
32
|
+
// Generate the user Tree
|
|
33
|
+
const LocaleTree = new Tree(LocaleDef);
|
|
34
|
+
|
|
35
|
+
// Types
|
|
36
|
+
import { responseErrorStruct } from '@ouroboros/body';
|
|
37
|
+
export type LocalesProps = {
|
|
38
|
+
mobile: boolean,
|
|
39
|
+
onError: (error: responseErrorStruct) => void,
|
|
40
|
+
onSuccess: (type: string) => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Locales
|
|
45
|
+
*
|
|
46
|
+
* Handles template locale management
|
|
47
|
+
*
|
|
48
|
+
* @name Locales
|
|
49
|
+
* @access public
|
|
50
|
+
* @param Object props Properties passed to the component
|
|
51
|
+
* @returns React.Component
|
|
52
|
+
*/
|
|
53
|
+
export default function Locales(props: LocalesProps) {
|
|
54
|
+
|
|
55
|
+
// State
|
|
56
|
+
const [create, createSet] = useState<boolean>(false);
|
|
57
|
+
const [records, recordsSet] = useState<any[]>([]);
|
|
58
|
+
|
|
59
|
+
// Hooks
|
|
60
|
+
const rights = Myself.useRights('mouth_locale');
|
|
61
|
+
|
|
62
|
+
// User / archived change effect
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
|
|
65
|
+
// If we have read rights
|
|
66
|
+
if(rights.read) {
|
|
67
|
+
mouth.read('locale').then(recordsSet);
|
|
68
|
+
} else {
|
|
69
|
+
recordsSet([]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// If we don't have create rights
|
|
73
|
+
if(!rights.create) {
|
|
74
|
+
createSet(false);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}, [rights]);
|
|
78
|
+
|
|
79
|
+
// Called when a create form is submitted
|
|
80
|
+
function createSubmit(locale: any): Promise<boolean> {
|
|
81
|
+
|
|
82
|
+
// Create a new Promise and return it
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
|
|
85
|
+
// Create the new locale
|
|
86
|
+
mouth.create('locale').then((data: string) => {
|
|
87
|
+
|
|
88
|
+
// If we were successful
|
|
89
|
+
if(data) {
|
|
90
|
+
|
|
91
|
+
// Notify the parent
|
|
92
|
+
props.onSuccess('create');
|
|
93
|
+
|
|
94
|
+
// Close the create form
|
|
95
|
+
createSet(false);
|
|
96
|
+
|
|
97
|
+
// Clone the records, add the new one to the start, and set the new
|
|
98
|
+
// records
|
|
99
|
+
const lRecords = clone(records);
|
|
100
|
+
lRecords.unshift(locale);
|
|
101
|
+
recordsSet(lRecords);
|
|
102
|
+
|
|
103
|
+
// Send the clone to the locales
|
|
104
|
+
locales.set(lRecords);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Resolve with the form
|
|
108
|
+
resolve(data ? true : false);
|
|
109
|
+
|
|
110
|
+
}, (error: responseErrorStruct) => {
|
|
111
|
+
if(error.code === errors.body.DB_NO_RECORD) {
|
|
112
|
+
reject([['_id', 'Already in use']]);
|
|
113
|
+
} else if(error.code === errors.body.DATA_FIELDS) {
|
|
114
|
+
reject(error.msg);
|
|
115
|
+
} else {
|
|
116
|
+
if(props.onError) {
|
|
117
|
+
props.onError(error);
|
|
118
|
+
} else {
|
|
119
|
+
throw new Error(JSON.stringify(error));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Called when the delete button on a locale was clicked
|
|
127
|
+
function deleteClick(key: string) {
|
|
128
|
+
|
|
129
|
+
// Delete the existing locale
|
|
130
|
+
mouth.delete('locale', { _id: key }).then((data: boolean) => {
|
|
131
|
+
|
|
132
|
+
// If it was successful
|
|
133
|
+
if(data) {
|
|
134
|
+
|
|
135
|
+
// Notify the parent
|
|
136
|
+
props.onSuccess('delete');
|
|
137
|
+
|
|
138
|
+
// Look for the record
|
|
139
|
+
const i = afindi(records, '_id', key);
|
|
140
|
+
|
|
141
|
+
// If it exists
|
|
142
|
+
if(i > -1) {
|
|
143
|
+
|
|
144
|
+
// Clone the records, delete the index, and set the new records
|
|
145
|
+
const lRecords = clone(records);
|
|
146
|
+
lRecords.splice(i, 1);
|
|
147
|
+
recordsSet(lRecords);
|
|
148
|
+
|
|
149
|
+
// Send the clone to the locales
|
|
150
|
+
locales.set(lRecords);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}, (error: responseErrorStruct) => {
|
|
154
|
+
if(props.onError) {
|
|
155
|
+
props.onError(error);
|
|
156
|
+
} else {
|
|
157
|
+
throw new Error(JSON.stringify(error));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Called when an update form is submitted
|
|
163
|
+
function updateSubmit(locale: any, key: string): Promise<boolean> {
|
|
164
|
+
|
|
165
|
+
// Add the ID to the locale
|
|
166
|
+
locale._id = key;
|
|
167
|
+
|
|
168
|
+
// Create a new Promise and return it
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
|
|
171
|
+
// Update the locale on the server
|
|
172
|
+
mouth.update('locale', locale).then((data: boolean) => {
|
|
173
|
+
|
|
174
|
+
// If we were successful
|
|
175
|
+
if(data) {
|
|
176
|
+
|
|
177
|
+
// Notify the parent
|
|
178
|
+
props.onSuccess('update');
|
|
179
|
+
|
|
180
|
+
// Look for the record
|
|
181
|
+
const i = afindi(records, '_id', key);
|
|
182
|
+
|
|
183
|
+
// If it exists
|
|
184
|
+
if(i > -1) {
|
|
185
|
+
|
|
186
|
+
// Clone the records, update the index, and set the new records
|
|
187
|
+
const lRecords = clone(records);
|
|
188
|
+
merge(lRecords[i], locale);
|
|
189
|
+
recordsSet(lRecords);
|
|
190
|
+
|
|
191
|
+
// Send the clone to the locales
|
|
192
|
+
locales.set(lRecords);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Resolve with the Form
|
|
197
|
+
resolve(data);
|
|
198
|
+
|
|
199
|
+
}, (error: responseErrorStruct) => {
|
|
200
|
+
if(error.code === errors.body.DATA_FIELDS) {
|
|
201
|
+
reject(error.msg);
|
|
202
|
+
} else {
|
|
203
|
+
if(props.onError) {
|
|
204
|
+
props.onError(error);
|
|
205
|
+
} else {
|
|
206
|
+
throw new Error(JSON.stringify(error));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Render
|
|
214
|
+
return (
|
|
215
|
+
<Box id="mouth_locales" className="flexGrow padding">
|
|
216
|
+
<Box className="flexColumns">
|
|
217
|
+
<h1 className="flexGrow">Locales</h1>
|
|
218
|
+
{rights.create &&
|
|
219
|
+
<Box className="flexStatic">
|
|
220
|
+
<Tooltip title="Create new Locale" className="page_action" onClick={() => createSet(b => !b)}>
|
|
221
|
+
<IconButton>
|
|
222
|
+
<i className={'fa-solid fa-plus' + (create ? ' open' : '')} />
|
|
223
|
+
</IconButton>
|
|
224
|
+
</Tooltip>
|
|
225
|
+
</Box>
|
|
226
|
+
}
|
|
227
|
+
</Box>
|
|
228
|
+
{create &&
|
|
229
|
+
<Paper className="padding">
|
|
230
|
+
<Form
|
|
231
|
+
onCancel={() => createSet(false)}
|
|
232
|
+
onSubmit={createSubmit}
|
|
233
|
+
tree={LocaleTree}
|
|
234
|
+
type="create"
|
|
235
|
+
/>
|
|
236
|
+
</Paper>
|
|
237
|
+
}
|
|
238
|
+
<Results
|
|
239
|
+
data={records}
|
|
240
|
+
orderBy="name"
|
|
241
|
+
onDelete={rights.delete ? deleteClick : false}
|
|
242
|
+
onUpdate={rights.update ? updateSubmit : false}
|
|
243
|
+
tree={LocaleTree}
|
|
244
|
+
/>
|
|
245
|
+
</Box>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Valid props
|
|
250
|
+
Locales.propTypes = {
|
|
251
|
+
mobile: PropTypes.bool.isRequired,
|
|
252
|
+
onError: PropTypes.func.isRequired,
|
|
253
|
+
onSuccess: PropTypes.func.isRequired
|
|
254
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Templates Create
|
|
3
|
+
*
|
|
4
|
+
* Create 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 { templateStruct } from './Template';
|
|
13
|
+
export interface CreateProps {
|
|
14
|
+
onCancel?: () => void;
|
|
15
|
+
onCreated: (template: templateStruct) => void;
|
|
16
|
+
onError: (error: responseErrorStruct) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create
|
|
20
|
+
*
|
|
21
|
+
* Form for creating a new template
|
|
22
|
+
*
|
|
23
|
+
* @name Create
|
|
24
|
+
* @access public
|
|
25
|
+
* @param Object props Properties passed to the component
|
|
26
|
+
* @returns React.Component
|
|
27
|
+
*/
|
|
28
|
+
declare function Create(props: CreateProps): JSX.Element;
|
|
29
|
+
declare namespace Create {
|
|
30
|
+
var propTypes: {
|
|
31
|
+
onCancel: PropTypes.Requireable<(...args: any[]) => any>;
|
|
32
|
+
onCreated: PropTypes.Validator<(...args: any[]) => any>;
|
|
33
|
+
onError: PropTypes.Validator<(...args: any[]) => any>;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export default Create;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Templates Create
|
|
3
|
+
*
|
|
4
|
+
* Create 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
|
+
// NPM modules
|
|
16
|
+
import PropTypes from 'prop-types';
|
|
17
|
+
import React, { useRef, useState } from 'react';
|
|
18
|
+
// Material UI
|
|
19
|
+
import Button from '@mui/material/Button';
|
|
20
|
+
import Grid from '@mui/material/Grid';
|
|
21
|
+
import Paper from '@mui/material/Paper';
|
|
22
|
+
import Typography from '@mui/material/Typography';
|
|
23
|
+
// Locale components
|
|
24
|
+
import Variables from './Template/Variables';
|
|
25
|
+
// Format Node
|
|
26
|
+
const oNameNode = new Node(TemplateDef.name);
|
|
27
|
+
/**
|
|
28
|
+
* Create
|
|
29
|
+
*
|
|
30
|
+
* Form for creating a new template
|
|
31
|
+
*
|
|
32
|
+
* @name Create
|
|
33
|
+
* @access public
|
|
34
|
+
* @param Object props Properties passed to the component
|
|
35
|
+
* @returns React.Component
|
|
36
|
+
*/
|
|
37
|
+
export default function Create(props) {
|
|
38
|
+
// State
|
|
39
|
+
const [record, recordSet] = useState({
|
|
40
|
+
name: '',
|
|
41
|
+
variables: {}
|
|
42
|
+
});
|
|
43
|
+
// Refs
|
|
44
|
+
const refName = useRef(null);
|
|
45
|
+
// Called when record changes
|
|
46
|
+
function change(field, value) {
|
|
47
|
+
// Set the new record
|
|
48
|
+
recordSet(o => {
|
|
49
|
+
const oRecord = clone(o);
|
|
50
|
+
oRecord[field] = value;
|
|
51
|
+
return oRecord;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Called to create the template
|
|
55
|
+
function create() {
|
|
56
|
+
// Create the data in the system
|
|
57
|
+
mouth.create('template', record).then(data => {
|
|
58
|
+
// Add the ID to the record
|
|
59
|
+
record._id = data;
|
|
60
|
+
// Let the parent know
|
|
61
|
+
props.onCreated(clone(record));
|
|
62
|
+
}, error => {
|
|
63
|
+
if (error.code === errors.body.DB_DUPLICATE) {
|
|
64
|
+
refName.current?.error('Duplicate');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
if (props.onError) {
|
|
68
|
+
props.onError(error);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw new Error(JSON.stringify(error));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Render
|
|
77
|
+
return (React.createElement(Paper, { className: "padding" },
|
|
78
|
+
React.createElement("h2", null, "Create new Template"),
|
|
79
|
+
React.createElement(Grid, { container: true, spacing: 2 },
|
|
80
|
+
React.createElement(Grid, { item: true, lg: 6, md: 12, className: "field" },
|
|
81
|
+
React.createElement(Typography, null,
|
|
82
|
+
React.createElement("strong", null, "Name")),
|
|
83
|
+
React.createElement(DefineNode, { label: "none", name: "name", node: oNameNode, onChange: value => change('name', value), onEnterPressed: create, ref: refName, type: "create", value: record.name || null })),
|
|
84
|
+
React.createElement(Grid, { item: true, lg: 6, md: 12 },
|
|
85
|
+
React.createElement(Typography, null,
|
|
86
|
+
React.createElement("strong", null, "Variables")),
|
|
87
|
+
React.createElement(Variables, { onChange: value => change('variables', value), value: record.variables || {} })),
|
|
88
|
+
React.createElement(Grid, { item: true, xs: 12, className: "actions" },
|
|
89
|
+
props.onCancel &&
|
|
90
|
+
React.createElement(Button, { variant: "contained", color: "secondary", onClick: props.onCancel }, "Cancel"),
|
|
91
|
+
React.createElement(Button, { variant: "contained", color: "primary", onClick: create }, "Create Template")))));
|
|
92
|
+
}
|
|
93
|
+
// Valid props
|
|
94
|
+
Create.propTypes = {
|
|
95
|
+
onCancel: PropTypes.func,
|
|
96
|
+
onCreated: PropTypes.func.isRequired,
|
|
97
|
+
onError: PropTypes.func.isRequired,
|
|
98
|
+
};
|