@topconsultnpm/sdkui-react-beta 6.7.24 → 6.7.26
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/editors/TMMetadataEditor.d.ts +2 -1
- package/lib/components/editors/TMMetadataEditor.js +10 -10
- package/lib/components/forms/TMLoginForm.d.ts +1 -0
- package/lib/components/forms/TMLoginForm.js +24 -1
- package/lib/components/forms/TMLoginPopupSaveLoginInfo.d.ts +4 -0
- package/lib/components/forms/TMLoginPopupSaveLoginInfo.js +123 -16
- package/lib/helper/SDKUI_Localizator.d.ts +4 -1
- package/lib/helper/SDKUI_Localizator.js +55 -7
- package/package.json +1 -1
|
@@ -14,9 +14,10 @@ interface ITMMetadataEditorProps {
|
|
|
14
14
|
validationItems?: ValidationItem[];
|
|
15
15
|
hasLabel?: boolean;
|
|
16
16
|
readOnly?: boolean;
|
|
17
|
+
isModifiedWhen?: boolean;
|
|
17
18
|
onValueChanged?: (value: any) => void;
|
|
18
19
|
onValueChange?: (value: any) => void;
|
|
19
20
|
onCascadeRefreshDynDataLists?: (dynDataListsToBeRefreshed: DynDataListsToBeRefreshed[]) => void;
|
|
20
21
|
}
|
|
21
|
-
declare const TMMetadataEditor: ({ hasLabel, readOnly, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems, disabled, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }: ITMMetadataEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
declare const TMMetadataEditor: ({ isModifiedWhen, hasLabel, readOnly, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems, disabled, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }: ITMMetadataEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
23
|
export default TMMetadataEditor;
|
|
@@ -10,7 +10,7 @@ import TMUserChooser from '../choosers/TMUserChooser';
|
|
|
10
10
|
import TMDateBox from './TMDateBox';
|
|
11
11
|
import TMTextBox from './TMTextBox';
|
|
12
12
|
import { TMMetadataIcon } from '../viewers/TMMidViewer';
|
|
13
|
-
const TMMetadataEditor = ({ hasLabel = false, readOnly, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems = [], disabled = false, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }) => {
|
|
13
|
+
const TMMetadataEditor = ({ isModifiedWhen = false, hasLabel = false, readOnly, tid, mid, value, queryParamsDynDataList, containerElement, allowMultipleSelection, autoFocus, showAsText, showAsNumber, validationItems = [], disabled = false, onValueChanged, onValueChange, onCascadeRefreshDynDataLists }) => {
|
|
14
14
|
const [md, setMd] = useState();
|
|
15
15
|
useEffect(() => {
|
|
16
16
|
DcmtTypeListCacheService.GetAsync(tid).then((dtd) => {
|
|
@@ -19,36 +19,36 @@ const TMMetadataEditor = ({ hasLabel = false, readOnly, tid, mid, value, queryPa
|
|
|
19
19
|
}, [mid]);
|
|
20
20
|
let btnDistincValues = { text: 'Valori distinti', icon: _jsx(IconLayerGroup, { fontSize: 16 }), onClick: () => { ShowAlert({ message: "TODO Valori distinti", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } };
|
|
21
21
|
if (value?.startsWith("{@QueryParam") || value == "{@UserName}" || value == "{@UserID}")
|
|
22
|
-
return _jsx(TMTextBox, { readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', maxLength: md?.length, autoFocus: autoFocus, value: value || '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
22
|
+
return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', maxLength: md?.length, autoFocus: autoFocus, value: value || '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
23
23
|
if (md?.dataDomain == MetadataDataDomains.DynamicDataList)
|
|
24
|
-
return _jsx(TMDynDataListItemChooser, { label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, md: md, tid: tid, buttons: [btnDistincValues], queryParamsDynDataList: queryParamsDynDataList, onCascadeRefreshDynDataLists: onCascadeRefreshDynDataLists, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, allowMultipleSelection: allowMultipleSelection, values: value ? [value] : [], showClearButton: true, onValueChanged: (IDs) => {
|
|
24
|
+
return _jsx(TMDynDataListItemChooser, { isModifiedWhen: isModifiedWhen, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, md: md, tid: tid, buttons: [btnDistincValues], queryParamsDynDataList: queryParamsDynDataList, onCascadeRefreshDynDataLists: onCascadeRefreshDynDataLists, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, allowMultipleSelection: allowMultipleSelection, values: value ? [value] : [], showClearButton: true, onValueChanged: (IDs) => {
|
|
25
25
|
if (!IDs || IDs.length <= 0)
|
|
26
26
|
onValueChanged?.(undefined);
|
|
27
27
|
else
|
|
28
28
|
onValueChanged?.(IDs[0]);
|
|
29
29
|
} });
|
|
30
30
|
if (md?.dataDomain == MetadataDataDomains.DataList)
|
|
31
|
-
return _jsx(TMDataListItemChooser, { label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, dataListId: md.dataListID, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? item : item.slice(1, -1)) ?? [], showClearButton: true, buttons: [btnDistincValues], onValueChanged: (IDs) => {
|
|
31
|
+
return _jsx(TMDataListItemChooser, { isModifiedWhen: isModifiedWhen, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, dataListId: md.dataListID, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? item : item.slice(1, -1)) ?? [], showClearButton: true, buttons: [btnDistincValues], onValueChanged: (IDs) => {
|
|
32
32
|
if (!IDs || IDs.length <= 0)
|
|
33
33
|
onValueChanged?.(undefined);
|
|
34
34
|
else
|
|
35
35
|
onValueChanged?.(IDs.join(","));
|
|
36
36
|
} });
|
|
37
37
|
if (md?.dataDomain == MetadataDataDomains.UserID)
|
|
38
|
-
return _jsx(TMUserChooser, { label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, placeHolder: " ", showClearButton: true, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? Number(item) : Number(item.slice(1, -1))) ?? [], buttons: [btnDistincValues], onValueChanged: (IDs) => {
|
|
38
|
+
return _jsx(TMUserChooser, { isModifiedWhen: isModifiedWhen, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, backgroundColor: TMColors.default_background, placeHolder: " ", showClearButton: true, allowMultipleSelection: allowMultipleSelection, values: value?.split(',').map((item) => !item.startsWith("'") ? Number(item) : Number(item.slice(1, -1))) ?? [], buttons: [btnDistincValues], onValueChanged: (IDs) => {
|
|
39
39
|
if (!IDs || IDs.length <= 0)
|
|
40
40
|
onValueChanged?.(undefined);
|
|
41
41
|
else
|
|
42
42
|
onValueChanged?.(IDs.join(","));
|
|
43
43
|
} });
|
|
44
44
|
if (showAsText)
|
|
45
|
-
return _jsx(TMTextBox, { readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', buttons: [btnDistincValues], showClearButton: true, maxLength: md?.length, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
45
|
+
return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', buttons: [btnDistincValues], showClearButton: true, maxLength: md?.length, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
46
46
|
if (showAsNumber)
|
|
47
|
-
return _jsx(TMTextBox, { readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: true, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
47
|
+
return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: true, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
48
48
|
switch (md?.dataType) {
|
|
49
|
-
case MetadataDataTypes.DateTime: return _jsx(TMDateBox, { readOnly: readOnly, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, label: hasLabel ? md?.nameLoc : undefined, validationItems: validationItems, disabled: disabled, width: '100%', value: value, buttons: [btnDistincValues], showClearButton: true, useDateSerializationFormat: true, containerElement: containerElement, onValueChange: (newValue) => { onValueChange?.(newValue ? newValue.toString() : undefined); onValueChanged?.(newValue ? newValue.toString() : undefined); } });
|
|
50
|
-
case MetadataDataTypes.Number: return _jsx(TMTextBox, { readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', buttons: [btnDistincValues], showClearButton: true, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
51
|
-
default: return _jsx(TMTextBox, { readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: true, buttons: [btnDistincValues], autoFocus: autoFocus, maxLength: md?.length, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
|
|
49
|
+
case MetadataDataTypes.DateTime: return _jsx(TMDateBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, label: hasLabel ? md?.nameLoc : undefined, validationItems: validationItems, disabled: disabled, width: '100%', value: value, buttons: [btnDistincValues], showClearButton: true, useDateSerializationFormat: true, containerElement: containerElement, onValueChange: (newValue) => { onValueChange?.(newValue ? newValue.toString() : undefined); onValueChanged?.(newValue ? newValue.toString() : undefined); } });
|
|
50
|
+
case MetadataDataTypes.Number: return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', buttons: [btnDistincValues], showClearButton: true, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
|
|
51
|
+
default: return _jsx(TMTextBox, { isModifiedWhen: isModifiedWhen, readOnly: readOnly, label: hasLabel ? md?.nameLoc : undefined, icon: hasLabel ? _jsx(TMMetadataIcon, { md: md, tid: tid }) : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: true, buttons: [btnDistincValues], autoFocus: autoFocus, maxLength: md?.length, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
export default TMMetadataEditor;
|
|
@@ -117,6 +117,28 @@ const TMLoginForm = (props) => {
|
|
|
117
117
|
const [saveLoginInfo, setSaveLoginInfo] = useState(false);
|
|
118
118
|
const [saveLoginInfoName, setSaveLoginInfoName] = useState("");
|
|
119
119
|
const [loginHistory, setLoginHistory] = useState(LocalStorageService.getItem(LOGIN_HISTORY_KEY) ?? []);
|
|
120
|
+
const [preferredLoginItem, setPreferredLoginItem] = useState(undefined);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (props.saveLoginHistoryToLocalStorage && loginHistory.length > 0) {
|
|
123
|
+
setPreferredLoginItem(loginHistory.find(item => item.preferred));
|
|
124
|
+
}
|
|
125
|
+
}, []);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (props.saveLoginHistoryToLocalStorage && preferredLoginItem !== undefined) {
|
|
128
|
+
setEndpoint(preferredLoginItem.endpoint);
|
|
129
|
+
setArchive(preferredLoginItem.archive);
|
|
130
|
+
setUsername(preferredLoginItem.username);
|
|
131
|
+
setPassword("");
|
|
132
|
+
setAuthMode(preferredLoginItem.authenticationMode);
|
|
133
|
+
setDomain(preferredLoginItem.domain);
|
|
134
|
+
setDomainArternative(preferredLoginItem.domainAlternative);
|
|
135
|
+
setOnBeHalfUsername(preferredLoginItem.onBehalfUsername);
|
|
136
|
+
setOnBeHalfPassword("");
|
|
137
|
+
if (props.onChangeLanguage) {
|
|
138
|
+
props.onChangeLanguage(preferredLoginItem.language);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, [preferredLoginItem]);
|
|
120
142
|
useEffect(() => {
|
|
121
143
|
let interval;
|
|
122
144
|
if (recoveryPasswordState.step === 2 && wait > 0) {
|
|
@@ -141,7 +163,7 @@ const TMLoginForm = (props) => {
|
|
|
141
163
|
useEffect(() => {
|
|
142
164
|
setEndpoints(props.endpoints);
|
|
143
165
|
if (props.sdInput) {
|
|
144
|
-
if (props.sdInput.userName)
|
|
166
|
+
if (props.sdInput.userName && preferredLoginItem === undefined)
|
|
145
167
|
setUsername(props.sdInput.userName);
|
|
146
168
|
}
|
|
147
169
|
}, []);
|
|
@@ -696,6 +718,7 @@ const TMLoginForm = (props) => {
|
|
|
696
718
|
username: username,
|
|
697
719
|
language: props.cultureID ?? CultureIDs.None,
|
|
698
720
|
onBehalfUsername: onBehalfUsername,
|
|
721
|
+
preferred: false
|
|
699
722
|
};
|
|
700
723
|
updateLoginHistory(loginHistoryNewEntry);
|
|
701
724
|
}
|
|
@@ -25,5 +25,9 @@ interface TMLoginItemTemplateProps {
|
|
|
25
25
|
deleteItemFromLocalStorage: (name: string) => void;
|
|
26
26
|
setSelectedItems: React.Dispatch<React.SetStateAction<ITMLoginHistory[]>>;
|
|
27
27
|
setSearchText: React.Dispatch<React.SetStateAction<string>>;
|
|
28
|
+
historyState: {
|
|
29
|
+
loginHistory: Array<ITMLoginHistory>;
|
|
30
|
+
searchedLoginHistory: Array<ITMLoginHistory>;
|
|
31
|
+
};
|
|
28
32
|
}
|
|
29
33
|
export declare const TMLoginItemTemplate: React.FC<TMLoginItemTemplateProps>;
|
|
@@ -1,6 +1,6 @@
|
|
|
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 } from "devextreme-react";
|
|
3
|
+
import { Accordion, LoadIndicator, Popup, SelectBox } from "devextreme-react";
|
|
4
4
|
import { cultureIDsDataSource, LOGIN_HISTORY_KEY, } from "./TMLoginForm";
|
|
5
5
|
import { LocalStorageService, ResultTypes, SDK_Localizator, ValidationItem } from "@topconsultnpm/sdk-ts-beta";
|
|
6
6
|
import { Item } from "devextreme-react/cjs/accordion";
|
|
@@ -9,6 +9,7 @@ import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from "../base
|
|
|
9
9
|
import TMTooltip from "../base/TMTooltip";
|
|
10
10
|
import TMTextBox from "../editors/TMTextBox";
|
|
11
11
|
import { TMSearchBar } from "../sidebar/TMHeader";
|
|
12
|
+
import TMCheckBox from "../editors/TMCheckBox";
|
|
12
13
|
const TMLoginPopupSaveLoginInfo = (props) => {
|
|
13
14
|
const { setLoginHistory, visible, hidePopup, setEndpoint, setArchive, setAuthMode, setUsername, setPassword, setDomain, setDomainArternative, setOnBeHalfUsername, setOnBeHalfPassword, onChangeLanguage } = props;
|
|
14
15
|
// State to manage loading status
|
|
@@ -17,6 +18,7 @@ const TMLoginPopupSaveLoginInfo = (props) => {
|
|
|
17
18
|
const [searchText, setSearchText] = useState('');
|
|
18
19
|
// State to store selected items of type ITMLoginHistory
|
|
19
20
|
const [selectedItems, setSelectedItems] = useState([]);
|
|
21
|
+
const [selectedImportExportOption, setSelectedImportExportOption] = useState('');
|
|
20
22
|
// Retrieve the login history from local storage, sort by 'name', and return the sorted array (or an empty array if not found)
|
|
21
23
|
const getSortedLoginHistory = () => {
|
|
22
24
|
const loginHistory = LocalStorageService.getItem(LOGIN_HISTORY_KEY);
|
|
@@ -101,11 +103,102 @@ const TMLoginPopupSaveLoginInfo = (props) => {
|
|
|
101
103
|
setSearchText('');
|
|
102
104
|
hidePopup();
|
|
103
105
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Handles the click event for import/export functionality.
|
|
108
|
+
* - For 'import': Opens a file input dialog, reads the selected file,
|
|
109
|
+
* parses the content, and updates the application state.
|
|
110
|
+
* - For 'export': Exports the current login history to a timestamped file.
|
|
111
|
+
*/
|
|
112
|
+
const onImportExportItemClick = (e) => {
|
|
113
|
+
// Inner function to create a file input element: creates a file input element, configures it to accept a specific file type, and triggers a callback when a file is selected.
|
|
114
|
+
const createFileInput = (accept, onChange) => {
|
|
115
|
+
const input = document.createElement("input");
|
|
116
|
+
input.type = "file";
|
|
117
|
+
input.accept = accept;
|
|
118
|
+
input.addEventListener('change', (event) => {
|
|
119
|
+
const file = event.target.files?.[0];
|
|
120
|
+
if (file)
|
|
121
|
+
onChange(file);
|
|
122
|
+
});
|
|
123
|
+
input.click();
|
|
124
|
+
};
|
|
125
|
+
// Inner function to handle file reading and parsing: reads and parses a file's content as JSON, handling success and error cases.
|
|
126
|
+
const handleFileRead = (file, onSuccess, onError) => {
|
|
127
|
+
const reader = new FileReader();
|
|
128
|
+
reader.onload = () => {
|
|
129
|
+
try {
|
|
130
|
+
const fileContent = reader.result;
|
|
131
|
+
const parsedData = JSON.parse(fileContent);
|
|
132
|
+
onSuccess(parsedData);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
onError();
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
reader.readAsText(file);
|
|
139
|
+
};
|
|
140
|
+
// Inner function to generate modified data by appending new IDs and timestamp: generates a modified version of the parsed data by assigning new IDs, and appending timestamped names to each entry.
|
|
141
|
+
const generateModifiedData = (parsedData, existingHistory) => {
|
|
142
|
+
const maxId = Math.max(...existingHistory.map(item => Number(item.id) || 0), 0);
|
|
143
|
+
return parsedData.map((item, index) => {
|
|
144
|
+
const id = maxId + index + 1;
|
|
145
|
+
const currentDate = new Date();
|
|
146
|
+
const formattedDate = currentDate.toISOString().split('T')[0];
|
|
147
|
+
const time = currentDate.toTimeString().split(' ')[0];
|
|
148
|
+
return {
|
|
149
|
+
...item,
|
|
150
|
+
name: `${item.name}_${formattedDate}_${time}`,
|
|
151
|
+
id,
|
|
152
|
+
preferred: false
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
// Inner function to update the application state with new history data: updates the application's history state with the new data and stores it in local storage.
|
|
157
|
+
const updateHistoryState = (newData) => {
|
|
158
|
+
setHistoryState((prevState) => {
|
|
159
|
+
const updatedHistory = {
|
|
160
|
+
loginHistory: [...prevState.loginHistory, ...newData],
|
|
161
|
+
searchedLoginHistory: [...prevState.searchedLoginHistory, ...newData],
|
|
162
|
+
};
|
|
163
|
+
LocalStorageService.setItem(LOGIN_HISTORY_KEY, updatedHistory.loginHistory);
|
|
164
|
+
return { ...prevState, ...updatedHistory };
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
// Inner function to export data as a file with a generated filename: exports the provided data to a file, generating a filename with a timestamp
|
|
168
|
+
const exportToFile = (data, filenamePrefix) => {
|
|
169
|
+
const file = new Blob([JSON.stringify(data, null, 2)], { type: 'text/plain' });
|
|
170
|
+
const element = document.createElement("a");
|
|
171
|
+
const currentDate = new Date();
|
|
172
|
+
const dateString = currentDate.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
173
|
+
const timeString = currentDate.toISOString().split('T')[1].split('.')[0].substring(0, 5); // HH:MM
|
|
174
|
+
element.href = URL.createObjectURL(file);
|
|
175
|
+
element.download = `${filenamePrefix}_${dateString}_${timeString}.txt`;
|
|
176
|
+
document.body.appendChild(element);
|
|
177
|
+
element.click();
|
|
178
|
+
document.body.removeChild(element);
|
|
179
|
+
};
|
|
180
|
+
// Main event handling logic for import/export
|
|
181
|
+
if (!e?.itemData)
|
|
182
|
+
return;
|
|
183
|
+
if (e.itemData.value === 'import') {
|
|
184
|
+
createFileInput(".txt", (file) => {
|
|
185
|
+
handleFileRead(file, (parsedData) => {
|
|
186
|
+
const modifiedData = generateModifiedData(parsedData, historyState.loginHistory);
|
|
187
|
+
updateHistoryState(modifiedData);
|
|
188
|
+
}, () => alert("Error parsing the file content. Ensure the file is in the correct format."));
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
else if (e.itemData.value === 'export') {
|
|
192
|
+
exportToFile(historyState.searchedLoginHistory, "TopMedia_SURFER_LOGIN_HISTORY");
|
|
193
|
+
}
|
|
194
|
+
setSelectedImportExportOption(e.itemData.value);
|
|
195
|
+
};
|
|
196
|
+
// titleRender function returns JSX to render a header with user interface components for import/export and closing the popup
|
|
197
|
+
const titleRender = () => (_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }, children: [_jsx("h3", { children: SDKUI_Localizator.SwitchUser }), _jsxs("div", { style: { marginLeft: 'auto', display: 'flex', alignItems: 'center' }, children: [_jsx(SelectBox, { items: [{ text: SDKUI_Localizator.Import, value: 'import', disabled: false }, { text: SDKUI_Localizator.Export, value: 'export', disabled: historyState.loginHistory.length === 0 }], placeholder: SDKUI_Localizator.ImportExport, onItemClick: onImportExportItemClick, value: selectedImportExportOption, valueExpr: "value", displayExpr: "text" }), _jsx("button", { style: { background: 'none', border: 'none', fontSize: '16px', cursor: 'pointer', marginLeft: '10px' }, onClick: hidePopup, children: _jsx("i", { style: { fontSize: 20 }, className: "dx-icon-remove" }) })] })] }));
|
|
106
198
|
// Render a styled title with its ID and title content, using flex layout
|
|
107
199
|
const itemTitleRender = (titleObj, id) => {
|
|
108
|
-
|
|
200
|
+
const historyItem = historyState.loginHistory.find(item => item.name === titleObj.title);
|
|
201
|
+
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 }), historyItem?.preferred && _jsx(TMTooltip, { position: "right", content: SDKUI_Localizator.SetAsFavorite, children: _jsx("div", { style: { padding: "10px", border: "1px solid #ddd", borderRadius: "10px", }, children: _jsx("i", { className: "dx-icon-favorites" }) }) })] });
|
|
109
202
|
};
|
|
110
203
|
// Conditionally render popup content based on loading state, available login history, or display login items in an accordion
|
|
111
204
|
const renderPopupContent = () => {
|
|
@@ -115,17 +208,19 @@ const TMLoginPopupSaveLoginInfo = (props) => {
|
|
|
115
208
|
if (historyState.searchedLoginHistory.length === 0) {
|
|
116
209
|
return (_jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", textAlign: "center", padding: "20px" }, children: SDKUI_Localizator.NoCredentialsSaved }));
|
|
117
210
|
}
|
|
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))) }) }));
|
|
211
|
+
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, historyState: historyState }) }, data.id))) }) }));
|
|
119
212
|
};
|
|
120
213
|
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()] }));
|
|
121
214
|
};
|
|
122
215
|
export default TMLoginPopupSaveLoginInfo;
|
|
123
216
|
export const TMLoginItemTemplate = (props) => {
|
|
124
|
-
const { data, fillLoginForm, reloadHistoryState, deleteItemFromLocalStorage, setSelectedItems, setSearchText } = props;
|
|
217
|
+
const { data, fillLoginForm, reloadHistoryState, deleteItemFromLocalStorage, setSelectedItems, setSearchText, historyState } = props;
|
|
125
218
|
const [name, setName] = useState(data.name);
|
|
219
|
+
const [preferred, setPreferred] = useState(data.preferred ?? false);
|
|
126
220
|
const [error, setError] = useState(false);
|
|
127
221
|
const [validationItems, setValidationItems] = useState([]);
|
|
128
|
-
const
|
|
222
|
+
const isNameMatching = data.name.trim().toLowerCase() === name.trim().toLowerCase();
|
|
223
|
+
const isPreferredMatching = data.preferred === preferred;
|
|
129
224
|
// Effect to handle validation side-effects (like setting error state)
|
|
130
225
|
useEffect(() => {
|
|
131
226
|
const validationsItems = getValidationItems();
|
|
@@ -133,19 +228,31 @@ export const TMLoginItemTemplate = (props) => {
|
|
|
133
228
|
setError(validationsItems.length > 0); // Set error state based on validation result
|
|
134
229
|
}, [name]); // Only re-run when 'name' changes
|
|
135
230
|
// Update the login history item name in local storage if no errors and name is different from the initial name
|
|
136
|
-
const
|
|
137
|
-
if (error ||
|
|
231
|
+
const updateHandler = () => {
|
|
232
|
+
if (error || (isNameMatching && isPreferredMatching))
|
|
138
233
|
return;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
234
|
+
if (!isNameMatching) {
|
|
235
|
+
const dataToUpdate = { ...data, name };
|
|
236
|
+
LocalStorageService.updateItemByField(LOGIN_HISTORY_KEY, "name", data.name, dataToUpdate);
|
|
237
|
+
reloadHistoryState();
|
|
238
|
+
setSelectedItems([]);
|
|
239
|
+
setSearchText("");
|
|
240
|
+
}
|
|
241
|
+
if (!isPreferredMatching) {
|
|
242
|
+
const historyStateUpdtated = historyState.loginHistory.map(history => {
|
|
243
|
+
if (history.name === data.name) {
|
|
244
|
+
return { ...history, preferred };
|
|
245
|
+
}
|
|
246
|
+
return { ...history, preferred: false };
|
|
247
|
+
});
|
|
248
|
+
LocalStorageService.setItem(LOGIN_HISTORY_KEY, historyStateUpdtated);
|
|
249
|
+
reloadHistoryState();
|
|
250
|
+
}
|
|
144
251
|
};
|
|
145
252
|
// Validation logic function
|
|
146
253
|
const getValidationItems = () => {
|
|
147
254
|
const validationsArray = [];
|
|
148
|
-
if (
|
|
255
|
+
if (isNameMatching)
|
|
149
256
|
return validationsArray;
|
|
150
257
|
if (name.length === 0)
|
|
151
258
|
validationsArray.push(new ValidationItem(ResultTypes.ERROR, 'saveLoginName', SDK_Localizator.RequiredField));
|
|
@@ -192,5 +299,5 @@ export const TMLoginItemTemplate = (props) => {
|
|
|
192
299
|
const randomBGColor = getRandomColorFromText(data.name);
|
|
193
300
|
// Determine the text color (black or white) based on background color luminance
|
|
194
301
|
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: SDKUI_Localizator.NameForAccess, value: name, readOnly: false, buttons: [{ text: `${SDKUI_Localizator.Save}`, icon: _jsx("i", { style: { color: (error ||
|
|
302
|
+
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: SDKUI_Localizator.NameForAccess, value: name, readOnly: false, buttons: [{ text: `${SDKUI_Localizator.Save}`, icon: _jsx("i", { style: { color: (error || (isNameMatching && isPreferredMatching)) ? "rgb(80,80,80)" : "#28a745", fontSize: 20 }, className: "dx-icon-save" }), onClick: updateHandler }], 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 }), _jsx(TMCheckBox, { elementStyle: { marginTop: 10, marginBottom: 10 }, labelPosition: "left", label: SDKUI_Localizator.SetAsFavorite, value: preferred, onValueChanged: (value) => { setPreferred(value); } }), _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: () => { updateHandler(); }, style: { backgroundColor: (error || (isNameMatching && isPreferredMatching)) ? "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
303
|
};
|
|
@@ -228,7 +228,10 @@ export declare class SDKUI_Localizator {
|
|
|
228
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 NameForAccess(): "Name für den Zugang" | "Access name" | "Nombre para el acceso" | "Nom pour l'accès" | "Nome para o acesso" | "Nome per l'accesso";
|
|
231
|
-
static get
|
|
231
|
+
static get SetAsFavorite(): "Als Favorit festlegen" | "Set as favorite" | "Establecer como favorito" | "Définir comme favori" | "Definir como favorito" | "Imposta come preferito";
|
|
232
232
|
static get RememberCredentials(): "Anmeldedaten merken" | "Remember credentials" | "Recordar credenciales" | "Se souvenir des identifiants" | "Lembrar credenciais" | "Ricorda credenziali";
|
|
233
233
|
static get SwitchUser(): "Benutzer wechseln" | "Switch user" | "Cambiar usuario" | "Changer d'utilisateur" | "Mudar de usuário" | "Cambia utente";
|
|
234
|
+
static get ImportExport(): "Importieren/Exportieren" | "Import/Export" | "Importar/Exportar" | "Importer/Exporter" | "Importa/Esporta";
|
|
235
|
+
static get Import(): "Importieren" | "Import" | "Importar" | "Importer" | "Importa";
|
|
236
|
+
static get Export(): "Exportieren" | "Export" | "Exportar" | "Exporter" | "Esporta";
|
|
234
237
|
}
|
|
@@ -2254,20 +2254,20 @@ export class SDKUI_Localizator {
|
|
|
2254
2254
|
return "Nome per l'accesso";
|
|
2255
2255
|
}
|
|
2256
2256
|
}
|
|
2257
|
-
static get
|
|
2257
|
+
static get SetAsFavorite() {
|
|
2258
2258
|
switch (this._cultureID) {
|
|
2259
2259
|
case CultureIDs.De_DE:
|
|
2260
|
-
return "
|
|
2260
|
+
return "Als Favorit festlegen";
|
|
2261
2261
|
case CultureIDs.En_US:
|
|
2262
|
-
return "
|
|
2262
|
+
return "Set as favorite";
|
|
2263
2263
|
case CultureIDs.Es_ES:
|
|
2264
|
-
return "
|
|
2264
|
+
return "Establecer como favorito";
|
|
2265
2265
|
case CultureIDs.Fr_FR:
|
|
2266
|
-
return "
|
|
2266
|
+
return "Définir comme favori";
|
|
2267
2267
|
case CultureIDs.Pt_PT:
|
|
2268
|
-
return "
|
|
2268
|
+
return "Definir como favorito";
|
|
2269
2269
|
default:
|
|
2270
|
-
return "
|
|
2270
|
+
return "Imposta come preferito";
|
|
2271
2271
|
}
|
|
2272
2272
|
}
|
|
2273
2273
|
static get RememberCredentials() {
|
|
@@ -2302,4 +2302,52 @@ export class SDKUI_Localizator {
|
|
|
2302
2302
|
return "Cambia utente";
|
|
2303
2303
|
}
|
|
2304
2304
|
}
|
|
2305
|
+
static get ImportExport() {
|
|
2306
|
+
switch (this._cultureID) {
|
|
2307
|
+
case CultureIDs.De_DE:
|
|
2308
|
+
return "Importieren/Exportieren";
|
|
2309
|
+
case CultureIDs.En_US:
|
|
2310
|
+
return "Import/Export";
|
|
2311
|
+
case CultureIDs.Es_ES:
|
|
2312
|
+
return "Importar/Exportar";
|
|
2313
|
+
case CultureIDs.Fr_FR:
|
|
2314
|
+
return "Importer/Exporter";
|
|
2315
|
+
case CultureIDs.Pt_PT:
|
|
2316
|
+
return "Importar/Exportar";
|
|
2317
|
+
default:
|
|
2318
|
+
return "Importa/Esporta";
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
static get Import() {
|
|
2322
|
+
switch (this._cultureID) {
|
|
2323
|
+
case CultureIDs.De_DE:
|
|
2324
|
+
return "Importieren";
|
|
2325
|
+
case CultureIDs.En_US:
|
|
2326
|
+
return "Import";
|
|
2327
|
+
case CultureIDs.Es_ES:
|
|
2328
|
+
return "Importar";
|
|
2329
|
+
case CultureIDs.Fr_FR:
|
|
2330
|
+
return "Importer";
|
|
2331
|
+
case CultureIDs.Pt_PT:
|
|
2332
|
+
return "Importar";
|
|
2333
|
+
default:
|
|
2334
|
+
return "Importa"; // Italian
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
static get Export() {
|
|
2338
|
+
switch (this._cultureID) {
|
|
2339
|
+
case CultureIDs.De_DE:
|
|
2340
|
+
return "Exportieren";
|
|
2341
|
+
case CultureIDs.En_US:
|
|
2342
|
+
return "Export";
|
|
2343
|
+
case CultureIDs.Es_ES:
|
|
2344
|
+
return "Exportar";
|
|
2345
|
+
case CultureIDs.Fr_FR:
|
|
2346
|
+
return "Exporter";
|
|
2347
|
+
case CultureIDs.Pt_PT:
|
|
2348
|
+
return "Exportar";
|
|
2349
|
+
default:
|
|
2350
|
+
return "Esporta"; // Italian
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2305
2353
|
}
|