@antscorp/antsomi-ui 1.3.5-beta.544 → 1.3.5-beta.545
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/es/components/molecules/AccessDenied/AccessDenied.d.ts +11 -0
- package/es/components/molecules/AccessDenied/AccessDenied.js +25 -0
- package/es/components/molecules/AccessDenied/index.d.ts +1 -0
- package/es/components/molecules/AccessDenied/index.js +1 -0
- package/es/components/molecules/AccessDenied/styled.d.ts +2 -0
- package/es/components/molecules/AccessDenied/styled.js +35 -0
- package/es/components/molecules/SelectAccount/AccountItem.d.ts +11 -0
- package/es/components/molecules/SelectAccount/AccountItem.js +10 -0
- package/es/components/molecules/SelectAccount/AccountList.d.ts +2 -2
- package/es/components/molecules/SelectAccount/AccountList.js +62 -25
- package/es/components/molecules/SelectAccount/context/reducer.js +15 -0
- package/es/components/molecules/SelectAccount/index.js +1 -0
- package/es/components/molecules/SelectAccount/styled.js +6 -33
- package/es/components/molecules/SelectAccount/type.d.ts +6 -0
- package/es/components/molecules/index.d.ts +1 -0
- package/es/components/molecules/index.js +1 -0
- package/es/components/organism/AccountSharing/AccountSharing.js +3 -2
- package/es/components/template/Layout/Layout.js +24 -6
- package/es/constants/theme.js +3 -0
- package/es/constants/variables.d.ts +1 -0
- package/es/constants/variables.js +1 -0
- package/es/locales/en/translation.json +7 -0
- package/es/locales/i18n.d.ts +14 -0
- package/es/locales/translations.d.ts +7 -0
- package/es/locales/vi/translation.json +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
interface AccessDeniedProps {
|
|
3
|
+
image?: ReactNode;
|
|
4
|
+
title?: ReactNode;
|
|
5
|
+
subTitle?: ReactNode;
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
onClickRequestAccess?: () => void;
|
|
8
|
+
onClickSwitchAccount?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const AccessDenied: React.FC<AccessDeniedProps>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Libraries
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// Components
|
|
4
|
+
import { Button, Flex, Typography } from '@antscorp/antsomi-ui/es/components/atoms';
|
|
5
|
+
// Styled
|
|
6
|
+
import { AccessDeniedWrapper } from './styled';
|
|
7
|
+
// Translations
|
|
8
|
+
import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
|
|
9
|
+
// Assets
|
|
10
|
+
import i18nInstance from '@antscorp/antsomi-ui/es/locales/i18n';
|
|
11
|
+
const { Text } = Typography;
|
|
12
|
+
const { t } = i18nInstance;
|
|
13
|
+
const AccessDeniedLockImage = 'https://st-media-template.antsomi.com/icons/antsomi/access_denied.png';
|
|
14
|
+
export const AccessDenied = props => {
|
|
15
|
+
const { image = AccessDeniedLockImage, title = t(translations.accessDenied.title).toString(), subTitle = t(translations.accessDenied.subTitle).toString(), description = t(translations.accessDenied.description).toString(), onClickRequestAccess, onClickSwitchAccount, } = props;
|
|
16
|
+
return (React.createElement(AccessDeniedWrapper, { vertical: true, align: "center", justify: "center" },
|
|
17
|
+
typeof image === 'string' ? (React.createElement("img", { src: image, alt: "Access Denied", className: "access-denied__lock", width: 100, height: "auto" })) : (image),
|
|
18
|
+
React.createElement(Flex, { vertical: true, gap: 5, align: "center" },
|
|
19
|
+
React.createElement(Text, { className: "access-denied__title", strong: true }, title),
|
|
20
|
+
React.createElement(Text, { className: "access-denied__subtitle" }, subTitle),
|
|
21
|
+
React.createElement(Text, { className: "access-denied__description" }, description)),
|
|
22
|
+
React.createElement(Flex, { className: "access-denied__actions", gap: 10 },
|
|
23
|
+
React.createElement(Button, { type: "primary", onClick: onClickRequestAccess }, t(translations.accessDenied.requestAccess).toString()),
|
|
24
|
+
React.createElement(Button, { type: "default", onClick: onClickSwitchAccount }, t(translations.accessDenied.switchAccount).toString()))));
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AccessDenied } from './AccessDenied';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AccessDenied } from './AccessDenied';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const AccessDeniedWrapper: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("antd/es/flex/interface").FlexProps<import("antd/es/_util/type").AnyObject> & import("react").RefAttributes<HTMLElement>>, any, {}, never>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Libraries
|
|
2
|
+
import { Flex } from '@antscorp/antsomi-ui/es/components/atoms';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
// Constants
|
|
5
|
+
import { globalToken } from '@antscorp/antsomi-ui/es/constants';
|
|
6
|
+
const { bw8, orange6 } = globalToken || {};
|
|
7
|
+
export const AccessDeniedWrapper = styled(Flex) `
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: 100%;
|
|
10
|
+
|
|
11
|
+
.access-denied {
|
|
12
|
+
&__lock {
|
|
13
|
+
width: 100px;
|
|
14
|
+
margin-bottom: 15px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&__title {
|
|
18
|
+
color: ${orange6};
|
|
19
|
+
font-size: 20px;
|
|
20
|
+
line-height: 23.44px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__subtitle {
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&__description {
|
|
28
|
+
color: ${bw8};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&__actions {
|
|
32
|
+
margin-top: 20px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CheckboxChangeEvent } from 'antd/es/checkbox';
|
|
3
|
+
type AccountItemProps = {
|
|
4
|
+
checked: boolean;
|
|
5
|
+
label: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
name?: string;
|
|
8
|
+
onChange?: (e: CheckboxChangeEvent) => void;
|
|
9
|
+
};
|
|
10
|
+
declare const _default: React.NamedExoticComponent<AccountItemProps>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { CheckboxStyled } from './styled';
|
|
3
|
+
import { Typography } from '../../atoms';
|
|
4
|
+
const AccountItem = props => {
|
|
5
|
+
const { checked, label, disabled, name, onChange } = props;
|
|
6
|
+
const TextLabel = ({ children }) => (React.createElement(Typography.Text, { ellipsis: { tooltip: { title: children } }, style: { maxWidth: '220px' } }, children));
|
|
7
|
+
return (React.createElement(CheckboxStyled, { name: name, disabled: disabled, checked: checked, onChange: onChange },
|
|
8
|
+
React.createElement(TextLabel, null, label)));
|
|
9
|
+
};
|
|
10
|
+
export default memo(AccountItem);
|
|
@@ -1,56 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
// Libraries
|
|
2
|
+
import React, { memo, useContext, useEffect, useState } from 'react';
|
|
3
|
+
import { slice } from 'lodash';
|
|
4
|
+
// Context
|
|
5
5
|
import { SelectAccountContext } from './context/SelectAccountContext';
|
|
6
|
+
// Components
|
|
7
|
+
import { AccountListBody, AccountListContent, AccountListFooter, AccountListTitleGroup, AccountListWrapper, } from './styled';
|
|
8
|
+
import { Button, Icon, Input, Scrollbars } from '../../atoms';
|
|
9
|
+
import { Dropdown } from '../Dropdown';
|
|
10
|
+
import AccountItem from './AccountItem';
|
|
6
11
|
const AccountList = () => {
|
|
12
|
+
var _a;
|
|
7
13
|
const { formListRef, state, dispatch } = useContext(SelectAccountContext);
|
|
8
|
-
const { usersSelected, usersDisplay, disabledAccount, nameKey, userIdKey, searchText, listAccountGroupDisplay, } = state;
|
|
14
|
+
const { usersSelected, usersDisplay, disabledAccount, nameKey, userIdKey, searchText, listAccountGroupDisplay, limit = 10, } = state;
|
|
15
|
+
const POSITION_TOP = 0.9;
|
|
16
|
+
// States
|
|
9
17
|
const [openGroup, setOpenGroup] = useState(true);
|
|
10
18
|
const [openAccount, setOpenAccount] = useState(true);
|
|
19
|
+
const [page, setPage] = useState(1);
|
|
20
|
+
const [pageGroup, setPageGroup] = useState(1);
|
|
21
|
+
const [tempSelected, setTempSelected] = useState([]);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setTempSelected([...usersSelected]);
|
|
24
|
+
}, [usersSelected]);
|
|
11
25
|
const handleCancel = () => {
|
|
12
26
|
dispatch({ type: 'CLOSE_ACCOUNT_LIST' });
|
|
13
27
|
};
|
|
14
28
|
const handleApply = () => {
|
|
15
|
-
dispatch({ type: '
|
|
29
|
+
dispatch({ type: 'APPLY_SELECTED', payload: tempSelected });
|
|
16
30
|
};
|
|
17
31
|
const handleSearch = text => {
|
|
18
32
|
dispatch({ type: 'UPDATE_SEARCH_TEXT', payload: text });
|
|
19
33
|
};
|
|
20
|
-
const
|
|
34
|
+
const handleTempSelected = (isChecked, key) => {
|
|
35
|
+
if (isChecked) {
|
|
36
|
+
setTempSelected([...tempSelected, key]);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
setTempSelected(tempSelected.filter(id => id !== key));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
21
42
|
return (React.createElement(AccountListWrapper, null,
|
|
22
43
|
React.createElement(AccountListBody, null,
|
|
23
44
|
React.createElement("form", { ref: formListRef, id: "form-account-list" },
|
|
24
45
|
React.createElement(Input, { value: searchText, placeholder: "Search", suffix: React.createElement(Icon, { type: "icon-ants-search-2" }), onAfterChange: value => handleSearch(value), debounce: 500 }),
|
|
25
46
|
(state === null || state === void 0 ? void 0 : state.type) === 'group' ? (React.createElement(React.Fragment, null,
|
|
26
|
-
React.createElement(Dropdown, { open: openGroup, getPopupContainer: () => document.getElementById('account-group-list') || document.body, overlayStyle: { position: 'initial' }, trigger: ['click'], dropdownRender: () =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
React.createElement(Dropdown, { open: openGroup, getPopupContainer: () => document.getElementById('account-group-list') || document.body, overlayStyle: { position: 'initial' }, trigger: ['click'], dropdownRender: () => {
|
|
48
|
+
var _a;
|
|
49
|
+
return (
|
|
50
|
+
// <AccountListContent>
|
|
51
|
+
React.createElement(Scrollbars, { width: "100%", autoHeight: true, autoHeightMax: 160, onScrollFrame: values => {
|
|
52
|
+
if (values.top > POSITION_TOP &&
|
|
53
|
+
limit * pageGroup < (listAccountGroupDisplay === null || listAccountGroupDisplay === void 0 ? void 0 : listAccountGroupDisplay.length)) {
|
|
54
|
+
setPageGroup(pageGroup + 1);
|
|
55
|
+
}
|
|
56
|
+
} },
|
|
57
|
+
React.createElement(AccountListContent, null, (_a = slice(listAccountGroupDisplay, 0, limit * pageGroup)) === null || _a === void 0 ? void 0 : _a.map(item => (React.createElement(AccountItem, { key: item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupIdKey], name: item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupIdKey], checked: tempSelected.includes(item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupIdKey]), label: item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupNameKey], disabled: disabledAccount === null || disabledAccount === void 0 ? void 0 : disabledAccount.includes(item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupIdKey]), onChange: e => handleTempSelected(e.target.checked, item === null || item === void 0 ? void 0 : item[state === null || state === void 0 ? void 0 : state.groupIdKey]) })))))
|
|
58
|
+
// </AccountListContent>
|
|
59
|
+
);
|
|
60
|
+
} },
|
|
35
61
|
React.createElement(AccountListTitleGroup, { onClick: () => setOpenGroup(!openGroup) },
|
|
36
|
-
React.createElement("div", null,
|
|
37
|
-
React.createElement(Icon, { type: "icon-ants-expand-more", size: 20, style: {
|
|
62
|
+
React.createElement("div", null, state.groupText || 'Account group'),
|
|
63
|
+
React.createElement(Icon, { type: "icon-ants-expand-more", size: 20, color: "#595959", style: {
|
|
38
64
|
transform: openGroup ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
39
65
|
transition: '0.3s',
|
|
40
66
|
} }))),
|
|
41
67
|
React.createElement("div", { id: "account-group-list" }),
|
|
42
|
-
React.createElement(Dropdown, { open: openAccount, getPopupContainer: () => document.getElementById('account-list') || document.body, overlayStyle: { position: 'initial' }, trigger: ['click'], dropdownRender: () =>
|
|
43
|
-
|
|
68
|
+
React.createElement(Dropdown, { open: openAccount, getPopupContainer: () => document.getElementById('account-list') || document.body, overlayStyle: { position: 'initial' }, trigger: ['click'], dropdownRender: () => {
|
|
69
|
+
var _a;
|
|
70
|
+
return (React.createElement(Scrollbars, { autoHeight: true, autoHeightMax: 160, width: "100%", onScrollFrame: values => {
|
|
71
|
+
if (values.top > POSITION_TOP && limit * page < (usersDisplay === null || usersDisplay === void 0 ? void 0 : usersDisplay.length)) {
|
|
72
|
+
setPage(page + 1);
|
|
73
|
+
}
|
|
74
|
+
} },
|
|
75
|
+
React.createElement(AccountListContent, null, (_a = slice(usersDisplay, 0, limit * page)) === null || _a === void 0 ? void 0 : _a.map(item => (React.createElement(AccountItem, { key: item === null || item === void 0 ? void 0 : item[userIdKey], name: item === null || item === void 0 ? void 0 : item[userIdKey], checked: tempSelected.includes(item === null || item === void 0 ? void 0 : item[userIdKey]), label: item === null || item === void 0 ? void 0 : item[nameKey], disabled: disabledAccount === null || disabledAccount === void 0 ? void 0 : disabledAccount.includes(item === null || item === void 0 ? void 0 : item[userIdKey]), onChange: e => handleTempSelected(e.target.checked, item === null || item === void 0 ? void 0 : item[userIdKey]) }))))));
|
|
76
|
+
} },
|
|
44
77
|
React.createElement(AccountListTitleGroup, { onClick: () => setOpenAccount(!openAccount) },
|
|
45
|
-
React.createElement("div", null,
|
|
46
|
-
React.createElement(Icon, { type: "icon-ants-expand-more", size: 20, style: {
|
|
78
|
+
React.createElement("div", null, state.accountText || 'Account'),
|
|
79
|
+
React.createElement(Icon, { type: "icon-ants-expand-more", size: 20, color: "#595959", style: {
|
|
47
80
|
transform: openAccount ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
48
81
|
transition: '0.3s',
|
|
49
82
|
} }))),
|
|
50
|
-
React.createElement("div", { id: "account-list" }))) : (React.createElement(
|
|
51
|
-
|
|
83
|
+
React.createElement("div", { id: "account-list" }))) : (React.createElement(Scrollbars, { autoHeight: true, autoHeightMax: 160, width: "100%", style: { marginTop: 15 }, onScrollFrame: values => {
|
|
84
|
+
if (values.top > POSITION_TOP && limit * page < (usersDisplay === null || usersDisplay === void 0 ? void 0 : usersDisplay.length)) {
|
|
85
|
+
setPage(page + 1);
|
|
86
|
+
}
|
|
87
|
+
} },
|
|
88
|
+
React.createElement(AccountListContent, null, (_a = slice(usersDisplay, 0, limit * page)) === null || _a === void 0 ? void 0 : _a.map(item => (React.createElement(AccountItem, { key: item === null || item === void 0 ? void 0 : item[userIdKey], checked: tempSelected.includes(item === null || item === void 0 ? void 0 : item[userIdKey]), label: item === null || item === void 0 ? void 0 : item[nameKey], disabled: disabledAccount === null || disabledAccount === void 0 ? void 0 : disabledAccount.includes(item === null || item === void 0 ? void 0 : item[userIdKey]), onChange: e => handleTempSelected(e.target.checked, item === null || item === void 0 ? void 0 : item[userIdKey]) })))))))),
|
|
52
89
|
React.createElement(AccountListFooter, null,
|
|
53
90
|
React.createElement(Button, { onClick: () => handleCancel() }, state.cancelText || 'Cancel'),
|
|
54
91
|
React.createElement(Button, { type: "primary", onClick: () => handleApply() }, state.applyText || 'Apply'))));
|
|
55
92
|
};
|
|
56
|
-
export default AccountList;
|
|
93
|
+
export default memo(AccountList);
|
|
@@ -90,6 +90,21 @@ export const reducer = (state, action) => produce(state, draft => {
|
|
|
90
90
|
}
|
|
91
91
|
break;
|
|
92
92
|
}
|
|
93
|
+
case 'APPLY_SELECTED':
|
|
94
|
+
draft.usersSelected = action.payload;
|
|
95
|
+
draft.openAccountList = false;
|
|
96
|
+
// handle change
|
|
97
|
+
if (typeof draft.onChange === 'function') {
|
|
98
|
+
const optionUsersSelected = [...state.users].filter(user => draft.usersSelected.includes(user[state.userIdKey]));
|
|
99
|
+
const optionGroupSelected = state.type === 'group'
|
|
100
|
+
? [...state.listAccountGroup].filter(group => draft.usersSelected.includes(group[state.groupIdKey]))
|
|
101
|
+
: [];
|
|
102
|
+
draft.onChange(draft.usersSelected, [
|
|
103
|
+
...(optionUsersSelected || []),
|
|
104
|
+
...(optionGroupSelected || []),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
93
108
|
case 'UPDATE_USERS':
|
|
94
109
|
if (Array.isArray(action.payload)) {
|
|
95
110
|
draft.users = action.payload;
|
|
@@ -108,10 +108,12 @@ export const AccountListTitleGroup = styled.div `
|
|
|
108
108
|
justify-content: space-between;
|
|
109
109
|
align-items: center;
|
|
110
110
|
margin-top: 10px;
|
|
111
|
+
margin-bottom: 10px;
|
|
111
112
|
|
|
112
|
-
font-size:
|
|
113
|
-
line-height:
|
|
114
|
-
font-weight:
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
line-height: 14px;
|
|
115
|
+
font-weight: 400;
|
|
116
|
+
height: 30px;
|
|
115
117
|
cursor: pointer;
|
|
116
118
|
`;
|
|
117
119
|
export const AccountListContent = styled.div `
|
|
@@ -119,41 +121,12 @@ export const AccountListContent = styled.div `
|
|
|
119
121
|
flex-direction: column;
|
|
120
122
|
gap: 5px;
|
|
121
123
|
|
|
122
|
-
max-height: 160px;
|
|
123
|
-
overflow: auto;
|
|
124
|
-
|
|
125
124
|
& label:hover {
|
|
126
125
|
background-color: #f2f9ff;
|
|
127
126
|
}
|
|
128
|
-
|
|
129
|
-
&:hover::-webkit-scrollbar-thumb {
|
|
130
|
-
display: initial !important;
|
|
131
|
-
-ms-overflow-style: initial; /* IE and Edge */
|
|
132
|
-
scrollbar-width: initial; /* Firefox */
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
::-webkit-scrollbar {
|
|
136
|
-
border-radius: 15px !important;
|
|
137
|
-
width: 4px !important;
|
|
138
|
-
height: 4px !important;
|
|
139
|
-
background-color: transparent !important;
|
|
140
|
-
}
|
|
141
|
-
::-webkit-scrollbar-track {
|
|
142
|
-
border-radius: 15px !important;
|
|
143
|
-
background-color: transparent !important;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
::-webkit-scrollbar-thumb {
|
|
147
|
-
display: none !important;
|
|
148
|
-
-ms-overflow-style: none; /* IE and Edge */
|
|
149
|
-
scrollbar-width: none; /* Firefox */
|
|
150
|
-
|
|
151
|
-
border-radius: 15px !important;
|
|
152
|
-
background-color: #babac0 !important;
|
|
153
|
-
}
|
|
154
127
|
`;
|
|
155
128
|
export const CheckboxStyled = styled(Checkbox) `
|
|
156
|
-
padding:
|
|
129
|
+
padding: 3px !important;
|
|
157
130
|
border-radius: 10px !important;
|
|
158
131
|
`;
|
|
159
132
|
export const ViewAllWrapper = styled.div `
|
|
@@ -7,6 +7,8 @@ type GroupAccountProps = {
|
|
|
7
7
|
listAccountGroup: any[];
|
|
8
8
|
groupNameKey: string;
|
|
9
9
|
groupIdKey: string;
|
|
10
|
+
groupText?: string;
|
|
11
|
+
accountText?: string;
|
|
10
12
|
};
|
|
11
13
|
export type SelectAccountWithUsers = {
|
|
12
14
|
users?: Record<any, string>[];
|
|
@@ -27,6 +29,7 @@ export type SelectAccountProps = {
|
|
|
27
29
|
onlyOne?: boolean;
|
|
28
30
|
disabled?: boolean;
|
|
29
31
|
disabledAccount?: any[];
|
|
32
|
+
limit?: number;
|
|
30
33
|
limitShow?: number;
|
|
31
34
|
className?: string;
|
|
32
35
|
styles?: {
|
|
@@ -64,6 +67,9 @@ export type TAction = {
|
|
|
64
67
|
payload: {
|
|
65
68
|
formRef: React.RefObject<HTMLFormElement>;
|
|
66
69
|
};
|
|
70
|
+
} | {
|
|
71
|
+
type: 'APPLY_SELECTED';
|
|
72
|
+
payload: any[];
|
|
67
73
|
} | {
|
|
68
74
|
type: 'UPDATE';
|
|
69
75
|
payload: SelectAccountProps;
|
|
@@ -58,6 +58,7 @@ export * from './ProcessLoading';
|
|
|
58
58
|
export * from './Tree';
|
|
59
59
|
export * from './MatchAnySelect';
|
|
60
60
|
export * from './ApplyPopupContent';
|
|
61
|
+
export * from './AccessDenied';
|
|
61
62
|
export { EditorScript } from './EditorScript';
|
|
62
63
|
export { EditorTab } from './EditorTab';
|
|
63
64
|
export { SelectAccount } from './SelectAccount';
|
|
@@ -58,6 +58,7 @@ export * from './ProcessLoading';
|
|
|
58
58
|
export * from './Tree';
|
|
59
59
|
export * from './MatchAnySelect';
|
|
60
60
|
export * from './ApplyPopupContent';
|
|
61
|
+
export * from './AccessDenied';
|
|
61
62
|
export { EditorScript } from './EditorScript';
|
|
62
63
|
export { EditorTab } from './EditorTab';
|
|
63
64
|
export { SelectAccount } from './SelectAccount';
|
|
@@ -24,8 +24,9 @@ import { translate } from './utils';
|
|
|
24
24
|
import Icon from '@antscorp/icons';
|
|
25
25
|
import { useDebounce } from '@antscorp/antsomi-ui/es/hooks/useDebounceV2';
|
|
26
26
|
import { DEFAULT_TRANSLATE_DATA } from './constant';
|
|
27
|
-
import { THEME } from '@antscorp/antsomi-ui/es/constants';
|
|
27
|
+
import { THEME, UOGS_PREFIX } from '@antscorp/antsomi-ui/es/constants';
|
|
28
28
|
import { useAppConfigContext } from '../../..';
|
|
29
|
+
// Constants
|
|
29
30
|
import { ENV } from '@antscorp/antsomi-ui/es/config';
|
|
30
31
|
// const STEP = {
|
|
31
32
|
// SWITCH_ACCOUNT: 'SWITCH_ACCOUNT',
|
|
@@ -228,7 +229,7 @@ export const AccountSharing = props => {
|
|
|
228
229
|
});
|
|
229
230
|
// const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
230
231
|
const onClickButtonLogout = () => {
|
|
231
|
-
removeCookie(
|
|
232
|
+
removeCookie(`${UOGS_PREFIX}${networkId}`, Object.assign(Object.assign({}, (env !== ENV.DEV && {
|
|
232
233
|
domain: `.${origin.split('.').splice(-2).join('.')}`,
|
|
233
234
|
})), { path: '/', sameSite: 'none', secure: true }));
|
|
234
235
|
if (callbackLogout)
|
|
@@ -17,22 +17,24 @@ import { cloneDeep, isString, merge, omit } from 'lodash';
|
|
|
17
17
|
import isEqual from 'react-fast-compare';
|
|
18
18
|
import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
|
|
19
19
|
import { Helmet } from 'react-helmet';
|
|
20
|
+
import { useCookies } from 'react-cookie';
|
|
20
21
|
// Styled
|
|
21
22
|
import { ChildrenWrapper, ContentWrapper, LayoutWrapper, NotificationWrapper } from './styled';
|
|
22
23
|
// Components
|
|
23
24
|
import { LeftMenu } from '../../organism';
|
|
24
25
|
import { Flex } from '../../atoms';
|
|
25
|
-
import { HeaderV2 } from '../../molecules';
|
|
26
|
+
import { HeaderV2, AccessDenied } from '../../molecules';
|
|
26
27
|
// Contexts
|
|
27
28
|
import { AppConfigContext } from '../../..';
|
|
28
29
|
// Constants
|
|
29
|
-
import { APP_CODES, APP_IAM_DOMAIN, APP_PERMISSION_DOMAIN, IAM_API, PERMISSION_API, PORTALS_IDS, SOCKET_API, } from '../../../constants';
|
|
30
|
+
import { APP_CODES, APP_IAM_DOMAIN, APP_PERMISSION_DOMAIN, IAM_API, PERMISSION_API, PORTALS_IDS, SOCKET_API, UOGS_PREFIX, } from '../../../constants';
|
|
31
|
+
import { ENV } from '@antscorp/antsomi-ui/es/config';
|
|
30
32
|
// Css
|
|
31
33
|
import '@antscorp/processing-notification/dist/index.css';
|
|
32
34
|
import { useLayoutStore } from './stores';
|
|
33
35
|
// Utils
|
|
34
36
|
import { hasSelectAccountPermission } from './utils';
|
|
35
|
-
import { useDeepCompareMemo, useMutationObserver } from '@antscorp/antsomi-ui/es/hooks';
|
|
37
|
+
import { useCustomRouter, useDeepCompareMemo, useMutationObserver, } from '@antscorp/antsomi-ui/es/hooks';
|
|
36
38
|
import { HOME_MENU_ITEMS } from '../../organism/LeftMenu/constants';
|
|
37
39
|
import { RecommendationWorkspace } from './components';
|
|
38
40
|
import i18nInstance from '@antscorp/antsomi-ui/es/locales/i18n';
|
|
@@ -40,6 +42,7 @@ const { DATAFLOWS, APP_ANTALYSER } = APP_CODES;
|
|
|
40
42
|
export const Layout = memo(props => {
|
|
41
43
|
const { leftMenuProps, headerProps = {}, workspaceProps, contentWrapperProps, processingNotificationProps, children, onActiveMenuChange, } = props;
|
|
42
44
|
const _a = workspaceProps || {}, { workspaceContentProps } = _a, restOfWorkspaceProps = __rest(_a, ["workspaceContentProps"]);
|
|
45
|
+
// Hooks
|
|
43
46
|
const appConfig = useContextSelector(AppConfigContext, state => state);
|
|
44
47
|
const { auth, languageCode, appCode, permissionDomain: configPermissionDomain, iamDomain: configIamDomain, env, } = appConfig;
|
|
45
48
|
const { token, userId, portalId } = auth || {};
|
|
@@ -47,10 +50,13 @@ export const Layout = memo(props => {
|
|
|
47
50
|
const header = useLayoutStore(store => store.state.header);
|
|
48
51
|
const contentWrapper = useLayoutStore(store => store.state.contentWrapper);
|
|
49
52
|
const workspace = useLayoutStore(store => store.state.workspace);
|
|
53
|
+
const [, , removeCookie] = useCookies();
|
|
54
|
+
const { navigate } = useCustomRouter();
|
|
50
55
|
const [showAccountSelection, setShowAccountSelection] = useState(false);
|
|
51
56
|
const [noSpaceTopContent, setNoSpaceTopContent] = useState(false);
|
|
52
57
|
const [activeMenuCode, setActiveMenuCode] = useState('');
|
|
53
58
|
const [activePageTitle, setActivePageTitle] = useState('');
|
|
59
|
+
const [isAccessDenied, setIsAccessDenied] = useState(false);
|
|
54
60
|
const notificationWrapperRef = useRef(null);
|
|
55
61
|
useMutationObserver(() => {
|
|
56
62
|
if (notificationWrapperRef.current) {
|
|
@@ -125,7 +131,7 @@ export const Layout = memo(props => {
|
|
|
125
131
|
const onActiveMenuCodeChange = useCallback((activeItemPath, flattenPermissionList, menuListPermission) => {
|
|
126
132
|
var _a;
|
|
127
133
|
const activeMenuItem = activeItemPath === null || activeItemPath === void 0 ? void 0 : activeItemPath[(activeItemPath === null || activeItemPath === void 0 ? void 0 : activeItemPath.length) - 1];
|
|
128
|
-
const { menu_item_code, page_title, menu_item_name } = activeMenuItem || {};
|
|
134
|
+
const { menu_item_code, page_title, menu_item_name, permission_code } = activeMenuItem || {};
|
|
129
135
|
setActivePageTitle(page_title
|
|
130
136
|
? i18nInstance.t((_a = translations.leftMenu.pageTitle) === null || _a === void 0 ? void 0 : _a[`${page_title}`]).toString()
|
|
131
137
|
: menu_item_name);
|
|
@@ -138,7 +144,20 @@ export const Layout = memo(props => {
|
|
|
138
144
|
appItem: activeItemPath[0],
|
|
139
145
|
});
|
|
140
146
|
setShowAccountSelection(hasRole);
|
|
147
|
+
// Check if the user has permission or not (access denied)
|
|
148
|
+
if (!!permission_code && !!activeMenuItem && !!flattenPermissionList) {
|
|
149
|
+
const isAccessDenied = !flattenPermissionList.some(item => item.menu_code === activeMenuItem.permission_code);
|
|
150
|
+
setIsAccessDenied(isAccessDenied);
|
|
151
|
+
}
|
|
141
152
|
}, [onActiveMenuChange]);
|
|
153
|
+
const onClickSwitchAccount = useCallback(() => {
|
|
154
|
+
// Remove cookie when switch account
|
|
155
|
+
removeCookie(`${UOGS_PREFIX}${portalId}`, Object.assign(Object.assign({}, (env !== ENV.DEV && {
|
|
156
|
+
domain: `.${origin.split('.').splice(-2).join('.')}`,
|
|
157
|
+
})), { path: '/', sameSite: 'none', secure: true }));
|
|
158
|
+
// Redirect to login page
|
|
159
|
+
navigate('/login');
|
|
160
|
+
}, [env, portalId, navigate, removeCookie]);
|
|
142
161
|
return (React.createElement(LayoutWrapper, { showLeftMenu: !!showLeftMenu },
|
|
143
162
|
React.createElement(Helmet, null,
|
|
144
163
|
React.createElement("meta", { charSet: "utf-8" }),
|
|
@@ -154,6 +173,5 @@ export const Layout = memo(props => {
|
|
|
154
173
|
React.createElement(ContentWrapper, Object.assign({ "$noPadding": noPadding, "$noSpaceTopContent": noSpaceTopContent }, mergeContentWrapperProps), activeMenuCode === HOME_MENU_ITEMS.RECOMMENDATION.menu_item_code ? (React.createElement("div", { className: "layout-body__content" },
|
|
155
174
|
React.createElement(RecommendationWorkspace, null))) : (React.createElement("div", Object.assign({ className: `layout-body__content ${(workspaceProps === null || workspaceProps === void 0 ? void 0 : workspaceProps.className) || ''}` }, mergeWorkSpaceProps),
|
|
156
175
|
React.createElement(NotificationWrapper, { className: "process-notification", ref: notificationWrapperRef }, showNotification && (React.createElement(AntsProcessingNotification, Object.assign({}, antsProcessingNotificationConfig)))),
|
|
157
|
-
React.createElement(ChildrenWrapper, Object.assign({}, workspaceContentProps),
|
|
158
|
-
React.createElement("div", null, children))))))));
|
|
176
|
+
React.createElement(ChildrenWrapper, Object.assign({}, workspaceContentProps), isAccessDenied ? (React.createElement(AccessDenied, { onClickSwitchAccount: onClickSwitchAccount })) : (React.createElement("div", null, children)))))))));
|
|
159
177
|
}, (prevProps, nextProps) => isEqual(prevProps, nextProps));
|
package/es/constants/theme.js
CHANGED
|
@@ -102,6 +102,9 @@ THEME.components = {
|
|
|
102
102
|
colorBgTextHover: (_f = THEME.token) === null || _f === void 0 ? void 0 : _f.blue,
|
|
103
103
|
colorBgTextActive: (_g = THEME.token) === null || _g === void 0 ? void 0 : _g.blue1_1,
|
|
104
104
|
},
|
|
105
|
+
Typography: {
|
|
106
|
+
lineHeight: 1.2,
|
|
107
|
+
},
|
|
105
108
|
Input: {
|
|
106
109
|
controlHeight: 31,
|
|
107
110
|
colorBgContainerDisabled: (_h = THEME.token) === null || _h === void 0 ? void 0 : _h.bw2,
|
|
@@ -658,5 +658,12 @@
|
|
|
658
658
|
"_builtIn": "Built in",
|
|
659
659
|
"_standard": "Standard"
|
|
660
660
|
}
|
|
661
|
+
},
|
|
662
|
+
"accessDenied": {
|
|
663
|
+
"title": "Access Denied",
|
|
664
|
+
"subTitle": "You don’t have permission to access this feature",
|
|
665
|
+
"description": "Ask for permission or switch to an account with access",
|
|
666
|
+
"requestAccess": "Request access",
|
|
667
|
+
"switchAccount": "Switch account"
|
|
661
668
|
}
|
|
662
669
|
}
|
package/es/locales/i18n.d.ts
CHANGED
|
@@ -661,6 +661,13 @@ export declare const translationsJson: {
|
|
|
661
661
|
_standard: string;
|
|
662
662
|
};
|
|
663
663
|
};
|
|
664
|
+
accessDenied: {
|
|
665
|
+
title: string;
|
|
666
|
+
subTitle: string;
|
|
667
|
+
description: string;
|
|
668
|
+
requestAccess: string;
|
|
669
|
+
switchAccount: string;
|
|
670
|
+
};
|
|
664
671
|
};
|
|
665
672
|
};
|
|
666
673
|
vi: {
|
|
@@ -875,6 +882,13 @@ export declare const translationsJson: {
|
|
|
875
882
|
_standard: string;
|
|
876
883
|
};
|
|
877
884
|
};
|
|
885
|
+
accessDenied: {
|
|
886
|
+
title: string;
|
|
887
|
+
subTitle: string;
|
|
888
|
+
description: string;
|
|
889
|
+
requestAccess: string;
|
|
890
|
+
switchAccount: string;
|
|
891
|
+
};
|
|
878
892
|
};
|
|
879
893
|
};
|
|
880
894
|
};
|
|
@@ -661,6 +661,13 @@ export declare const convertLanguageJsonToObject: (json: any, objToConvertTo?: C
|
|
|
661
661
|
_standard: string;
|
|
662
662
|
};
|
|
663
663
|
};
|
|
664
|
+
accessDenied: {
|
|
665
|
+
title: string;
|
|
666
|
+
subTitle: string;
|
|
667
|
+
description: string;
|
|
668
|
+
requestAccess: string;
|
|
669
|
+
switchAccount: string;
|
|
670
|
+
};
|
|
664
671
|
}>, current?: string) => void;
|
|
665
672
|
export declare const t: (id: string, ...rest: any[]) => [string, ...any[]];
|
|
666
673
|
export declare const getTranslateMessage: (id: string, defaultMessage?: string, value?: Record<string, unknown>) => string;
|
|
@@ -208,5 +208,12 @@
|
|
|
208
208
|
"_builtIn": "Mẫu",
|
|
209
209
|
"_standard": "Tiêu chuẩn"
|
|
210
210
|
}
|
|
211
|
+
},
|
|
212
|
+
"accessDenied": {
|
|
213
|
+
"title": "Truy cập bị từ chối",
|
|
214
|
+
"subTitle": "Bạn không có quyền truy cập tính năng này",
|
|
215
|
+
"description": "Hãy yêu cầu quyền truy cập hoặc chuyển sang tài khoản có quyền",
|
|
216
|
+
"requestAccess": "Yêu cầu truy cập",
|
|
217
|
+
"switchAccount": "Đổi tài khoản"
|
|
211
218
|
}
|
|
212
219
|
}
|