@topconsultnpm/sdkui-react-beta 6.7.21 → 6.7.23
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/lib/components/base/TMListView.d.ts +1 -0
- package/lib/components/base/TMListView.js +2 -1
- package/lib/components/forms/TMLoginForm.js +3 -3
- package/lib/components/forms/TMLoginPopupSaveLoginInfo.d.ts +9 -1
- package/lib/components/forms/TMLoginPopupSaveLoginInfo.js +144 -62
- package/lib/helper/SDKUI_Localizator.d.ts +1 -1
- package/lib/helper/SDKUI_Localizator.js +6 -6
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import { IconApply, IconCloseCircle, IconColumns, IconDown, IconHide, IconShow,
|
|
|
7
7
|
import { TMSearchBar } from '../sidebar/TMHeader';
|
|
8
8
|
import TMTooltip from './TMTooltip';
|
|
9
9
|
import { SDKUI_Localizator } from '../../helper';
|
|
10
|
+
import { TMColors } from '../../utils/theme';
|
|
10
11
|
const StyledListItem = styled.div ` width: 100%; height: max-content; border-bottom: 1px solid #e5e5e5; background-color: ${props => props.$isSelected ? props.$color ? `${props.$color}99` : '#00000030' : 'transparent'} ; color: ${props => props.$isSelected ? props.$color ? 'white' : '#000000' : '#000000'} ; &:hover{ background-color: ${props => props.$color ? props.$isSelected ? `${props.$color}99` : `${props.$color}40` : props.$isSelected ? '#00000030' : '#00000010'};} `;
|
|
11
12
|
const StyledListViewContainer = styled.div ` position: relative; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; width: 100%; height: 100%; `;
|
|
12
13
|
const StyledSearchContainer = styled.div ` width: 100%; height: max-content; padding: 5px; border-bottom: 1px solid #e5e5e5; display: flex; align-items: center; gap: 10px; `;
|
|
@@ -330,5 +331,5 @@ const TMListView = ({ customGroupingHeaders, headerBackGroundColor, header, show
|
|
|
330
331
|
};
|
|
331
332
|
export default TMListView;
|
|
332
333
|
export const CustomListViewHeader = (props) => {
|
|
333
|
-
return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', padding: '0 5px', gap: 5 }, children: [props.headerIcon, _jsx("p", { children: props.headerTitle }), props.firstCounter, props.secondCounter] }));
|
|
334
|
+
return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', padding: '0 5px', gap: 5 }, children: [props.headerIcon, _jsx("p", { style: { fontWeight: 'bold', color: props.titleColor ? props.titleColor : TMColors.text_normal }, children: props.headerTitle }), props.firstCounter, props.secondCounter] }));
|
|
334
335
|
};
|
|
@@ -146,13 +146,13 @@ const TMLoginForm = (props) => {
|
|
|
146
146
|
}
|
|
147
147
|
}, []);
|
|
148
148
|
useEffect(() => {
|
|
149
|
-
const loginWidthEnterKey = (e) => { if (loginValidationItems.length === 0) {
|
|
149
|
+
const loginWidthEnterKey = (e) => { if (loginValidationItems.length === 0 && !popupSaveLoginInfoVisible) {
|
|
150
150
|
if (e.key === 'Enter')
|
|
151
151
|
login();
|
|
152
152
|
} };
|
|
153
153
|
window.addEventListener('keyup', loginWidthEnterKey);
|
|
154
154
|
return () => window.removeEventListener('keyup', loginWidthEnterKey);
|
|
155
|
-
}, [loginValidationItems]);
|
|
155
|
+
}, [loginValidationItems, popupSaveLoginInfoVisible]);
|
|
156
156
|
// useEffect(() => { setEndpoint(props.endpoints[0]) }, [endpoints])
|
|
157
157
|
useEffect(() => { setEndpoint(props.endpoints.find(ep => ep.isDefault)); }, [endpoints]);
|
|
158
158
|
useEffect(() => { setTmServer(new TopMediaServer(endpoint?.URL)); }, [endpoint]);
|
|
@@ -844,7 +844,7 @@ const TMLoginForm = (props) => {
|
|
|
844
844
|
_jsxs(_Fragment, { children: [_jsx(TMTextBox, { label: SDKUI_Localizator.Domain, icon: _jsx(IconWeb, {}), value: domainAlternative, onValueChanged: (e) => setDomainArternative(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'domain_alt') }), _jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'username'), label: SDKUI_Localizator.UserName, icon: _jsx(IconUser, {}), value: username, onValueChanged: (e) => setUsername(e.target.value) }), _jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'password'), type: "password", label: SDKUI_Localizator.Password, icon: _jsx(IconPassword, {}), value: password, onValueChanged: (e) => setPassword(e.target.value) })] })
|
|
845
845
|
:
|
|
846
846
|
_jsxs(_Fragment, { children: [_jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'username'), label: SDKUI_Localizator.UserName, icon: _jsx(IconUser, {}), value: username, onValueChanged: (e) => setUsername(e.target.value) }), _jsx(TMLayoutItem, { children: _jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'password'), type: "password", label: SDKUI_Localizator.Password, icon: _jsx(IconPassword, {}), value: password, onValueChanged: (e) => setPassword(e.target.value) }) })] }) }), authMode === AuthenticationModes.TopMediaOnBehalfOf && _jsx(TMLayoutItem, { children: _jsxs(TMLayoutContainer, { direction: "horizontal", children: [_jsx(TMLayoutItem, { children: _jsxs(TMLayoutContainer, { children: [_jsx(TMLayoutItem, { children: _jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'username'), label: SDKUI_Localizator.UserName, icon: _jsx(IconUser, {}), value: username, onValueChanged: (e) => setUsername(e.target.value) }) }), _jsx(TMLayoutItem, { children: _jsx(TMTextBox, { validationItems: loginValidationItems.filter(item => item.PropertyName === 'password'), type: "password", label: SDKUI_Localizator.Password, icon: _jsx(IconPassword, {}), value: password, onValueChanged: (e) => setPassword(e.target.value) }) })] }) }), _jsx(TMLayoutItem, { children: _jsxs(TMLayoutContainer, { children: [_jsx(TMLayoutItem, { children: _jsx(TMTextBox, { label: SDKUI_Localizator.Domain, icon: _jsx(IconWeb, {}), value: domain, onValueChanged: (e) => setDomain(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'domain') }) }), _jsx(TMLayoutItem, { children: _jsx(TMTextBox, { label: SDKUI_Localizator.UserName, icon: _jsx(IconUser, {}), value: onBehalfUsername, onValueChanged: (e) => setOnBeHalfUsername(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'onBeHalfUsername') }) })] }) })] }) }), authMode !== AuthenticationModes.TopMediaOnBehalfOf ? _jsx(TMLayoutItem, { children: _jsx(TMDropDown, { dataSource: cultureIDsDataSource, icon: _jsx(IconLanguage, {}), label: SDKUI_Localizator.CultureID, onValueChanged: (e) => props.onChangeLanguage && props.onChangeLanguage(e.target.value), value: props.cultureID, validationItems: loginValidationItems.filter(item => item.PropertyName === 'cultureId') }) }) :
|
|
847
|
-
_jsxs(TMLayoutContainer, { direction: "horizontal", children: [_jsx(TMLayoutItem, { children: _jsx(TMDropDown, { dataSource: cultureIDsDataSource, icon: _jsx(IconLanguage, {}), label: SDKUI_Localizator.CultureID, onValueChanged: (e) => props.onChangeLanguage && props.onChangeLanguage(e.target.value), value: props.cultureID, validationItems: loginValidationItems.filter(item => item.PropertyName === 'cultureId') }) }), _jsx(TMLayoutItem, { children: _jsx(TMTextBox, { type: "password", label: SDKUI_Localizator.Password, icon: _jsx(IconPassword, {}), value: onBeHalfPassword, onValueChanged: (e) => setOnBeHalfPassword(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'onBeHalfPassword') }) })] }), props.saveLoginHistoryToLocalStorage && _jsxs(TMLayoutItem, { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', marginTop: 12 }, children: [_jsx("i", { style: { fontSize: 20 }, className: "dx-icon-save" }), _jsx(TMCheckBox, { elementStyle: { marginLeft: 5 }, labelPosition: "left", label: SDKUI_Localizator.RememberCredentials, value: saveLoginInfo, onValueChanged: () => { setSaveLoginInfo(prevSaveLoginInfo => !prevSaveLoginInfo); }, isModifiedWhen: saveLoginInfo })] }), saveLoginInfo && _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.EnterNameForAccess, icon: _jsx("i", { style: { fontSize: 20 }, className: "dx-icon-save" }), value: saveLoginInfoName, onValueChanged: (e) => setSaveLoginInfoName(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'saveLoginName') })] })] }) }) }) }), _jsxs(TMLayoutItem, { height: "fit-content", width: "fit-content", children: [props.saveLoginHistoryToLocalStorage && _jsx("p", { onClick: showPopupSaveLoginInfo, onKeyDown: (e) => { }, style: { marginTop: '10px', userSelect: 'none', cursor: 'pointer', color: TMColors.primary, textAlign: 'center', fontSize: '0.9rem' }, children: SDKUI_Localizator.SwitchUser }), authMode === AuthenticationModes.TopMedia && _jsxs("div", { children: [_jsx("p", { onClick: () => isPasswordChangeEnable() && setTogglePages({ recovery: false, change: true, archive: false, endpoint: false }), tabIndex: isPasswordChangeEnable() ? 0 : undefined, onKeyDown: (e) => e.code === 'Space' && setTogglePages({ recovery: false, change: true, archive: false, endpoint: false }), style: { marginTop: '10px', userSelect: 'none', cursor: isPasswordChangeEnable() ? 'pointer' : 'default', color: isPasswordChangeEnable() ? TMColors.primary : 'rgb(180,180,180)', textAlign: 'center', fontSize: '0.9rem' }, children: SDKUI_Localizator.ChangePassword }), _jsx("p", { tabIndex: isPasswordChangeEnable() ? 0 : undefined, onKeyDown: (e) => e.code === 'Space' && showRecoveryPassword(), onClick: () => isPasswordChangeEnable() && showRecoveryPassword(), style: { userSelect: 'none', marginTop: '10px', cursor: isPasswordChangeEnable() ? 'pointer' : 'default', color: isPasswordChangeEnable() ? TMColors.primary : 'rgb(180,180,180)', fontSize: '0.9rem' }, children: SDKUI_Localizator.ForgetPassword })] })] }), _jsx(TMLayoutItem, { height: "fit-content", children: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px 0' }, children: _jsx(TMButton, { width: calcResponsiveSizes(deviceType, '150px', '150px', '250px'), height: calcResponsiveSizes(deviceType, '30px', '40px', '40px'), fontSize: "1.1rem", caption: "Login", disabled: loginValidationItems.length > 0, onClick: login, showTooltip: false }) }) })] }) })] })] }), _jsx(TMLoginPopupSaveLoginInfo, { visible: popupSaveLoginInfoVisible, hidePopup: hidePopupSaveLoginInfo,
|
|
847
|
+
_jsxs(TMLayoutContainer, { direction: "horizontal", children: [_jsx(TMLayoutItem, { children: _jsx(TMDropDown, { dataSource: cultureIDsDataSource, icon: _jsx(IconLanguage, {}), label: SDKUI_Localizator.CultureID, onValueChanged: (e) => props.onChangeLanguage && props.onChangeLanguage(e.target.value), value: props.cultureID, validationItems: loginValidationItems.filter(item => item.PropertyName === 'cultureId') }) }), _jsx(TMLayoutItem, { children: _jsx(TMTextBox, { type: "password", label: SDKUI_Localizator.Password, icon: _jsx(IconPassword, {}), value: onBeHalfPassword, onValueChanged: (e) => setOnBeHalfPassword(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'onBeHalfPassword') }) })] }), props.saveLoginHistoryToLocalStorage && _jsxs(TMLayoutItem, { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', marginTop: 12 }, children: [_jsx("i", { style: { fontSize: 20 }, className: "dx-icon-save" }), _jsx(TMCheckBox, { elementStyle: { marginLeft: 5 }, labelPosition: "left", label: SDKUI_Localizator.RememberCredentials, value: saveLoginInfo, onValueChanged: () => { setSaveLoginInfo(prevSaveLoginInfo => !prevSaveLoginInfo); }, isModifiedWhen: saveLoginInfo })] }), saveLoginInfo && _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.EnterNameForAccess, icon: _jsx("i", { style: { fontSize: 20 }, className: "dx-icon-save" }), value: saveLoginInfoName, onValueChanged: (e) => setSaveLoginInfoName(e.target.value), validationItems: loginValidationItems.filter(item => item.PropertyName === 'saveLoginName') })] })] }) }) }) }), _jsxs(TMLayoutItem, { height: "fit-content", width: "fit-content", children: [props.saveLoginHistoryToLocalStorage && _jsx("p", { onClick: showPopupSaveLoginInfo, onKeyDown: (e) => { }, style: { marginTop: '10px', userSelect: 'none', cursor: 'pointer', color: TMColors.primary, textAlign: 'center', fontSize: '0.9rem' }, children: SDKUI_Localizator.SwitchUser }), authMode === AuthenticationModes.TopMedia && _jsxs("div", { children: [_jsx("p", { onClick: () => isPasswordChangeEnable() && setTogglePages({ recovery: false, change: true, archive: false, endpoint: false }), tabIndex: isPasswordChangeEnable() ? 0 : undefined, onKeyDown: (e) => e.code === 'Space' && setTogglePages({ recovery: false, change: true, archive: false, endpoint: false }), style: { marginTop: '10px', userSelect: 'none', cursor: isPasswordChangeEnable() ? 'pointer' : 'default', color: isPasswordChangeEnable() ? TMColors.primary : 'rgb(180,180,180)', textAlign: 'center', fontSize: '0.9rem' }, children: SDKUI_Localizator.ChangePassword }), _jsx("p", { tabIndex: isPasswordChangeEnable() ? 0 : undefined, onKeyDown: (e) => e.code === 'Space' && showRecoveryPassword(), onClick: () => isPasswordChangeEnable() && showRecoveryPassword(), style: { userSelect: 'none', marginTop: '10px', cursor: isPasswordChangeEnable() ? 'pointer' : 'default', color: isPasswordChangeEnable() ? TMColors.primary : 'rgb(180,180,180)', fontSize: '0.9rem' }, children: SDKUI_Localizator.ForgetPassword })] })] }), _jsx(TMLayoutItem, { height: "fit-content", children: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px 0' }, children: _jsx(TMButton, { width: calcResponsiveSizes(deviceType, '150px', '150px', '250px'), height: calcResponsiveSizes(deviceType, '30px', '40px', '40px'), fontSize: "1.1rem", caption: "Login", disabled: loginValidationItems.length > 0, onClick: login, showTooltip: false }) }) })] }) })] })] }), _jsx(TMLoginPopupSaveLoginInfo, { visible: popupSaveLoginInfoVisible, hidePopup: hidePopupSaveLoginInfo, setLoginHistory: setLoginHistory, setEndpoint: setEndpoint, setArchive: setArchive, setAuthMode: setAuthMode, setUsername: setUsername, setPassword: setPassword, setDomain: setDomain, setDomainArternative: setDomainArternative, setOnBeHalfUsername: setOnBeHalfUsername, setOnBeHalfPassword: setOnBeHalfPassword, onChangeLanguage: onChangeLanguage })] }));
|
|
848
848
|
};
|
|
849
849
|
const TMPasswordManager = ({ validationItems = [], operation = 'change' }) => {
|
|
850
850
|
const passwordStrength = () => {
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
import { ITMLoginHistory, TMEndpointsType } from "./TMLoginForm";
|
|
3
3
|
import { ArchiveDescriptor, AuthenticationModes, CultureIDs } from "@topconsultnpm/sdk-ts-beta";
|
|
4
4
|
interface TMLoginPopupSaveLoginInfoProps {
|
|
5
|
-
loginHistory: Array<ITMLoginHistory>;
|
|
6
5
|
setLoginHistory: React.Dispatch<React.SetStateAction<Array<ITMLoginHistory>>>;
|
|
7
6
|
visible: boolean;
|
|
8
7
|
hidePopup: () => void;
|
|
@@ -19,3 +18,12 @@ interface TMLoginPopupSaveLoginInfoProps {
|
|
|
19
18
|
}
|
|
20
19
|
declare const TMLoginPopupSaveLoginInfo: (props: TMLoginPopupSaveLoginInfoProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
20
|
export default TMLoginPopupSaveLoginInfo;
|
|
21
|
+
interface TMLoginItemTemplateProps {
|
|
22
|
+
data: ITMLoginHistory;
|
|
23
|
+
reloadHistoryState: () => void;
|
|
24
|
+
fillLoginForm: (data: ITMLoginHistory) => void;
|
|
25
|
+
deleteItemFromLocalStorage: (name: string) => void;
|
|
26
|
+
setSelectedItems: React.Dispatch<React.SetStateAction<ITMLoginHistory[]>>;
|
|
27
|
+
setSearchText: React.Dispatch<React.SetStateAction<string>>;
|
|
28
|
+
}
|
|
29
|
+
export declare const TMLoginItemTemplate: React.FC<TMLoginItemTemplateProps>;
|
|
@@ -1,69 +1,82 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { Accordion, LoadIndicator, Popup
|
|
3
|
+
import { Accordion, LoadIndicator, Popup } from "devextreme-react";
|
|
4
4
|
import { cultureIDsDataSource, LOGIN_HISTORY_KEY, } from "./TMLoginForm";
|
|
5
|
-
import { LocalStorageService } from "@topconsultnpm/sdk-ts-beta";
|
|
5
|
+
import { LocalStorageService, ResultTypes, SDK_Localizator, ValidationItem } from "@topconsultnpm/sdk-ts-beta";
|
|
6
6
|
import { Item } from "devextreme-react/cjs/accordion";
|
|
7
7
|
import { SDKUI_Localizator } from "../../helper/SDKUI_Localizator";
|
|
8
8
|
import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from "../base/TMPopUp";
|
|
9
9
|
import TMTooltip from "../base/TMTooltip";
|
|
10
10
|
import TMTextBox from "../editors/TMTextBox";
|
|
11
|
+
import { TMSearchBar } from "../sidebar/TMHeader";
|
|
11
12
|
const TMLoginPopupSaveLoginInfo = (props) => {
|
|
12
|
-
const {
|
|
13
|
-
|
|
13
|
+
const { setLoginHistory, visible, hidePopup, setEndpoint, setArchive, setAuthMode, setUsername, setPassword, setDomain, setDomainArternative, setOnBeHalfUsername, setOnBeHalfPassword, onChangeLanguage } = props;
|
|
14
|
+
// State to manage loading status
|
|
14
15
|
const [loading, setLoading] = useState(false);
|
|
16
|
+
// State to store the search input text
|
|
15
17
|
const [searchText, setSearchText] = useState('');
|
|
18
|
+
// State to store selected items of type ITMLoginHistory
|
|
19
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
|
20
|
+
// Retrieve the login history from local storage, sort by 'name', and return the sorted array (or an empty array if not found)
|
|
21
|
+
const getSortedLoginHistory = () => {
|
|
22
|
+
const loginHistory = LocalStorageService.getItem(LOGIN_HISTORY_KEY);
|
|
23
|
+
return loginHistory?.sort((a, b) => a.name.localeCompare(b.name)) || [];
|
|
24
|
+
};
|
|
25
|
+
// State to store both the full login history and the filtered search history
|
|
26
|
+
const [historyState, setHistoryState] = useState({
|
|
27
|
+
loginHistory: getSortedLoginHistory(),
|
|
28
|
+
searchedLoginHistory: getSortedLoginHistory(),
|
|
29
|
+
});
|
|
30
|
+
// Handle search input changes with a debounce effect, updating the searched login history after a delay
|
|
16
31
|
useEffect(() => {
|
|
17
32
|
let timeoutId;
|
|
18
33
|
if (searchText.length > 0) {
|
|
19
34
|
setLoading(true);
|
|
20
35
|
timeoutId = setTimeout(() => {
|
|
21
|
-
|
|
36
|
+
setHistoryState(prevState => ({
|
|
37
|
+
...prevState,
|
|
38
|
+
searchedLoginHistory: historyState.loginHistory.filter(data => data.name.toLowerCase().includes(searchText.toLowerCase()))
|
|
39
|
+
}));
|
|
22
40
|
setLoading(false);
|
|
23
41
|
}, 300);
|
|
24
42
|
}
|
|
25
43
|
else {
|
|
26
|
-
|
|
44
|
+
setHistoryState(prevState => ({ ...prevState, loginHistory: historyState.loginHistory, searchedLoginHistory: historyState.loginHistory }));
|
|
27
45
|
setLoading(false);
|
|
28
46
|
}
|
|
29
47
|
return () => {
|
|
30
48
|
clearTimeout(timeoutId);
|
|
31
49
|
};
|
|
32
50
|
}, [searchText]);
|
|
33
|
-
// Function to
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
return hash;
|
|
51
|
+
// Function to reload and update state
|
|
52
|
+
const reloadHistoryState = () => {
|
|
53
|
+
const updatedLoginHistory = getSortedLoginHistory();
|
|
54
|
+
setHistoryState({
|
|
55
|
+
loginHistory: updatedLoginHistory,
|
|
56
|
+
searchedLoginHistory: updatedLoginHistory,
|
|
57
|
+
});
|
|
41
58
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const g = (hash & 0x00FF00) >> 8; // Green (8 bits)
|
|
47
|
-
const b = hash & 0x0000FF; // Blue (8 bits)
|
|
48
|
-
// Ensure the RGB values are within the valid range (0-255)
|
|
49
|
-
return `rgb(${r % 256}, ${g % 256}, ${b % 256})`;
|
|
59
|
+
// Update selected items with the last added item from the event (or an empty array if none were added)
|
|
60
|
+
const onSelectionChanged = (e) => {
|
|
61
|
+
const newItems = e.addedItems.length ? [e.addedItems[e.addedItems.length - 1]] : [];
|
|
62
|
+
setSelectedItems(newItems);
|
|
50
63
|
};
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
// Populate the login form fields with data from the selected login history item
|
|
65
|
+
const fillLoginForm = (data) => {
|
|
66
|
+
setEndpoint(data.endpoint);
|
|
67
|
+
setArchive(data.archive);
|
|
68
|
+
setUsername(data.username);
|
|
69
|
+
setPassword("");
|
|
70
|
+
setAuthMode(data.authenticationMode);
|
|
71
|
+
setDomain(data.domain);
|
|
72
|
+
setDomainArternative(data.domainAlternative);
|
|
73
|
+
setOnBeHalfUsername(data.onBehalfUsername);
|
|
74
|
+
setOnBeHalfPassword("");
|
|
75
|
+
if (onChangeLanguage)
|
|
76
|
+
onChangeLanguage(data.language);
|
|
77
|
+
hidePopup();
|
|
65
78
|
};
|
|
66
|
-
|
|
79
|
+
// Display a confirmation dialog for deleting an item from local storage and handle the deletion on confirmation
|
|
67
80
|
const deleteItemFromLocalStorage = (name) => {
|
|
68
81
|
const msg = SDKUI_Localizator.Delete_ConfirmFor1.replaceParams(name);
|
|
69
82
|
TMMessageBoxManager.show({
|
|
@@ -74,7 +87,8 @@ const TMLoginPopupSaveLoginInfo = (props) => {
|
|
|
74
87
|
try {
|
|
75
88
|
LocalStorageService.deleteItemByField(LOGIN_HISTORY_KEY, "name", name);
|
|
76
89
|
setLoginHistory(LocalStorageService.getItem(LOGIN_HISTORY_KEY) ?? []);
|
|
77
|
-
|
|
90
|
+
reloadHistoryState();
|
|
91
|
+
setSelectedItems([]);
|
|
78
92
|
}
|
|
79
93
|
catch (e) {
|
|
80
94
|
TMExceptionBoxManager.show({ exception: e });
|
|
@@ -82,33 +96,101 @@ const TMLoginPopupSaveLoginInfo = (props) => {
|
|
|
82
96
|
}
|
|
83
97
|
});
|
|
84
98
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
setUsername(data.username);
|
|
89
|
-
setPassword("");
|
|
90
|
-
setAuthMode(data.authenticationMode);
|
|
91
|
-
setDomain(data.domain);
|
|
92
|
-
setDomainArternative(data.domainAlternative);
|
|
93
|
-
setOnBeHalfUsername(data.onBehalfUsername);
|
|
94
|
-
setOnBeHalfPassword("");
|
|
95
|
-
if (onChangeLanguage)
|
|
96
|
-
onChangeLanguage(data.language);
|
|
99
|
+
// Clear the search text and close the popup
|
|
100
|
+
const closePopup = () => {
|
|
101
|
+
setSearchText('');
|
|
97
102
|
hidePopup();
|
|
98
103
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return _jsx(ScrollView, { direction: "horizontal", showScrollbar: "always", style: { width: '100%' }, useNative: true, children: _jsxs("div", { style: { display: 'flex', background: '#fff', boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)', overflow: 'hidden', width: '100%', justifyContent: 'center', alignItems: 'center' }, children: [_jsx(TMTooltip, { content: data.name, children: _jsx("div", { style: { background: randomBGColor, color: textColor, display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '70px', maxHeight: '70px', borderRadius: '50%', fontWeight: 'bold', margin: '20px', textAlign: 'center' }, children: data.name.slice(0, 3).toUpperCase() }) }), _jsxs("div", { style: { padding: '5px', flex: 1 }, children: [_jsxs("div", { style: { marginBottom: '12px', fontSize: '1em', color: '#555' }, children: [SDKUI_Localizator.Name, ": ", _jsxs("span", { style: { fontWeight: 'bold', color: '#333' }, children: [" ", data.name] })] }), _jsxs("div", { style: { marginBottom: '12px', fontSize: '1em', color: '#555' }, children: [SDKUI_Localizator.Endpoint, ": ", _jsxs("span", { style: { fontWeight: 'bold', color: '#333' }, children: [" ", data.endpoint?.Description ?? '', "/", data.username] }), " "] }), _jsxs("div", { style: { marginBottom: '12px', fontSize: '1em', color: '#555' }, children: [SDKUI_Localizator.ArchiveID, ": ", _jsxs("span", { style: { fontWeight: 'bold', color: '#333' }, children: [" ", data.archive?.description ?? ''] })] }), _jsxs("div", { style: { marginBottom: '12px', fontSize: '1em', color: '#555' }, children: [SDKUI_Localizator.AuthMode, ":", _jsxs("span", { style: { fontWeight: 'bold', color: '#333' }, children: [" ", data.authenticationMode] })] }), _jsxs("div", { style: { marginBottom: '12px', fontSize: '1em', color: '#555' }, children: [SDKUI_Localizator.CultureID, ":", _jsxs("span", { style: { fontWeight: 'bold', color: '#333' }, children: [" ", cultureIDsDataSource.find(item => item.value === data.language)?.display ?? ''] })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }, children: [_jsx(TMTooltip, { content: "Login", children: _jsx("div", { onClick: () => { fillLoginForm(data); }, style: { backgroundColor: randomBGColor, color: textColor, display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '50px', maxHeight: '50px', borderRadius: '50%', fontWeight: 'bold', marginRight: '10px', textAlign: 'center' }, children: _jsx("i", { className: "dx-icon-login", style: { fontSize: '1.5em', color: textColor, cursor: 'pointer' } }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Delete, children: _jsx("div", { onClick: () => { deleteItemFromLocalStorage(data.name); }, style: { backgroundColor: "#ff4d4f", display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '50px', maxHeight: '50px', borderRadius: '50%', fontWeight: 'bold', textAlign: 'center' }, children: _jsx("i", { className: "dx-icon-trash", style: { fontSize: '1.5em', color: getTextColor("#ff4d4f"), cursor: 'pointer' } }) }) })] })] })] }) });
|
|
104
|
+
// Render a title with a "Switch User" label and a close button styled as an icon
|
|
105
|
+
const titleRender = () => (_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }, children: [_jsx("h3", { children: SDKUI_Localizator.SwitchUser }), _jsx("button", { style: { background: 'none', border: 'none', fontSize: '16px', cursor: 'pointer' }, onClick: hidePopup, children: _jsx("i", { style: { fontSize: 20 }, className: "dx-icon-remove" }) })] }));
|
|
106
|
+
// Render a styled title with its ID and title content, using flex layout
|
|
107
|
+
const itemTitleRender = (titleObj, id) => {
|
|
108
|
+
return _jsxs("div", { style: { display: "flex", gap: "20px", fontFamily: "Arial, sans-serif" }, children: [_jsx("div", { style: { padding: "10px", border: "1px solid #ddd", borderRadius: "10px", }, children: id }), _jsx("div", { style: { padding: "10px", fontWeight: "bold", border: "1px solid #ddd", borderRadius: "10px", }, children: titleObj.title })] });
|
|
105
109
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
// Conditionally render popup content based on loading state, available login history, or display login items in an accordion
|
|
111
|
+
const renderPopupContent = () => {
|
|
112
|
+
if (loading) {
|
|
113
|
+
return (_jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", width: "100%" }, children: _jsx(LoadIndicator, {}) }));
|
|
114
|
+
}
|
|
115
|
+
if (historyState.searchedLoginHistory.length === 0) {
|
|
116
|
+
return (_jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", textAlign: "center", padding: "20px" }, children: SDKUI_Localizator.NoCredentialsSaved }));
|
|
117
|
+
}
|
|
118
|
+
return (_jsx("div", { style: { overflowY: "auto", maxHeight: "calc(100% - 60px)", padding: "10px" }, children: _jsx(Accordion, { selectedItems: selectedItems, onSelectionChanged: onSelectionChanged, collapsible: true, multiple: false, animationDuration: 300, noDataText: SDKUI_Localizator.NoCredentialsSaved, style: { border: "1px solid #ddd", borderRadius: "6px", boxShadow: "0 2px 6px rgba(0, 0, 0, 0.1)" }, children: historyState.searchedLoginHistory.map((data, index) => (_jsx(Item, { titleRender: (titleObj) => itemTitleRender(titleObj, index), title: data.name, children: _jsx(TMLoginItemTemplate, { data: data, reloadHistoryState: reloadHistoryState, fillLoginForm: fillLoginForm, deleteItemFromLocalStorage: deleteItemFromLocalStorage, setSelectedItems: setSelectedItems, setSearchText: setSearchText }) }, data.id))) }) }));
|
|
110
119
|
};
|
|
111
|
-
return _jsxs(Popup, {
|
|
112
|
-
_jsx(Accordion, { defaultSelectedItems: [], collapsible: true, multiple: false, animationDuration: 300, noDataText: SDKUI_Localizator.NoCredentialsSaved, style: { border: "1px solid #ddd", borderRadius: "6px", boxShadow: "0 2px 6px rgba(0, 0, 0, 0.1)" }, children: loginHistoryData.sort((a, b) => a.name.localeCompare(b.name)).map((data, index) => _jsxs(Item, { title: data.name, children: [itemTemplate(data), " "] }, index)) })] });
|
|
120
|
+
return (_jsxs(Popup, { maxWidth: 600, visible: visible, onHiding: closePopup, title: SDKUI_Localizator.SwitchUser, titleRender: titleRender, hideOnOutsideClick: false, showTitle: true, resizeEnabled: true, dragEnabled: true, showCloseButton: true, children: [_jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", width: "100%", position: "sticky", top: 0, backgroundColor: "#fff", zIndex: 1, padding: "10px 0" }, children: _jsx(TMSearchBar, { maxWidth: "200px", marginLeft: "0px", onSearchValueChanged: (e) => setSearchText(e), searchValue: searchText }) }), renderPopupContent()] }));
|
|
113
121
|
};
|
|
114
122
|
export default TMLoginPopupSaveLoginInfo;
|
|
123
|
+
export const TMLoginItemTemplate = (props) => {
|
|
124
|
+
const { data, fillLoginForm, reloadHistoryState, deleteItemFromLocalStorage, setSelectedItems, setSearchText } = props;
|
|
125
|
+
const [name, setName] = useState(data.name);
|
|
126
|
+
const [error, setError] = useState(false);
|
|
127
|
+
const [validationItems, setValidationItems] = useState([]);
|
|
128
|
+
const nameIsEqualToInitName = data.name.trim().toLowerCase() === name.trim().toLowerCase();
|
|
129
|
+
// Effect to handle validation side-effects (like setting error state)
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const validationsItems = getValidationItems();
|
|
132
|
+
setValidationItems(validationsItems);
|
|
133
|
+
setError(validationsItems.length > 0); // Set error state based on validation result
|
|
134
|
+
}, [name]); // Only re-run when 'name' changes
|
|
135
|
+
// Update the login history item name in local storage if no errors and name is different from the initial name
|
|
136
|
+
const updateNameHandler = () => {
|
|
137
|
+
if (error || nameIsEqualToInitName)
|
|
138
|
+
return;
|
|
139
|
+
const dataToUpdate = { ...data, name };
|
|
140
|
+
LocalStorageService.updateItemByField(LOGIN_HISTORY_KEY, "name", data.name, dataToUpdate);
|
|
141
|
+
reloadHistoryState();
|
|
142
|
+
setSelectedItems([]);
|
|
143
|
+
setSearchText("");
|
|
144
|
+
};
|
|
145
|
+
// Validation logic function
|
|
146
|
+
const getValidationItems = () => {
|
|
147
|
+
const validationsArray = [];
|
|
148
|
+
if (nameIsEqualToInitName)
|
|
149
|
+
return validationsArray;
|
|
150
|
+
if (name.length === 0)
|
|
151
|
+
validationsArray.push(new ValidationItem(ResultTypes.ERROR, 'saveLoginName', SDK_Localizator.RequiredField));
|
|
152
|
+
const findItemByField = LocalStorageService.findItemByField(LOGIN_HISTORY_KEY, "name", name);
|
|
153
|
+
if (findItemByField) {
|
|
154
|
+
validationsArray.push(new ValidationItem(ResultTypes.ERROR, 'saveLoginName', SDKUI_Localizator.DuplicateNameError));
|
|
155
|
+
}
|
|
156
|
+
return validationsArray;
|
|
157
|
+
};
|
|
158
|
+
// Function to calculate luminance from a hex color
|
|
159
|
+
const getLuminance = (color) => {
|
|
160
|
+
// Using slice() instead of substr()
|
|
161
|
+
let r = parseInt(color.slice(1, 3), 16) / 255; // slice(1, 3) extracts the hex digits for red
|
|
162
|
+
let g = parseInt(color.slice(3, 5), 16) / 255; // slice(3, 5) extracts the hex digits for green
|
|
163
|
+
let b = parseInt(color.slice(5, 7), 16) / 255; // slice(5, 7) extracts the hex digits for blue
|
|
164
|
+
// Apply the luminance formula
|
|
165
|
+
const a = [r, g, b].map(c => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
|
|
166
|
+
const luminance = 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
|
|
167
|
+
return luminance;
|
|
168
|
+
};
|
|
169
|
+
// Function to determine text color based on background luminance
|
|
170
|
+
const getTextColor = (backgroundColor) => {
|
|
171
|
+
return getLuminance(backgroundColor) > 0.5 ? 'black' : 'white';
|
|
172
|
+
};
|
|
173
|
+
// Function to generate a hash from a string (text)
|
|
174
|
+
const stringToHash = (str) => {
|
|
175
|
+
let hash = 0;
|
|
176
|
+
for (let i = 0; i < str.length; i++) {
|
|
177
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
178
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
179
|
+
}
|
|
180
|
+
return hash;
|
|
181
|
+
};
|
|
182
|
+
const getRandomColorFromText = (text) => {
|
|
183
|
+
const hash = stringToHash(text);
|
|
184
|
+
// Map the hash to a color, using the hash value for RGB
|
|
185
|
+
const r = (hash & 0xFF0000) >> 16; // Red (8 bits)
|
|
186
|
+
const g = (hash & 0x00FF00) >> 8; // Green (8 bits)
|
|
187
|
+
const b = hash & 0x0000FF; // Blue (8 bits)
|
|
188
|
+
// Ensure the RGB values are within the valid range (0-255)
|
|
189
|
+
return `rgb(${r % 256}, ${g % 256}, ${b % 256})`;
|
|
190
|
+
};
|
|
191
|
+
// Generate a random background color for the circle
|
|
192
|
+
const randomBGColor = getRandomColorFromText(data.name);
|
|
193
|
+
// Determine the text color (black or white) based on background color luminance
|
|
194
|
+
const textColor = getTextColor(randomBGColor);
|
|
195
|
+
return _jsxs("div", { style: { display: 'flex', background: '#fff', boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)', overflow: 'hidden', width: '100%', justifyContent: 'center', alignItems: 'center' }, children: [_jsx(TMTooltip, { content: data.name, children: _jsx("div", { style: { background: randomBGColor, color: textColor, display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '70px', maxHeight: '70px', borderRadius: '50%', fontWeight: 'bold', margin: '20px', textAlign: 'center' }, children: data.name.slice(0, 3).toUpperCase() }) }), _jsxs("div", { style: { padding: '2px', flex: 1 }, children: [_jsx(TMTextBox, { type: "text", label: "Nome per l'accesso", value: name, readOnly: false, buttons: [{ text: `${SDKUI_Localizator.Save}`, icon: _jsx("i", { style: { color: (error || nameIsEqualToInitName) ? "rgb(80,80,80)" : "#28a745", fontSize: 20 }, className: "dx-icon-save" }), onClick: updateNameHandler }], onValueChanged: (e) => setName(e.target.value), validationItems: validationItems }, "name"), (data.endpoint && data.endpoint?.Description) && _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.Endpoint, value: data.endpoint.Description + (' (' + data.endpoint.URL + ')'), readOnly: true, onValueChanged: (e) => setName(e.target.value) }), (data.archive && data.archive?.description) && _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.ArchiveID, value: data.archive.description + (' (' + (data.archive.id ?? '-') + ')'), readOnly: true }), _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.AuthMode, value: data.authenticationMode, readOnly: true }), data.domain.length > 0 && _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.Domain, value: data.domain, readOnly: true }), _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.UserName, value: data.username, readOnly: true }), _jsx(TMTextBox, { type: "text", label: SDKUI_Localizator.CultureID, value: cultureIDsDataSource.find(item => item.value === data.language)?.display ?? '', readOnly: true }), _jsxs("div", { style: { display: 'flex', justifyContent: 'flex-start', alignItems: 'center', marginTop: 10 }, children: [_jsx(TMTooltip, { content: "Login", children: _jsx("div", { onClick: () => { fillLoginForm(data); }, style: { backgroundColor: randomBGColor, color: textColor, display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '50px', maxHeight: '50px', borderRadius: '50%', fontWeight: 'bold', marginRight: '10px', textAlign: 'center' }, children: _jsx("i", { className: "dx-icon-login", style: { fontSize: '1.5em', color: textColor, cursor: 'pointer' } }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Save, children: _jsx("div", { onClick: () => { updateNameHandler(); }, style: { backgroundColor: (error || nameIsEqualToInitName) ? "rgb(80,80,80, 0.5)" : "#28a745", color: textColor, display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '50px', maxHeight: '50px', borderRadius: '50%', fontWeight: 'bold', marginRight: '10px', textAlign: 'center' }, children: _jsx("i", { className: "dx-icon-save", style: { fontSize: '1.5em', color: textColor, cursor: 'pointer' } }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Delete, children: _jsx("div", { onClick: () => { deleteItemFromLocalStorage(data.name); }, style: { backgroundColor: "#ff4d4f", display: 'flex', justifyContent: 'center', alignItems: 'center', width: '15vw', height: '15vw', maxWidth: '50px', maxHeight: '50px', borderRadius: '50%', fontWeight: 'bold', textAlign: 'center' }, children: _jsx("i", { className: "dx-icon-trash", style: { fontSize: '1.5em', color: getTextColor("#ff4d4f"), cursor: 'pointer' } }) }) })] })] })] });
|
|
196
|
+
};
|
|
@@ -225,7 +225,7 @@ export declare class SDKUI_Localizator {
|
|
|
225
225
|
static get ShowSearch(): "Suche anzeigen" | "Show search" | "Mostrar búsqueda" | "Afficher la recherche" | "Mostrar pesquisa" | "Mostra ricerca";
|
|
226
226
|
static get HideSearch(): "Suche ausblenden" | "Hide search" | "Ocultar búsqueda" | "Masquer la recherche" | "Ocultar pesquisa" | "Nascondi ricerca";
|
|
227
227
|
static get NoCredentialsSaved(): "Keine gespeicherten Anmeldedaten" | "No credentials saved" | "No se han guardado credenciales" | "Aucune information d'identification enregistrée" | "Nenhuma credencial salva" | "Nessuna credenziale salvata";
|
|
228
|
-
static get DuplicateNameError(): "Der Name existiert bereits in der Anmeldehistorie.
|
|
228
|
+
static get DuplicateNameError(): "Der Name existiert bereits in der Anmeldehistorie. Bitte wählen Sie einen anderen Namen" | "The name already exists in the login history. Please choose a different nam" | "El nombre ya existe en el historial de inicio de sesión. Por favor, elija un nombre diferente" | "Le nom existe déjà dans l'historique de connexion. Veuillez choisir un autre nom" | "O nome já existe no histórico de login. Por favor, escolha um nome diferente" | "Il nome esiste già nella cronologia di accesso. Si prega di scegliere un nome diverso";
|
|
229
229
|
static get EnterNameForAccess(): "Geben Sie einen Namen für den Zugriff ein" | "Enter a name for access" | "Introduzca un nombre para el acceso" | "Entrez un nom pour l'accès" | "Insira um nome para o acesso" | "Inserire un nome per l'accesso";
|
|
230
230
|
static get RememberCredentials(): "Anmeldedaten merken" | "Remember credentials" | "Recordar credenciales" | "Se souvenir des identifiants" | "Lembrar credenciais" | "Ricorda credenziali";
|
|
231
231
|
static get SwitchUser(): "Benutzer wechseln" | "Switch user" | "Cambiar usuario" | "Changer d'utilisateur" | "Mudar de usuário" | "Cambia utente";
|
|
@@ -2209,17 +2209,17 @@ export class SDKUI_Localizator {
|
|
|
2209
2209
|
static get DuplicateNameError() {
|
|
2210
2210
|
switch (this._cultureID) {
|
|
2211
2211
|
case CultureIDs.De_DE:
|
|
2212
|
-
return "Der Name existiert bereits in der Anmeldehistorie.
|
|
2212
|
+
return "Der Name existiert bereits in der Anmeldehistorie. Bitte wählen Sie einen anderen Namen";
|
|
2213
2213
|
case CultureIDs.En_US:
|
|
2214
|
-
return "The name already exists in the login history.
|
|
2214
|
+
return "The name already exists in the login history. Please choose a different nam";
|
|
2215
2215
|
case CultureIDs.Es_ES:
|
|
2216
|
-
return "El nombre ya existe en el historial de inicio de sesión.
|
|
2216
|
+
return "El nombre ya existe en el historial de inicio de sesión. Por favor, elija un nombre diferente";
|
|
2217
2217
|
case CultureIDs.Fr_FR:
|
|
2218
|
-
return "Le nom existe déjà dans l'historique de connexion.
|
|
2218
|
+
return "Le nom existe déjà dans l'historique de connexion. Veuillez choisir un autre nom";
|
|
2219
2219
|
case CultureIDs.Pt_PT:
|
|
2220
|
-
return "O nome já existe no histórico de login.
|
|
2220
|
+
return "O nome já existe no histórico de login. Por favor, escolha um nome diferente";
|
|
2221
2221
|
default:
|
|
2222
|
-
return "Il nome esiste già nella cronologia di accesso.
|
|
2222
|
+
return "Il nome esiste già nella cronologia di accesso. Si prega di scegliere un nome diverso";
|
|
2223
2223
|
}
|
|
2224
2224
|
}
|
|
2225
2225
|
static get EnterNameForAccess() {
|