devextreme-cli 1.3.1 → 1.4.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/index.js +4 -2
- package/package.json +8 -3
- package/src/application.js +19 -19
- package/src/applications/application.angular.js +48 -46
- package/src/applications/application.react.js +76 -39
- package/src/applications/application.vue.js +71 -34
- package/src/commands.json +3 -0
- package/src/templates/react/application/src/{App.js → App.tsx} +0 -0
- package/src/templates/react/application/src/{Content.js → Content.tsx} +11 -9
- package/src/templates/react/application/src/UnauthenticatedContent.tsx +46 -0
- package/src/templates/react/application/src/api/{auth.js → auth.tsx} +4 -4
- package/src/templates/react/application/src/{app-info.js → app-info.tsx} +0 -0
- package/src/templates/react/application/src/{app-navigation.js → app-navigation.tsx} +0 -0
- package/src/templates/react/application/src/app-routes.tsx +24 -0
- package/src/templates/react/application/src/components/change-password-form/{change-password-form.js → ChangePasswordForm.tsx} +9 -8
- package/src/templates/react/application/src/components/create-account-form/{create-account-form.scss → CreateAccountForm.scss} +0 -0
- package/src/templates/react/application/src/components/create-account-form/{create-account-form.js → CreateAccountForm.tsx} +10 -9
- package/src/templates/react/application/src/components/footer/{footer.scss → Footer.scss} +0 -0
- package/src/templates/react/application/src/components/footer/{footer.js → Footer.tsx} +1 -1
- package/src/templates/react/application/src/components/header/{header.scss → Header.scss} +0 -0
- package/src/templates/react/application/src/components/header/{header.js → Header.tsx} +4 -3
- package/src/templates/react/application/src/components/index.tsx +7 -0
- package/src/templates/react/application/src/components/login-form/{login-form.scss → LoginForm.scss} +0 -0
- package/src/templates/react/application/src/components/login-form/{login-form.js → LoginForm.tsx} +7 -7
- package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.scss → ResetPasswordForm.scss} +0 -0
- package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.js → ResetPasswordForm.tsx} +8 -8
- package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.scss → SideNavigationMenu.scss} +0 -0
- package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.js → SideNavigationMenu.tsx} +10 -12
- package/src/templates/react/application/src/components/user-panel/{user-panel.scss → UserPanel.scss} +0 -0
- package/src/templates/react/application/src/components/user-panel/{user-panel.js → UserPanel.tsx} +8 -8
- package/src/templates/react/application/src/contexts/{auth.js → auth.tsx} +6 -5
- package/src/templates/react/application/src/contexts/navigation.tsx +35 -0
- package/src/templates/react/application/src/dx-styles.scss +25 -13
- package/src/templates/react/application/src/layouts/{index.js → index.tsx} +0 -0
- package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.scss +1 -16
- package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/{side-nav-inner-toolbar.js → side-nav-inner-toolbar.tsx} +20 -15
- package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.scss +0 -9
- package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/{side-nav-outer-toolbar.js → side-nav-outer-toolbar.tsx} +19 -16
- package/src/templates/react/application/src/layouts/single-card/{single-card.js → single-card.tsx} +2 -1
- package/src/templates/react/application/src/{polyfills.js → polyfills.tsx} +0 -0
- package/src/templates/react/application/src/types.tsx +57 -0
- package/src/templates/react/application/src/utils/{default-user.js → default-user.tsx} +0 -0
- package/src/templates/react/application/src/utils/{media-query.js → media-query.tsx} +4 -3
- package/src/templates/react/application/src/utils/{patches.js → patches.tsx} +1 -1
- package/src/templates/react/page/{page.js → page.tsx} +0 -0
- package/src/templates/react/sample-pages/home/{home.js → home.tsx} +0 -0
- package/src/templates/react/sample-pages/{index.js → index.tsx} +0 -0
- package/src/templates/react/sample-pages/profile/{profile.js → profile.tsx} +0 -0
- package/src/templates/react/sample-pages/tasks/{tasks.js → tasks.tsx} +1 -1
- package/src/templates/vue-v2/application/devextreme.json +2 -1
- package/src/templates/vue-v2/application/src/dx-styles.scss +12 -0
- package/src/templates/vue-v2/application/src/layouts/side-nav-inner-toolbar.vue +0 -15
- package/src/templates/vue-v2/application/src/layouts/side-nav-outer-toolbar.vue +0 -9
- package/src/templates/vue-v3/application/devextreme.json +2 -1
- package/src/templates/vue-v3/application/src/dx-styles.scss +12 -0
- package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +2 -17
- package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +0 -9
- package/src/themebuider.js +19 -4
- package/src/utility/latest-versions.js +3 -3
- package/src/utility/ng-version.js +35 -0
- package/src/utility/prompts/layout.js +9 -21
- package/src/utility/prompts/prompts.js +24 -8
- package/src/utility/prompts/typescript.js +18 -0
- package/src/utility/prompts/vue-version.js +9 -21
- package/src/utility/template-creator.js +11 -6
- package/src/utility/typescript-extension.js +24 -0
- package/src/templates/react/application/src/UnauthenticatedContent.js +0 -35
- package/src/templates/react/application/src/app-routes.js +0 -24
- package/src/templates/react/application/src/components/index.js +0 -7
- package/src/templates/react/application/src/contexts/navigation.js +0 -34
package/src/commands.json
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
}, {
|
|
19
19
|
"name": "--version",
|
|
20
20
|
"description": "Specifies whether to generate a Vue 2 or Vue 3 application. Available values: 2 (default) and 3"
|
|
21
|
+
}, {
|
|
22
|
+
"name": "--template",
|
|
23
|
+
"description": "Create template with typescsript support. Specifies for React & Vue application"
|
|
21
24
|
}]
|
|
22
25
|
}]
|
|
23
26
|
}, {
|
|
File without changes
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Switch, Route<%=^empty%>, Redirect<%=/empty%> } from 'react-router-dom';
|
|
1
|
+
import { Routes, Route, Navigate } from 'react-router-dom';
|
|
3
2
|
import appInfo from './app-info';
|
|
4
3
|
import routes from './app-routes';
|
|
5
4
|
import { <%=layout%> as SideNavBarLayout } from './layouts';
|
|
@@ -8,17 +7,19 @@ import { Footer } from './components';
|
|
|
8
7
|
export default function Content() {
|
|
9
8
|
return (
|
|
10
9
|
<SideNavBarLayout title={appInfo.title}>
|
|
11
|
-
<
|
|
12
|
-
{routes.map(({ path,
|
|
10
|
+
<Routes>
|
|
11
|
+
{routes.map(({ path, element }) => (
|
|
13
12
|
<Route
|
|
14
|
-
exact
|
|
15
13
|
key={path}
|
|
16
14
|
path={path}
|
|
17
|
-
|
|
15
|
+
element={element}
|
|
18
16
|
/>
|
|
19
|
-
))}
|
|
20
|
-
<
|
|
21
|
-
|
|
17
|
+
))}
|
|
18
|
+
<Route
|
|
19
|
+
path='*'
|
|
20
|
+
element={<Navigate to='/home' />}
|
|
21
|
+
/>
|
|
22
|
+
</Routes>
|
|
22
23
|
<Footer>
|
|
23
24
|
Copyright © 2011-{new Date().getFullYear()} {appInfo.title} Inc.
|
|
24
25
|
<br />
|
|
@@ -28,3 +29,4 @@ export default function Content() {
|
|
|
28
29
|
</SideNavBarLayout>
|
|
29
30
|
);
|
|
30
31
|
}
|
|
32
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Routes, Route, Navigate } from 'react-router-dom';
|
|
2
|
+
import { SingleCard } from './layouts';
|
|
3
|
+
import { LoginForm, ResetPasswordForm, ChangePasswordForm, CreateAccountForm } from './components';
|
|
4
|
+
|
|
5
|
+
export default function UnauthenticatedContent() {
|
|
6
|
+
return (
|
|
7
|
+
<Routes>
|
|
8
|
+
<Route
|
|
9
|
+
path='/login'
|
|
10
|
+
element={
|
|
11
|
+
<SingleCard title="Sign In">
|
|
12
|
+
<LoginForm />
|
|
13
|
+
</SingleCard>
|
|
14
|
+
}
|
|
15
|
+
/>
|
|
16
|
+
<Route
|
|
17
|
+
path='/create-account'
|
|
18
|
+
element={
|
|
19
|
+
<SingleCard title="Sign Up">
|
|
20
|
+
<CreateAccountForm />
|
|
21
|
+
</SingleCard>
|
|
22
|
+
}
|
|
23
|
+
/>
|
|
24
|
+
<Route
|
|
25
|
+
path='/reset-password'
|
|
26
|
+
element={
|
|
27
|
+
<SingleCard
|
|
28
|
+
title="Reset Password"
|
|
29
|
+
description="Please enter the email address that you used to register, and we will send you a link to reset your password via Email."
|
|
30
|
+
>
|
|
31
|
+
<ResetPasswordForm />
|
|
32
|
+
</SingleCard>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
35
|
+
<Route
|
|
36
|
+
path='/change-password/:recoveryCode'
|
|
37
|
+
element={
|
|
38
|
+
<SingleCard title="Change Password">
|
|
39
|
+
<ChangePasswordForm />
|
|
40
|
+
</SingleCard>
|
|
41
|
+
}
|
|
42
|
+
/>
|
|
43
|
+
<Route path='*' element={<Navigate to={'/login'} />}></Route>
|
|
44
|
+
</Routes>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import defaultUser from '../utils/default-user';
|
|
2
2
|
|
|
3
|
-
export async function signIn(email
|
|
3
|
+
export async function signIn(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
4
4
|
try {
|
|
5
5
|
// Send request
|
|
6
6
|
console.log(email, password);
|
|
@@ -34,7 +34,7 @@ export async function getUser() {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export async function createAccount(email
|
|
37
|
+
export async function createAccount(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
38
38
|
try {
|
|
39
39
|
// Send request
|
|
40
40
|
console.log(email, password);
|
|
@@ -51,7 +51,7 @@ export async function createAccount(email, password) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export async function changePassword(email
|
|
54
|
+
export async function changePassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>, recoveryCode<%=#isTypeScript%>?: string<%=/isTypeScript%>) {
|
|
55
55
|
try {
|
|
56
56
|
// Send request
|
|
57
57
|
console.log(email, recoveryCode);
|
|
@@ -68,7 +68,7 @@ export async function changePassword(email, recoveryCode) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export async function resetPassword(email) {
|
|
71
|
+
export async function resetPassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
72
72
|
try {
|
|
73
73
|
// Send request
|
|
74
74
|
console.log(email);
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HomePage, TasksPage, ProfilePage } from './pages';
|
|
2
|
+
import { withNavigationWatcher } from './contexts/navigation';
|
|
3
|
+
|
|
4
|
+
const routes = [<%=^empty%>
|
|
5
|
+
{
|
|
6
|
+
path: '/tasks',
|
|
7
|
+
element: TasksPage
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
path: '/profile',
|
|
11
|
+
element: ProfilePage
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: '/home',
|
|
15
|
+
element: HomePage
|
|
16
|
+
}
|
|
17
|
+
<%=/empty%>];
|
|
18
|
+
|
|
19
|
+
export default routes.map(route => {
|
|
20
|
+
return {
|
|
21
|
+
...route,
|
|
22
|
+
element: withNavigationWatcher(route.element, route.path)
|
|
23
|
+
};
|
|
24
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -10,15 +10,16 @@ import Form, {
|
|
|
10
10
|
} from 'devextreme-react/form';
|
|
11
11
|
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
|
+
<%=#isTypeScript%>import { ValidationType } from '../../types';<%=/isTypeScript%>
|
|
13
14
|
import { changePassword } from '../../api/auth';
|
|
14
15
|
|
|
15
|
-
export default function ChangePasswordForm(
|
|
16
|
-
const
|
|
16
|
+
export default function ChangePasswordForm() {
|
|
17
|
+
const navigate = useNavigate();
|
|
17
18
|
const [loading, setLoading] = useState(false);
|
|
18
|
-
const formData = useRef({});
|
|
19
|
+
const formData = useRef({ password: '' });
|
|
19
20
|
const { recoveryCode } = useParams();
|
|
20
21
|
|
|
21
|
-
const onSubmit = useCallback(async (e) => {
|
|
22
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
22
23
|
e.preventDefault();
|
|
23
24
|
const { password } = formData.current;
|
|
24
25
|
setLoading(true);
|
|
@@ -27,14 +28,14 @@ export default function ChangePasswordForm(props) {
|
|
|
27
28
|
setLoading(false);
|
|
28
29
|
|
|
29
30
|
if (result.isOk) {
|
|
30
|
-
|
|
31
|
+
navigate('/login');
|
|
31
32
|
} else {
|
|
32
33
|
notify(result.message, 'error', 2000);
|
|
33
34
|
}
|
|
34
|
-
}, [
|
|
35
|
+
}, [navigate, recoveryCode]);
|
|
35
36
|
|
|
36
37
|
const confirmPassword = useCallback(
|
|
37
|
-
({ value }) => value === formData.current.password,
|
|
38
|
+
({ value }<%=#isTypeScript%>: ValidationType<%=/isTypeScript%>) => value === formData.current.password,
|
|
38
39
|
[]
|
|
39
40
|
);
|
|
40
41
|
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -12,14 +12,15 @@ import Form, {
|
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
14
|
import { createAccount } from '../../api/auth';
|
|
15
|
-
import '
|
|
15
|
+
<%=#isTypeScript%>import { ValidationType } from '../../types';<%=/isTypeScript%>
|
|
16
|
+
import './CreateAccountForm.scss';
|
|
16
17
|
|
|
17
|
-
export default function CreateAccountForm(
|
|
18
|
-
const
|
|
18
|
+
export default function CreateAccountForm() {
|
|
19
|
+
const navigate = useNavigate();
|
|
19
20
|
const [loading, setLoading] = useState(false);
|
|
20
|
-
const formData = useRef({});
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
21
22
|
|
|
22
|
-
const onSubmit = useCallback(async (e) => {
|
|
23
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
23
24
|
e.preventDefault();
|
|
24
25
|
const { email, password } = formData.current;
|
|
25
26
|
setLoading(true);
|
|
@@ -28,14 +29,14 @@ export default function CreateAccountForm(props) {
|
|
|
28
29
|
setLoading(false);
|
|
29
30
|
|
|
30
31
|
if (result.isOk) {
|
|
31
|
-
|
|
32
|
+
navigate('/login');
|
|
32
33
|
} else {
|
|
33
34
|
notify(result.message, 'error', 2000);
|
|
34
35
|
}
|
|
35
|
-
}, [
|
|
36
|
+
}, [navigate]);
|
|
36
37
|
|
|
37
38
|
const confirmPassword = useCallback(
|
|
38
|
-
({ value }) => value === formData.current.password,
|
|
39
|
+
({ value }<%=#isTypeScript%>: ValidationType<%=/isTypeScript%>) => value === formData.current.password,
|
|
39
40
|
[]
|
|
40
41
|
);
|
|
41
42
|
|
|
File without changes
|
|
File without changes
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Toolbar, { Item } from 'devextreme-react/toolbar';
|
|
3
3
|
import Button from 'devextreme-react/button';
|
|
4
|
-
import UserPanel from '../user-panel/
|
|
5
|
-
import './
|
|
4
|
+
import UserPanel from '../user-panel/UserPanel';
|
|
5
|
+
import './Header.scss';
|
|
6
6
|
import { Template } from 'devextreme-react/core/template';
|
|
7
|
+
<%=#isTypeScript%>import type { HeaderProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
|
-
export default function Header({ menuToggleEnabled, title, toggleMenu }) {
|
|
9
|
+
export default function Header({ menuToggleEnabled, title, toggleMenu }<%=#isTypeScript%>: HeaderProps<%=/isTypeScript%>) {
|
|
9
10
|
return (
|
|
10
11
|
<header className={'header-component'}>
|
|
11
12
|
<Toolbar className={'header-toolbar'}>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Header } from './header/Header';
|
|
2
|
+
export { default as Footer } from './footer/Footer';
|
|
3
|
+
export { default as LoginForm } from './login-form/LoginForm';
|
|
4
|
+
export { default as ResetPasswordForm } from './reset-password-form/ResetPasswordForm';
|
|
5
|
+
export { default as CreateAccountForm } from './create-account-form/CreateAccountForm';
|
|
6
|
+
export { default as ChangePasswordForm } from './change-password-form/ChangePasswordForm';
|
|
7
|
+
export { default as SideNavigationMenu } from './side-navigation-menu/SideNavigationMenu';
|
package/src/templates/react/application/src/components/login-form/{login-form.scss → LoginForm.scss}
RENAMED
|
File without changes
|
package/src/templates/react/application/src/components/login-form/{login-form.js → LoginForm.tsx}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -12,15 +12,15 @@ import LoadIndicator from 'devextreme-react/load-indicator';
|
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import { useAuth } from '../../contexts/auth';
|
|
14
14
|
|
|
15
|
-
import './
|
|
15
|
+
import './LoginForm.scss';
|
|
16
16
|
|
|
17
17
|
export default function LoginForm() {
|
|
18
|
-
const
|
|
18
|
+
const navigate = useNavigate();
|
|
19
19
|
const { signIn } = useAuth();
|
|
20
20
|
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({});
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
22
|
|
|
23
|
-
const onSubmit = useCallback(async (e) => {
|
|
23
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
24
|
e.preventDefault();
|
|
25
25
|
const { email, password } = formData.current;
|
|
26
26
|
setLoading(true);
|
|
@@ -33,8 +33,8 @@ export default function LoginForm() {
|
|
|
33
33
|
}, [signIn]);
|
|
34
34
|
|
|
35
35
|
const onCreateAccountClick = useCallback(() => {
|
|
36
|
-
|
|
37
|
-
}, [
|
|
36
|
+
navigate('/create-account');
|
|
37
|
+
}, [navigate]);
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<form className={'login-form'} onSubmit={onSubmit}>
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from "react-router-dom";
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -11,16 +11,16 @@ import Form, {
|
|
|
11
11
|
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import { resetPassword } from '../../api/auth';
|
|
14
|
-
import './
|
|
14
|
+
import './ResetPasswordForm.scss';
|
|
15
15
|
|
|
16
16
|
const notificationText = 'We\'ve sent a link to reset your password. Check your inbox.';
|
|
17
17
|
|
|
18
|
-
export default function ResetPasswordForm(
|
|
19
|
-
const
|
|
18
|
+
export default function ResetPasswordForm() {
|
|
19
|
+
const navigate = useNavigate();
|
|
20
20
|
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({});
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
22
|
|
|
23
|
-
const onSubmit = useCallback(async (e) => {
|
|
23
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
24
|
e.preventDefault();
|
|
25
25
|
const { email } = formData.current;
|
|
26
26
|
setLoading(true);
|
|
@@ -29,12 +29,12 @@ export default function ResetPasswordForm(props) {
|
|
|
29
29
|
setLoading(false);
|
|
30
30
|
|
|
31
31
|
if (result.isOk) {
|
|
32
|
-
|
|
32
|
+
navigate('/login');
|
|
33
33
|
notify(notificationText, 'success', 2500);
|
|
34
34
|
} else {
|
|
35
35
|
notify(result.message, 'error', 2000);
|
|
36
36
|
}
|
|
37
|
-
}, [
|
|
37
|
+
}, [navigate]);
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<form className={'reset-password-form'} onSubmit={onSubmit}>
|
|
File without changes
|
|
@@ -3,11 +3,12 @@ import TreeView from 'devextreme-react/tree-view';
|
|
|
3
3
|
import { navigation } from '../../app-navigation';
|
|
4
4
|
import { useNavigation } from '../../contexts/navigation';
|
|
5
5
|
import { useScreenSize } from '../../utils/media-query';
|
|
6
|
-
import './
|
|
6
|
+
import './SideNavigationMenu.scss';
|
|
7
|
+
<%=#isTypeScript%>import type { SideNavigationMenuProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
9
|
import * as events from 'devextreme/events';
|
|
9
10
|
|
|
10
|
-
export default function SideNavigationMenu(props) {
|
|
11
|
+
export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsWithChildren<SideNavigationMenuProps><%=/isTypeScript%>) {
|
|
11
12
|
const {
|
|
12
13
|
children,
|
|
13
14
|
selectedItemChanged,
|
|
@@ -18,12 +19,9 @@ export default function SideNavigationMenu(props) {
|
|
|
18
19
|
|
|
19
20
|
const { isLarge } = useScreenSize();
|
|
20
21
|
function normalizePath () {
|
|
21
|
-
return navigation.map((item) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
return {...item, expanded: isLarge};
|
|
26
|
-
});
|
|
22
|
+
return navigation.map((item) => (
|
|
23
|
+
{ ...item, expanded: isLarge, path: item.path && !(/^\//.test(item.path)) ? `/${item.path}` : item.path }
|
|
24
|
+
))
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
const items = useMemo(
|
|
@@ -34,16 +32,16 @@ export default function SideNavigationMenu(props) {
|
|
|
34
32
|
|
|
35
33
|
const { navigationData: { currentPath } } = useNavigation();
|
|
36
34
|
|
|
37
|
-
const treeViewRef = useRef();
|
|
38
|
-
const wrapperRef = useRef();
|
|
39
|
-
const getWrapperRef = useCallback((element) => {
|
|
35
|
+
const treeViewRef = useRef<%=#isTypeScript%><TreeView><%=/isTypeScript%>(null);
|
|
36
|
+
const wrapperRef = useRef<%=#isTypeScript%><HTMLDivElement><%=/isTypeScript%>();
|
|
37
|
+
const getWrapperRef = useCallback((element<%=#isTypeScript%>: HTMLDivElement<%=/isTypeScript%>) => {
|
|
40
38
|
const prevElement = wrapperRef.current;
|
|
41
39
|
if (prevElement) {
|
|
42
40
|
events.off(prevElement, 'dxclick');
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
wrapperRef.current = element;
|
|
46
|
-
events.on(element, 'dxclick', e => {
|
|
44
|
+
events.on(element, 'dxclick', (e<%=#isTypeScript%>: React.PointerEvent<%=/isTypeScript%>) => {
|
|
47
45
|
openMenu(e);
|
|
48
46
|
});
|
|
49
47
|
}, [openMenu]);
|
package/src/templates/react/application/src/components/user-panel/{user-panel.scss → UserPanel.scss}
RENAMED
|
File without changes
|
package/src/templates/react/application/src/components/user-panel/{user-panel.js → UserPanel.tsx}
RENAMED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigate } from "react-router-dom";
|
|
3
3
|
import ContextMenu, { Position } from 'devextreme-react/context-menu';
|
|
4
4
|
import List from 'devextreme-react/list';
|
|
5
5
|
import { useAuth } from '../../contexts/auth';
|
|
6
|
-
import './
|
|
6
|
+
import './UserPanel.scss';
|
|
7
|
+
<%=#isTypeScript%>import type { UserPanelProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
|
-
export default function UserPanel({ menuMode }) {
|
|
9
|
+
export default function UserPanel({ menuMode }<%=#isTypeScript%>: UserPanelProps<%=/isTypeScript%>) {
|
|
9
10
|
const { user, signOut } = useAuth();
|
|
10
|
-
const
|
|
11
|
+
const navigate = useNavigate();
|
|
11
12
|
|
|
12
13
|
function navigateToProfile() {
|
|
13
|
-
|
|
14
|
+
navigate("/profile");
|
|
14
15
|
}
|
|
15
16
|
const menuItems = useMemo(() => ([
|
|
16
17
|
{
|
|
@@ -24,19 +25,18 @@ export default function UserPanel({ menuMode }) {
|
|
|
24
25
|
onClick: signOut
|
|
25
26
|
}
|
|
26
27
|
]), [signOut]);
|
|
27
|
-
|
|
28
28
|
return (
|
|
29
29
|
<div className={'user-panel'}>
|
|
30
30
|
<div className={'user-info'}>
|
|
31
31
|
<div className={'image-container'}>
|
|
32
32
|
<div
|
|
33
33
|
style={{
|
|
34
|
-
background: `url(${user
|
|
34
|
+
background: `url(${user<%=#isTypeScript%>!<%=/isTypeScript%>.avatarUrl}) no-repeat #fff`,
|
|
35
35
|
backgroundSize: 'cover'
|
|
36
36
|
}}
|
|
37
37
|
className={'user-image'} />
|
|
38
38
|
</div>
|
|
39
|
-
<div className={'user-name'}>{user
|
|
39
|
+
<div className={'user-name'}>{user<%=#isTypeScript%>!<%=/isTypeScript%>.email}</div>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
42
|
{menuMode === 'context' && (
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect, createContext, useContext, useCallback } from 'react';
|
|
2
2
|
import { getUser, signIn as sendSignInRequest } from '../api/auth';
|
|
3
|
+
<%=#isTypeScript%>import type { User, AuthContextType } from '../types';<%=/isTypeScript%>
|
|
3
4
|
|
|
4
|
-
function AuthProvider(props) {
|
|
5
|
-
const [user, setUser] = useState();
|
|
5
|
+
function AuthProvider(props<%=#isTypeScript%>: React.PropsWithChildren<unknown><%=/isTypeScript%>) {
|
|
6
|
+
const [user, setUser] = useState<%=#isTypeScript%><User><%=/isTypeScript%>();
|
|
6
7
|
const [loading, setLoading] = useState(true);
|
|
7
8
|
|
|
8
9
|
useEffect(() => {
|
|
@@ -16,7 +17,7 @@ function AuthProvider(props) {
|
|
|
16
17
|
})();
|
|
17
18
|
}, []);
|
|
18
19
|
|
|
19
|
-
const signIn = useCallback(async (email
|
|
20
|
+
const signIn = useCallback(async (email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) => {
|
|
20
21
|
const result = await sendSignInRequest(email, password);
|
|
21
22
|
if (result.isOk) {
|
|
22
23
|
setUser(result.data);
|
|
@@ -26,7 +27,7 @@ function AuthProvider(props) {
|
|
|
26
27
|
}, []);
|
|
27
28
|
|
|
28
29
|
const signOut = useCallback(() => {
|
|
29
|
-
setUser();
|
|
30
|
+
setUser(undefined);
|
|
30
31
|
}, []);
|
|
31
32
|
|
|
32
33
|
|
|
@@ -35,7 +36,7 @@ function AuthProvider(props) {
|
|
|
35
36
|
);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
const AuthContext = createContext({});
|
|
39
|
+
const AuthContext = createContext<%=#isTypeScript%><AuthContextType><%=/isTypeScript%>({ loading: false }<%=#isTypeScript%> as AuthContextType<%=/isTypeScript%>);
|
|
39
40
|
const useAuth = () => useContext(AuthContext);
|
|
40
41
|
|
|
41
42
|
export { AuthProvider, useAuth }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { useState, createContext, useContext, useEffect } from 'react';
|
|
2
|
+
<%=#isTypeScript%>import type { NavigationContextType } from '../types';<%=/isTypeScript%>
|
|
3
|
+
|
|
4
|
+
const NavigationContext = createContext<%=#isTypeScript%><NavigationContextType><%=/isTypeScript%>({}<%=#isTypeScript%> as NavigationContextType<%=/isTypeScript%>);
|
|
5
|
+
const useNavigation = () => useContext(NavigationContext);
|
|
6
|
+
|
|
7
|
+
function NavigationProvider(props<%=#isTypeScript%>: React.PropsWithChildren<unknown><%=/isTypeScript%>) {
|
|
8
|
+
const [navigationData, setNavigationData] = useState({ currentPath: '' });
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<NavigationContext.Provider
|
|
12
|
+
value={{ navigationData, setNavigationData }}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function withNavigationWatcher(Component<%=#isTypeScript%>: React.ElementType<%=/isTypeScript%>, path<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
19
|
+
const WrappedComponent = function (props<%=#isTypeScript%>: Record<string, unknown><%=/isTypeScript%>) {
|
|
20
|
+
const { setNavigationData } = useNavigation();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setNavigationData<%=#isTypeScript%>!<%=/isTypeScript%>({ currentPath: path });
|
|
24
|
+
}, [path, setNavigationData]);
|
|
25
|
+
|
|
26
|
+
return <Component {...props} />;
|
|
27
|
+
}
|
|
28
|
+
return <WrappedComponent />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
NavigationProvider,
|
|
33
|
+
useNavigation,
|
|
34
|
+
withNavigationWatcher
|
|
35
|
+
}
|
|
@@ -5,26 +5,38 @@
|
|
|
5
5
|
display: flex;
|
|
6
6
|
height: 100%;
|
|
7
7
|
width: 100%;
|
|
8
|
-
}
|
|
9
8
|
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
.content {
|
|
10
|
+
line-height: 1.5;
|
|
11
|
+
flex-grow: 1;
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
h2 {
|
|
14
|
+
font-size: 30px;
|
|
15
|
+
margin-top: 20px;
|
|
16
|
+
margin-bottom: 20px;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
.container {
|
|
21
|
+
height: 100%;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
display: flex;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.layout-body {
|
|
27
|
+
flex: 1;
|
|
28
|
+
min-height: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.content-block {
|
|
32
|
+
margin-left: 40px;
|
|
33
|
+
margin-right: 40px;
|
|
19
34
|
margin-top: 20px;
|
|
20
|
-
margin-bottom: 20px;
|
|
21
35
|
}
|
|
22
36
|
}
|
|
23
37
|
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
margin-right: 40px;
|
|
27
|
-
margin-top: 20px;
|
|
38
|
+
.side-nav-outer-toolbar .dx-drawer {
|
|
39
|
+
height: calc(100% - 56px)
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
.screen-x-small .content-block {
|
|
File without changes
|
|
@@ -2,21 +2,6 @@
|
|
|
2
2
|
width: 100%;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
.container {
|
|
6
|
-
height: 100%;
|
|
7
|
-
flex-direction: column;
|
|
8
|
-
display: flex;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.layout-body {
|
|
12
|
-
flex: 1;
|
|
13
|
-
min-height: 0;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.content {
|
|
17
|
-
flex-grow: 1;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
5
|
#navigation-header {
|
|
21
6
|
@import "../../themes/generated/variables.additional.scss";
|
|
22
7
|
background-color: $base-accent;
|
|
@@ -29,7 +14,7 @@
|
|
|
29
14
|
.screen-x-small & {
|
|
30
15
|
padding-left: 20px;
|
|
31
16
|
}
|
|
32
|
-
|
|
17
|
+
|
|
33
18
|
.dx-theme-generic & {
|
|
34
19
|
padding-top: 10px;
|
|
35
20
|
padding-bottom: 10px;
|