@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.
@@ -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;
@@ -17,6 +17,7 @@ export interface ITMLoginHistory {
17
17
  username: string;
18
18
  language: CultureIDs;
19
19
  onBehalfUsername: string;
20
+ preferred: boolean;
20
21
  }
21
22
  export type TMEndpointsType = {
22
23
  Description: string;
@@ -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
- // 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
+ /**
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
- 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 })] });
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 nameIsEqualToInitName = data.name.trim().toLowerCase() === name.trim().toLowerCase();
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 updateNameHandler = () => {
137
- if (error || nameIsEqualToInitName)
231
+ const updateHandler = () => {
232
+ if (error || (isNameMatching && isPreferredMatching))
138
233
  return;
139
- const dataToUpdate = { ...data, name };
140
- LocalStorageService.updateItemByField(LOGIN_HISTORY_KEY, "name", data.name, dataToUpdate);
141
- reloadHistoryState();
142
- setSelectedItems([]);
143
- setSearchText("");
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 (nameIsEqualToInitName)
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 || 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' } }) }) })] })] })] });
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 PreferredAccessAtStartup(): "Bevorzugter Zugriff beim Start" | "Preferred access at startup" | "Acceso preferido al inicio" | "Accès préféré au démarrage" | "Acesso preferido na inicialização" | "Accesso preferito all'avvio";
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 PreferredAccessAtStartup() {
2257
+ static get SetAsFavorite() {
2258
2258
  switch (this._cultureID) {
2259
2259
  case CultureIDs.De_DE:
2260
- return "Bevorzugter Zugriff beim Start";
2260
+ return "Als Favorit festlegen";
2261
2261
  case CultureIDs.En_US:
2262
- return "Preferred access at startup";
2262
+ return "Set as favorite";
2263
2263
  case CultureIDs.Es_ES:
2264
- return "Acceso preferido al inicio";
2264
+ return "Establecer como favorito";
2265
2265
  case CultureIDs.Fr_FR:
2266
- return "Accès préféré au démarrage";
2266
+ return "Définir comme favori";
2267
2267
  case CultureIDs.Pt_PT:
2268
- return "Acesso preferido na inicialização";
2268
+ return "Definir como favorito";
2269
2269
  default:
2270
- return "Accesso preferito all'avvio";
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.7.24",
3
+ "version": "6.7.26",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",