devextreme-cli 1.7.1 → 1.8.0-beta.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/package.json +2 -2
- package/src/applications/application.angular.js +4 -8
- package/src/applications/application.react.js +2 -0
- package/src/applications/application.vue.js +2 -0
- package/src/commands.json +3 -6
- package/src/templates/react/application/devextreme.json +28 -0
- package/src/templates/react/application/src/App.tsx +11 -7
- package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx +86 -86
- package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.scss +3 -3
- package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx +107 -107
- package/src/templates/react/application/src/components/footer/Footer.scss +7 -4
- package/src/templates/react/application/src/components/header/Header.scss +4 -5
- package/src/templates/react/application/src/components/header/Header.tsx +8 -12
- package/src/templates/react/application/src/components/login-form/LoginForm.scss +1 -1
- package/src/templates/react/application/src/components/reset-password-form/ResetPasswordForm.scss +1 -1
- package/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.scss +49 -68
- package/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.tsx +5 -3
- package/src/templates/react/application/src/components/theme-switcher/ThemeSwitcher.tsx +20 -0
- package/src/templates/react/application/src/components/user-panel/UserPanel.scss +41 -53
- package/src/templates/react/application/src/components/user-panel/UserPanel.tsx +22 -25
- package/src/templates/react/application/src/dx-styles.scss +63 -67
- package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.scss +1 -6
- package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.scss +3 -3
- package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.tsx +2 -2
- package/src/templates/react/application/src/layouts/single-card/single-card.scss +4 -2
- package/src/templates/react/application/src/theme.tsx +51 -0
- package/src/templates/react/application/src/themes/metadata.additional.dark.json +11 -0
- package/src/templates/react/application/src/themes/metadata.additional.json +1 -1
- package/src/templates/react/application/src/themes/metadata.base.dark.json +8 -0
- package/src/templates/react/application/src/themes/metadata.base.json +1 -1
- package/src/templates/react/application/src/variables.scss +37 -0
- package/src/templates/react/page/page.tsx +1 -1
- package/src/templates/react/sample-pages/home/home.scss +20 -15
- package/src/templates/react/sample-pages/home/home.tsx +50 -4
- package/src/templates/react/sample-pages/profile/profile.tsx +1 -1
- package/src/templates/react/sample-pages/tasks/tasks.scss +3 -0
- package/src/templates/react/sample-pages/tasks/tasks.tsx +3 -2
- package/src/templates/vue-v3/application/devextreme.json +28 -0
- package/src/templates/vue-v3/application/src/App.vue +1 -5
- package/src/templates/vue-v3/application/src/components/app-footer.vue +7 -4
- package/src/templates/vue-v3/application/src/components/header-toolbar.vue +23 -30
- package/src/templates/vue-v3/application/src/components/side-nav-menu.vue +63 -73
- package/src/templates/vue-v3/application/src/components/theme-switcher.vue +19 -0
- package/src/templates/vue-v3/application/src/components/user-panel.vue +61 -81
- package/src/templates/vue-v3/application/src/dx-styles.scss +66 -51
- package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +4 -7
- package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +4 -2
- package/src/templates/vue-v3/application/src/layouts/single-card.vue +2 -4
- package/src/templates/vue-v3/application/src/theme-service.js +40 -0
- package/src/templates/vue-v3/application/src/themes/metadata.additional.dark.json +11 -0
- package/src/templates/vue-v3/application/src/themes/metadata.additional.json +1 -1
- package/src/templates/vue-v3/application/src/themes/metadata.base.dark.json +8 -0
- package/src/templates/vue-v3/application/src/themes/metadata.base.json +1 -1
- package/src/templates/vue-v3/application/src/variables.scss +37 -0
- package/src/templates/vue-v3/application/src/views/create-account-form.vue +5 -7
- package/src/templates/vue-v3/application/src/views/login-form.vue +1 -3
- package/src/templates/vue-v3/application/src/views/reset-password-form.vue +2 -4
- package/src/templates/vue-v3/page/page.vue +1 -1
- package/src/templates/vue-v3/sample-pages/home-page.vue +86 -45
- package/src/templates/vue-v3/sample-pages/profile-page.vue +1 -1
- package/src/templates/vue-v3/sample-pages/tasks-page.vue +7 -2
- package/src/utility/latest-versions.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devextreme-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0-beta.0",
|
|
4
4
|
"description": "DevExtreme CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"devexpress",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"typescript": "^4.0.2",
|
|
73
73
|
"typescript-eslint-parser": "^22.0.0"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "afe86ffa75cfe3ee7b9b5a78af5adcb2e3bb28f3"
|
|
76
76
|
}
|
|
@@ -10,8 +10,7 @@ const latestVersions = require('../utility/latest-versions');
|
|
|
10
10
|
const { extractToolingVersion, toolingVersionOptionName } = require('../utility/extract-tooling-version');
|
|
11
11
|
const schematicsVersion = latestVersions['devextreme-schematics'] || 'latest';
|
|
12
12
|
|
|
13
|
-
const minNgCliVersion = new semver('
|
|
14
|
-
const ngCliWithStandalone = new semver('17.0.0');
|
|
13
|
+
const minNgCliVersion = new semver('17.0.0');
|
|
15
14
|
|
|
16
15
|
async function runSchematicCommand(schematicCommand, options, evaluatingOptions) {
|
|
17
16
|
const collectionName = 'devextreme-schematics';
|
|
@@ -77,7 +76,6 @@ const install = async(options) => {
|
|
|
77
76
|
|
|
78
77
|
const create = async(appName, options) => {
|
|
79
78
|
const layout = await getLayoutInfo(options.layout);
|
|
80
|
-
const currentNgVersion = ngVersion.getNgCliVersion().version;
|
|
81
79
|
|
|
82
80
|
const commandArguments = [
|
|
83
81
|
'new',
|
|
@@ -85,13 +83,11 @@ const create = async(appName, options) => {
|
|
|
85
83
|
'--style=scss',
|
|
86
84
|
'--routing=false',
|
|
87
85
|
'--skip-tests=true',
|
|
88
|
-
'--skip-install=true'
|
|
86
|
+
'--skip-install=true',
|
|
87
|
+
'--standalone=false',
|
|
88
|
+
'--ssr=false'
|
|
89
89
|
];
|
|
90
90
|
|
|
91
|
-
if(ngCliWithStandalone.compare(currentNgVersion) <= 0) {
|
|
92
|
-
commandArguments.push('--standalone=false', '--ssr=false');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
91
|
await runNgCommand(commandArguments, options);
|
|
96
92
|
|
|
97
93
|
const appPath = path.join(process.cwd(), appName);
|
|
@@ -100,7 +100,9 @@ const addTemplate = (appPath, appName, templateOptions) => {
|
|
|
100
100
|
|
|
101
101
|
const styles = [
|
|
102
102
|
'./themes/generated/theme.additional.css',
|
|
103
|
+
'./themes/generated/theme.additional.dark.css',
|
|
103
104
|
'./themes/generated/theme.base.css',
|
|
105
|
+
'./themes/generated/theme.base.dark.css',
|
|
104
106
|
'devextreme/dist/css/dx.common.css'
|
|
105
107
|
];
|
|
106
108
|
|
|
@@ -77,7 +77,9 @@ const addTemplate = (appPath, appName, templateOptions) => {
|
|
|
77
77
|
const applicationTemplatePath = path.join(templateCreator.getTempaltePath('vue-v3'), 'application');
|
|
78
78
|
const styles = [
|
|
79
79
|
'./themes/generated/theme.additional.css',
|
|
80
|
+
'./themes/generated/theme.additional.dark.css',
|
|
80
81
|
'./themes/generated/theme.base.css',
|
|
82
|
+
'./themes/generated/theme.base.dark.css',
|
|
81
83
|
'devextreme/dist/css/dx.common.css'
|
|
82
84
|
];
|
|
83
85
|
|
package/src/commands.json
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"description": "Specifies base theme name (default value is generic.light)"
|
|
58
58
|
}, {
|
|
59
59
|
"name": "--input-file",
|
|
60
|
-
"description": "Specifies file name with input data (a .json file with metadata or a .
|
|
60
|
+
"description": "Specifies file name with input data (a .json file with metadata or a .scss file with Bootstrap 5 variables)"
|
|
61
61
|
}, {
|
|
62
62
|
"name": "--make-swatch",
|
|
63
63
|
"description": "If present, adds a CSS scope to each CSS rule (.dx-swatch-xxx), where xxx is the value from the --output-color-scheme parameter"
|
|
@@ -76,9 +76,6 @@
|
|
|
76
76
|
}, {
|
|
77
77
|
"name": "--remove-external-resources",
|
|
78
78
|
"description": "When present, removes links to external resources, such as fonts. The theme will use local fallbacks instead. Available from DevExtreme v20.2.7."
|
|
79
|
-
}, {
|
|
80
|
-
"name": "--bootstrap-version",
|
|
81
|
-
"description": "Specifies Bootstrap version 4 or 5 if '--input-file' is a '.scss' file. Available from DevExtreme v21.1.5. Default value: 4."
|
|
82
79
|
}]
|
|
83
80
|
}, {
|
|
84
81
|
"name": "export-theme-vars",
|
|
@@ -89,7 +86,7 @@
|
|
|
89
86
|
"description": "Specifies base theme name (default value is generic.light)"
|
|
90
87
|
}, {
|
|
91
88
|
"name": "--input-file",
|
|
92
|
-
"description": "Specifies file name with input data (a .json file with metadata or a .
|
|
89
|
+
"description": "Specifies file name with input data (a .json file with metadata or a .scss file with Bootstrap 5 variables)"
|
|
93
90
|
}, {
|
|
94
91
|
"name": "--output-format",
|
|
95
92
|
"description": "Specifies the format of output variables (less or scss) (default value is less or the extension extracted from the --output-file value (if it contains any))"
|
|
@@ -112,7 +109,7 @@
|
|
|
112
109
|
"description": "Specifies base theme name (default value is generic.light)"
|
|
113
110
|
}, {
|
|
114
111
|
"name": "--input-file",
|
|
115
|
-
"description": "Specifies file name with input data (a .json file with metadata or a .
|
|
112
|
+
"description": "Specifies file name with input data (a .json file with metadata or a .scss file with Bootstrap 5 variables)"
|
|
116
113
|
}, {
|
|
117
114
|
"name": "--output-file",
|
|
118
115
|
"description": "Specifies output file name"
|
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
"outputFile": "src/themes/generated/theme.base.css"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"command": "build-theme",
|
|
14
|
+
"options": {
|
|
15
|
+
"inputFile": "src/themes/metadata.base.dark.json",
|
|
16
|
+
"outputFile": "src/themes/generated/theme.base.dark.css"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
12
19
|
{
|
|
13
20
|
"command": "build-theme",
|
|
14
21
|
"options": {
|
|
@@ -16,6 +23,13 @@
|
|
|
16
23
|
"outputFile": "src/themes/generated/theme.additional.css"
|
|
17
24
|
}
|
|
18
25
|
},
|
|
26
|
+
{
|
|
27
|
+
"command": "build-theme",
|
|
28
|
+
"options": {
|
|
29
|
+
"inputFile": "src/themes/metadata.additional.dark.json",
|
|
30
|
+
"outputFile": "src/themes/generated/theme.additional.dark.css"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
19
33
|
{
|
|
20
34
|
"command": "export-theme-vars",
|
|
21
35
|
"options": {
|
|
@@ -23,12 +37,26 @@
|
|
|
23
37
|
"outputFile": "src/themes/generated/variables.base.scss"
|
|
24
38
|
}
|
|
25
39
|
},
|
|
40
|
+
{
|
|
41
|
+
"command": "export-theme-vars",
|
|
42
|
+
"options": {
|
|
43
|
+
"inputFile": "src/themes/metadata.base.dark.json",
|
|
44
|
+
"outputFile": "src/themes/generated/variables.base.dark.scss"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
26
47
|
{
|
|
27
48
|
"command": "export-theme-vars",
|
|
28
49
|
"options": {
|
|
29
50
|
"inputFile": "src/themes/metadata.additional.json",
|
|
30
51
|
"outputFile": "src/themes/generated/variables.additional.scss"
|
|
31
52
|
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"command": "export-theme-vars",
|
|
56
|
+
"options": {
|
|
57
|
+
"inputFile": "src/themes/metadata.additional.dark.json",
|
|
58
|
+
"outputFile": "src/themes/generated/variables.additional.dark.scss"
|
|
59
|
+
}
|
|
32
60
|
}
|
|
33
61
|
]
|
|
34
62
|
}
|
|
@@ -7,6 +7,7 @@ import { AuthProvider, useAuth } from './contexts/auth';
|
|
|
7
7
|
import { useScreenSizeClass } from './utils/media-query';
|
|
8
8
|
import Content from './Content';
|
|
9
9
|
import UnauthenticatedContent from './UnauthenticatedContent';
|
|
10
|
+
import { ThemeContext, useThemeContext} from "./theme";
|
|
10
11
|
|
|
11
12
|
function App() {
|
|
12
13
|
const { user, loading } = useAuth();
|
|
@@ -24,16 +25,19 @@ function App() {
|
|
|
24
25
|
|
|
25
26
|
export default function Root() {
|
|
26
27
|
const screenSizeClass = useScreenSizeClass();
|
|
28
|
+
const themeContext = useThemeContext();
|
|
27
29
|
|
|
28
30
|
return (
|
|
29
31
|
<Router>
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
<ThemeContext.Provider value={themeContext}>
|
|
33
|
+
<AuthProvider>
|
|
34
|
+
<NavigationProvider>
|
|
35
|
+
<div className={`app ${screenSizeClass}`}>
|
|
36
|
+
<App />
|
|
37
|
+
</div>
|
|
38
|
+
</NavigationProvider>
|
|
39
|
+
</AuthProvider>
|
|
40
|
+
</ThemeContext.Provider>
|
|
37
41
|
</Router>
|
|
38
42
|
);
|
|
39
43
|
}
|
package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
|
-
import Form, {
|
|
4
|
-
Item,
|
|
5
|
-
Label,
|
|
6
|
-
ButtonItem,
|
|
7
|
-
ButtonOptions,
|
|
8
|
-
RequiredRule,
|
|
9
|
-
CustomRule,
|
|
10
|
-
} from 'devextreme-react/form';
|
|
11
|
-
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
|
-
import notify from 'devextreme/ui/notify';
|
|
13
|
-
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
14
|
-
import { changePassword } from '../../api/auth';
|
|
15
|
-
|
|
16
|
-
export default function ChangePasswordForm() {
|
|
17
|
-
const navigate = useNavigate();
|
|
18
|
-
const [loading, setLoading] = useState(false);
|
|
19
|
-
const formData = useRef({ password: '' });
|
|
20
|
-
const { recoveryCode } = useParams();
|
|
21
|
-
|
|
22
|
-
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
const { password } = formData.current;
|
|
25
|
-
setLoading(true);
|
|
26
|
-
|
|
27
|
-
const result = await changePassword(password, recoveryCode);
|
|
28
|
-
setLoading(false);
|
|
29
|
-
|
|
30
|
-
if (result.isOk) {
|
|
31
|
-
navigate('/login');
|
|
32
|
-
} else {
|
|
33
|
-
notify(result.message, 'error', 2000);
|
|
34
|
-
}
|
|
35
|
-
}, [navigate, recoveryCode]);
|
|
36
|
-
|
|
37
|
-
const confirmPassword = useCallback(
|
|
38
|
-
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
39
|
-
[]
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<form onSubmit={onSubmit}>
|
|
44
|
-
<Form formData={formData.current} disabled={loading}>
|
|
45
|
-
<Item
|
|
46
|
-
dataField={'password'}
|
|
47
|
-
editorType={'dxTextBox'}
|
|
48
|
-
editorOptions={passwordEditorOptions}
|
|
49
|
-
>
|
|
50
|
-
<RequiredRule message="Password is required" />
|
|
51
|
-
<Label visible={false} />
|
|
52
|
-
</Item>
|
|
53
|
-
<Item
|
|
54
|
-
dataField={'confirmedPassword'}
|
|
55
|
-
editorType={'dxTextBox'}
|
|
56
|
-
editorOptions={confirmedPasswordEditorOptions}
|
|
57
|
-
>
|
|
58
|
-
<RequiredRule message="Password is required" />
|
|
59
|
-
<CustomRule
|
|
60
|
-
message={'Passwords do not match'}
|
|
61
|
-
validationCallback={confirmPassword}
|
|
62
|
-
/>
|
|
63
|
-
<Label visible={false} />
|
|
64
|
-
</Item>
|
|
65
|
-
<ButtonItem>
|
|
66
|
-
<ButtonOptions
|
|
67
|
-
width={'100%'}
|
|
68
|
-
type={'default'}
|
|
69
|
-
useSubmitBehavior={true}
|
|
70
|
-
>
|
|
71
|
-
<span className="dx-button-text">
|
|
72
|
-
{
|
|
73
|
-
loading
|
|
74
|
-
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
75
|
-
: 'Continue'
|
|
76
|
-
}
|
|
77
|
-
</span>
|
|
78
|
-
</ButtonOptions>
|
|
79
|
-
</ButtonItem>
|
|
80
|
-
</Form>
|
|
81
|
-
</form>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
86
|
-
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
1
|
+
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
|
+
import Form, {
|
|
4
|
+
Item,
|
|
5
|
+
Label,
|
|
6
|
+
ButtonItem,
|
|
7
|
+
ButtonOptions,
|
|
8
|
+
RequiredRule,
|
|
9
|
+
CustomRule,
|
|
10
|
+
} from 'devextreme-react/form';
|
|
11
|
+
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
|
+
import notify from 'devextreme/ui/notify';
|
|
13
|
+
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
14
|
+
import { changePassword } from '../../api/auth';
|
|
15
|
+
|
|
16
|
+
export default function ChangePasswordForm() {
|
|
17
|
+
const navigate = useNavigate();
|
|
18
|
+
const [loading, setLoading] = useState(false);
|
|
19
|
+
const formData = useRef({ password: '' });
|
|
20
|
+
const { recoveryCode } = useParams();
|
|
21
|
+
|
|
22
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const { password } = formData.current;
|
|
25
|
+
setLoading(true);
|
|
26
|
+
|
|
27
|
+
const result = await changePassword(password, recoveryCode);
|
|
28
|
+
setLoading(false);
|
|
29
|
+
|
|
30
|
+
if (result.isOk) {
|
|
31
|
+
navigate('/login');
|
|
32
|
+
} else {
|
|
33
|
+
notify(result.message, 'error', 2000);
|
|
34
|
+
}
|
|
35
|
+
}, [navigate, recoveryCode]);
|
|
36
|
+
|
|
37
|
+
const confirmPassword = useCallback(
|
|
38
|
+
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
39
|
+
[]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<form onSubmit={onSubmit}>
|
|
44
|
+
<Form formData={formData.current} disabled={loading}>
|
|
45
|
+
<Item
|
|
46
|
+
dataField={'password'}
|
|
47
|
+
editorType={'dxTextBox'}
|
|
48
|
+
editorOptions={passwordEditorOptions}
|
|
49
|
+
>
|
|
50
|
+
<RequiredRule message="Password is required" />
|
|
51
|
+
<Label visible={false} />
|
|
52
|
+
</Item>
|
|
53
|
+
<Item
|
|
54
|
+
dataField={'confirmedPassword'}
|
|
55
|
+
editorType={'dxTextBox'}
|
|
56
|
+
editorOptions={confirmedPasswordEditorOptions}
|
|
57
|
+
>
|
|
58
|
+
<RequiredRule message="Password is required" />
|
|
59
|
+
<CustomRule
|
|
60
|
+
message={'Passwords do not match'}
|
|
61
|
+
validationCallback={confirmPassword}
|
|
62
|
+
/>
|
|
63
|
+
<Label visible={false} />
|
|
64
|
+
</Item>
|
|
65
|
+
<ButtonItem>
|
|
66
|
+
<ButtonOptions
|
|
67
|
+
width={'100%'}
|
|
68
|
+
type={'default'}
|
|
69
|
+
useSubmitBehavior={true}
|
|
70
|
+
>
|
|
71
|
+
<span className="dx-button-text">
|
|
72
|
+
{
|
|
73
|
+
loading
|
|
74
|
+
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
75
|
+
: 'Continue'
|
|
76
|
+
}
|
|
77
|
+
</span>
|
|
78
|
+
</ButtonOptions>
|
|
79
|
+
</ButtonItem>
|
|
80
|
+
</Form>
|
|
81
|
+
</form>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
86
|
+
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.scss
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
.create-account-form {
|
|
4
4
|
.policy-info {
|
|
5
5
|
margin: 10px 0;
|
|
6
|
-
color:
|
|
6
|
+
color: var(--base-text-color-alpha-7);
|
|
7
7
|
font-size: 14px;
|
|
8
8
|
font-style: normal;
|
|
9
9
|
|
|
10
10
|
a {
|
|
11
|
-
color:
|
|
11
|
+
color: var(--base-text-color-alpha-7);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.login-link {
|
|
16
|
-
color:
|
|
16
|
+
color: var(--base-accent);
|
|
17
17
|
font-size: 16px;
|
|
18
18
|
text-align: center;
|
|
19
19
|
}
|
package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link, useNavigate } from 'react-router-dom';
|
|
3
|
-
import Form, {
|
|
4
|
-
Item,
|
|
5
|
-
Label,
|
|
6
|
-
ButtonItem,
|
|
7
|
-
ButtonOptions,
|
|
8
|
-
RequiredRule,
|
|
9
|
-
CustomRule,
|
|
10
|
-
EmailRule
|
|
11
|
-
} from 'devextreme-react/form';
|
|
12
|
-
import notify from 'devextreme/ui/notify';
|
|
13
|
-
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
|
-
import { createAccount } from '../../api/auth';
|
|
15
|
-
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
16
|
-
import './CreateAccountForm.scss';
|
|
17
|
-
|
|
18
|
-
export default function CreateAccountForm() {
|
|
19
|
-
const navigate = useNavigate();
|
|
20
|
-
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({ email: '', password: '' });
|
|
22
|
-
|
|
23
|
-
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
const { email, password } = formData.current;
|
|
26
|
-
setLoading(true);
|
|
27
|
-
|
|
28
|
-
const result = await createAccount(email, password);
|
|
29
|
-
setLoading(false);
|
|
30
|
-
|
|
31
|
-
if (result.isOk) {
|
|
32
|
-
navigate('/login');
|
|
33
|
-
} else {
|
|
34
|
-
notify(result.message, 'error', 2000);
|
|
35
|
-
}
|
|
36
|
-
}, [navigate]);
|
|
37
|
-
|
|
38
|
-
const confirmPassword = useCallback(
|
|
39
|
-
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
40
|
-
[]
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<form className={'create-account-form'} onSubmit={onSubmit}>
|
|
45
|
-
<Form formData={formData.current} disabled={loading}>
|
|
46
|
-
<Item
|
|
47
|
-
dataField={'email'}
|
|
48
|
-
editorType={'dxTextBox'}
|
|
49
|
-
editorOptions={emailEditorOptions}
|
|
50
|
-
>
|
|
51
|
-
<RequiredRule message="Email is required" />
|
|
52
|
-
<EmailRule message="Email is invalid" />
|
|
53
|
-
<Label visible={false} />
|
|
54
|
-
</Item>
|
|
55
|
-
<Item
|
|
56
|
-
dataField={'password'}
|
|
57
|
-
editorType={'dxTextBox'}
|
|
58
|
-
editorOptions={passwordEditorOptions}
|
|
59
|
-
>
|
|
60
|
-
<RequiredRule message="Password is required" />
|
|
61
|
-
<Label visible={false} />
|
|
62
|
-
</Item>
|
|
63
|
-
<Item
|
|
64
|
-
dataField={'confirmedPassword'}
|
|
65
|
-
editorType={'dxTextBox'}
|
|
66
|
-
editorOptions={confirmedPasswordEditorOptions}
|
|
67
|
-
>
|
|
68
|
-
<RequiredRule message="Password is required" />
|
|
69
|
-
<CustomRule
|
|
70
|
-
message={'Passwords do not match'}
|
|
71
|
-
validationCallback={confirmPassword}
|
|
72
|
-
/>
|
|
73
|
-
<Label visible={false} />
|
|
74
|
-
</Item>
|
|
75
|
-
<Item>
|
|
76
|
-
<div className='policy-info'>
|
|
77
|
-
By creating an account, you agree to the <Link to="#">Terms of Service</Link> and <Link to="#">Privacy Policy</Link>
|
|
78
|
-
</div>
|
|
79
|
-
</Item>
|
|
80
|
-
<ButtonItem>
|
|
81
|
-
<ButtonOptions
|
|
82
|
-
width={'100%'}
|
|
83
|
-
type={'default'}
|
|
84
|
-
useSubmitBehavior={true}
|
|
85
|
-
>
|
|
86
|
-
<span className="dx-button-text">
|
|
87
|
-
{
|
|
88
|
-
loading
|
|
89
|
-
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
90
|
-
: 'Create a new account'
|
|
91
|
-
}
|
|
92
|
-
</span>
|
|
93
|
-
</ButtonOptions>
|
|
94
|
-
</ButtonItem>
|
|
95
|
-
<Item>
|
|
96
|
-
<div className={'login-link'}>
|
|
97
|
-
Have an account? <Link to={'/login'}>Sign In</Link>
|
|
98
|
-
</div>
|
|
99
|
-
</Item>
|
|
100
|
-
</Form>
|
|
101
|
-
</form>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
|
|
106
|
-
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
107
|
-
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
1
|
+
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
|
+
import Form, {
|
|
4
|
+
Item,
|
|
5
|
+
Label,
|
|
6
|
+
ButtonItem,
|
|
7
|
+
ButtonOptions,
|
|
8
|
+
RequiredRule,
|
|
9
|
+
CustomRule,
|
|
10
|
+
EmailRule
|
|
11
|
+
} from 'devextreme-react/form';
|
|
12
|
+
import notify from 'devextreme/ui/notify';
|
|
13
|
+
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
|
+
import { createAccount } from '../../api/auth';
|
|
15
|
+
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
16
|
+
import './CreateAccountForm.scss';
|
|
17
|
+
|
|
18
|
+
export default function CreateAccountForm() {
|
|
19
|
+
const navigate = useNavigate();
|
|
20
|
+
const [loading, setLoading] = useState(false);
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
|
+
|
|
23
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
const { email, password } = formData.current;
|
|
26
|
+
setLoading(true);
|
|
27
|
+
|
|
28
|
+
const result = await createAccount(email, password);
|
|
29
|
+
setLoading(false);
|
|
30
|
+
|
|
31
|
+
if (result.isOk) {
|
|
32
|
+
navigate('/login');
|
|
33
|
+
} else {
|
|
34
|
+
notify(result.message, 'error', 2000);
|
|
35
|
+
}
|
|
36
|
+
}, [navigate]);
|
|
37
|
+
|
|
38
|
+
const confirmPassword = useCallback(
|
|
39
|
+
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
40
|
+
[]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<form className={'create-account-form'} onSubmit={onSubmit}>
|
|
45
|
+
<Form formData={formData.current} disabled={loading}>
|
|
46
|
+
<Item
|
|
47
|
+
dataField={'email'}
|
|
48
|
+
editorType={'dxTextBox'}
|
|
49
|
+
editorOptions={emailEditorOptions}
|
|
50
|
+
>
|
|
51
|
+
<RequiredRule message="Email is required" />
|
|
52
|
+
<EmailRule message="Email is invalid" />
|
|
53
|
+
<Label visible={false} />
|
|
54
|
+
</Item>
|
|
55
|
+
<Item
|
|
56
|
+
dataField={'password'}
|
|
57
|
+
editorType={'dxTextBox'}
|
|
58
|
+
editorOptions={passwordEditorOptions}
|
|
59
|
+
>
|
|
60
|
+
<RequiredRule message="Password is required" />
|
|
61
|
+
<Label visible={false} />
|
|
62
|
+
</Item>
|
|
63
|
+
<Item
|
|
64
|
+
dataField={'confirmedPassword'}
|
|
65
|
+
editorType={'dxTextBox'}
|
|
66
|
+
editorOptions={confirmedPasswordEditorOptions}
|
|
67
|
+
>
|
|
68
|
+
<RequiredRule message="Password is required" />
|
|
69
|
+
<CustomRule
|
|
70
|
+
message={'Passwords do not match'}
|
|
71
|
+
validationCallback={confirmPassword}
|
|
72
|
+
/>
|
|
73
|
+
<Label visible={false} />
|
|
74
|
+
</Item>
|
|
75
|
+
<Item>
|
|
76
|
+
<div className='policy-info'>
|
|
77
|
+
By creating an account, you agree to the <Link to="#">Terms of Service</Link> and <Link to="#">Privacy Policy</Link>
|
|
78
|
+
</div>
|
|
79
|
+
</Item>
|
|
80
|
+
<ButtonItem>
|
|
81
|
+
<ButtonOptions
|
|
82
|
+
width={'100%'}
|
|
83
|
+
type={'default'}
|
|
84
|
+
useSubmitBehavior={true}
|
|
85
|
+
>
|
|
86
|
+
<span className="dx-button-text">
|
|
87
|
+
{
|
|
88
|
+
loading
|
|
89
|
+
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
90
|
+
: 'Create a new account'
|
|
91
|
+
}
|
|
92
|
+
</span>
|
|
93
|
+
</ButtonOptions>
|
|
94
|
+
</ButtonItem>
|
|
95
|
+
<Item>
|
|
96
|
+
<div className={'login-link'}>
|
|
97
|
+
Have an account? <Link to={'/login'}>Sign In</Link>
|
|
98
|
+
</div>
|
|
99
|
+
</Item>
|
|
100
|
+
</Form>
|
|
101
|
+
</form>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
|
|
106
|
+
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
107
|
+
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
@import "../../themes/generated/variables.base.scss";
|
|
2
|
-
|
|
3
1
|
.footer {
|
|
4
2
|
display: block;
|
|
5
|
-
color:
|
|
6
|
-
border-top: 1px solid
|
|
3
|
+
color: var(--base-text-color-alpha-7);
|
|
4
|
+
border-top: 1px solid var(--footer-border-color);
|
|
7
5
|
padding-top: 20px;
|
|
8
6
|
padding-bottom: 24px;
|
|
7
|
+
margin: 0 40px;
|
|
8
|
+
|
|
9
|
+
.screen-x-small & {
|
|
10
|
+
margin: 0 20px;
|
|
11
|
+
}
|
|
9
12
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
@import "../../themes/generated/variables.base.scss";
|
|
2
1
|
@import "../../dx-styles.scss";
|
|
3
2
|
|
|
3
|
+
header {
|
|
4
|
+
background-color: var(--base-bg);
|
|
5
|
+
}
|
|
6
|
+
|
|
4
7
|
.header-component {
|
|
5
8
|
flex: 0 0 auto;
|
|
6
9
|
z-index: 1;
|
|
7
10
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
|
|
8
|
-
|
|
9
|
-
.dx-toolbar .dx-toolbar-item.menu-button>.dx-toolbar-item-content .dx-icon {
|
|
10
|
-
color: $base-accent;
|
|
11
|
-
}
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
.dx-toolbar.header-toolbar .dx-toolbar-items-container .dx-toolbar-after {
|