@topconsultnpm/sdkui-react 6.20.0-dev1.26 → 6.20.0-dev1.28
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.
|
@@ -3,6 +3,8 @@ import { TMEndpointsType } from './TMLoginForm';
|
|
|
3
3
|
export interface LoginData {
|
|
4
4
|
endpoint: TMEndpointsType;
|
|
5
5
|
dcmtArchive: ArchiveDescriptor;
|
|
6
|
+
manualArchiveID?: string;
|
|
7
|
+
hasArchives?: boolean;
|
|
6
8
|
authenticationMode: AuthenticationModes;
|
|
7
9
|
username?: string;
|
|
8
10
|
password?: string;
|
|
@@ -27,8 +27,13 @@ export class LoginValidator {
|
|
|
27
27
|
if (!data.endpoint?.Description?.trim()) {
|
|
28
28
|
addError("endpoint", SDKUI_Localizator.RequiredField);
|
|
29
29
|
}
|
|
30
|
-
if (
|
|
31
|
-
|
|
30
|
+
if (data.hasArchives) {
|
|
31
|
+
if (!data.dcmtArchive?.description?.trim()) {
|
|
32
|
+
addError("dcmtArchive", SDKUI_Localizator.RequiredField);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else if (!data.manualArchiveID?.trim()) {
|
|
36
|
+
addError("manualArchiveID", SDKUI_Localizator.RequiredField);
|
|
32
37
|
}
|
|
33
38
|
if (!data.authenticationMode || data.authenticationMode === AuthenticationModes.None) {
|
|
34
39
|
addError("authenticationMode", SDKUI_Localizator.RequiredField);
|
|
@@ -113,6 +113,7 @@ const TMLoginForm = (props) => {
|
|
|
113
113
|
const [showCultureIDs, setShowCultureIDs] = useState(false);
|
|
114
114
|
const [dcmtArchives, setDcmtArchives] = useState([]);
|
|
115
115
|
const [dcmtArchive, setDcmtArchive] = useState();
|
|
116
|
+
const [manualArchiveID, setManualArchiveID] = useState('');
|
|
116
117
|
const [authMode, setAuthMode] = useState(AuthenticationModes.TopMedia);
|
|
117
118
|
const [username, setUsername] = useState('SysAdmin');
|
|
118
119
|
const [password, setPassword] = useState('');
|
|
@@ -133,6 +134,8 @@ const TMLoginForm = (props) => {
|
|
|
133
134
|
authenticationMode: authMode,
|
|
134
135
|
cultureID: props.cultureID ?? CultureIDs.It_IT,
|
|
135
136
|
dcmtArchive: dcmtArchive,
|
|
137
|
+
manualArchiveID: manualArchiveID,
|
|
138
|
+
hasArchives: dcmtArchives.length > 0,
|
|
136
139
|
endpoint: endpoint,
|
|
137
140
|
authDomain: authDomain,
|
|
138
141
|
authDomainOnBehalfOf: authDomain,
|
|
@@ -144,7 +147,7 @@ const TMLoginForm = (props) => {
|
|
|
144
147
|
username: username,
|
|
145
148
|
usernameOnBehalfOf: usernameOnBehalf
|
|
146
149
|
};
|
|
147
|
-
}, [authMode, props.cultureID, dcmtArchive, endpoint, authDomain, otpCode, password, passwordOnBehalf, saveLoginName, saveLoginEnable, username, usernameOnBehalf]);
|
|
150
|
+
}, [authMode, props.cultureID, dcmtArchive, manualArchiveID, dcmtArchives.length, endpoint, authDomain, otpCode, password, passwordOnBehalf, saveLoginName, saveLoginEnable, username, usernameOnBehalf]);
|
|
148
151
|
const inputRefs = useMemo(() => {
|
|
149
152
|
switch (authMode) {
|
|
150
153
|
case AuthenticationModes.TopMedia:
|
|
@@ -304,7 +307,7 @@ const TMLoginForm = (props) => {
|
|
|
304
307
|
}, []);
|
|
305
308
|
const disableContinueBtn = useMemo(() => {
|
|
306
309
|
switch (loginStep) {
|
|
307
|
-
case 1: return fieldValidations('endpoint').length > 0 || fieldValidations('dcmtArchive').length > 0;
|
|
310
|
+
case 1: return fieldValidations('endpoint').length > 0 || fieldValidations('dcmtArchive').length > 0 || fieldValidations('manualArchiveID').length > 0;
|
|
308
311
|
case 2: return fieldValidations('authenticationMode').length > 0 || fieldValidations('username').length > 0 || fieldValidations('password').length > 0;
|
|
309
312
|
default: return false;
|
|
310
313
|
}
|
|
@@ -323,8 +326,13 @@ const TMLoginForm = (props) => {
|
|
|
323
326
|
return tmSession;
|
|
324
327
|
}, [endpoint, username, dcmtArchive]);
|
|
325
328
|
const nextStepHandler = async () => {
|
|
326
|
-
if (!endpoint || !dcmtArchive)
|
|
329
|
+
if (!endpoint || (!dcmtArchive && !manualArchiveID))
|
|
327
330
|
return;
|
|
331
|
+
if (loginStep === 1 && !dcmtArchive && manualArchiveID) {
|
|
332
|
+
const isValid = await validateManualArchiveAsync();
|
|
333
|
+
if (!isValid)
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
328
336
|
if (loginStep === 1) {
|
|
329
337
|
setLoginStep(2);
|
|
330
338
|
}
|
|
@@ -351,6 +359,23 @@ const TMLoginForm = (props) => {
|
|
|
351
359
|
return;
|
|
352
360
|
setLoginStep(prev => prev - 1);
|
|
353
361
|
}, [loginStep]);
|
|
362
|
+
const validateManualArchiveAsync = async () => {
|
|
363
|
+
if (!tmSession || !manualArchiveID)
|
|
364
|
+
return false;
|
|
365
|
+
try {
|
|
366
|
+
TMSpinner.show({ description: '' });
|
|
367
|
+
const archiveEngine = tmSession.NewArchiveEngine();
|
|
368
|
+
await archiveEngine.RetrieveAsync(manualArchiveID);
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
TMExceptionBoxManager.show({ exception: e });
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
TMSpinner.hide();
|
|
377
|
+
}
|
|
378
|
+
};
|
|
354
379
|
const getArchivesAsync = async () => {
|
|
355
380
|
if (!tmSession)
|
|
356
381
|
return;
|
|
@@ -394,7 +419,7 @@ const TMLoginForm = (props) => {
|
|
|
394
419
|
const sdInput = {
|
|
395
420
|
authenticationMode: authMode,
|
|
396
421
|
appModuleID: props.appModule,
|
|
397
|
-
archiveID: dcmtArchive?.id,
|
|
422
|
+
archiveID: dcmtArchive?.id ?? (dcmtArchives.length === 0 && manualArchiveID ? manualArchiveID : undefined),
|
|
398
423
|
description: dcmtArchive?.description,
|
|
399
424
|
userName: username,
|
|
400
425
|
password: password,
|
|
@@ -596,7 +621,7 @@ const TMLoginForm = (props) => {
|
|
|
596
621
|
}
|
|
597
622
|
}, [SDK_Globals.appModule]);
|
|
598
623
|
return (_jsxs(StyledWrapper, { children: [!isMobile && _jsxs(StyledVersionContainer, { children: [_jsxs(StyledVersion, { children: [_jsxs(StyledVersionName, { children: [_jsx("span", { style: { color: TMColors.primary }, children: "\u25CF" }), SDK_Globals.appModule] }), _jsxs("p", { children: ["v.", SDK_Globals.appVersion] })] }), _jsxs(StyledVersion, { children: [_jsxs(StyledVersionName, { children: [_jsx("span", { style: { color: TMColors.tertiary }, children: "\u25CF" }), "SDKUI"] }), _jsxs("p", { children: ["v.", SDK_Globals.sdkuiVersion] })] }), _jsxs(StyledVersion, { children: [_jsxs(StyledVersionName, { children: [_jsx("span", { style: { color: TMColors.error }, children: "\u25CF" }), "SDK"] }), _jsxs("p", { children: ["v.", SDK_Globals.sdkVersion] })] })] }), _jsxs(StyledLoginContainer, { "$isMobile": isMobile, children: [_jsxs(StyledLeftSection, { "$isMobile": isMobile, "$isConnector": props.isConnector ?? false, children: [isMobile && _jsxs(StyledTopBar, { children: [_jsx(StyledTitle, { children: SDKUI_Localizator.WelcomeTo.replaceParams('') + ' ' + welcomeAppNameHeader + ' ' + 'v.' + SDK_Globals.appVersion }), _jsx(StyledMobileVersionIcon, { onClick: showVersionPopup, children: _jsx(IconInfo, { fontSize: 20, color: TMColors.primary }) })] }), _jsx(StyledOverlay, { "$isMobile": isMobile, children: _jsx(StyledCustomLogo, { style: { backgroundImage: `url(${showDefaultLogo ? 'logo-default.svg' : 'logo-custom.svg'})` } }) }), (windowHeight === WindowHeight.LARGE || !isMobile) && _jsxs(StyledPoweredByContainer, { "$isMobile": isMobile, children: [" ", showDefaultLogo ? 'Powered by TopConsult' : _jsx("img", { src: "/logo-default.svg", alt: "Logo", width: isMobile ? 50 : 100 }), " "] })] }), _jsxs(StyledRightSection, { "$isMobile": isMobile, children: [((((getDeviceType() === 'desktop' || isDesktop || isTablet) && windowHeight !== WindowHeight.SMALL)) && !isMobile) && _jsxs(StyledLogoContainer, { "$isMobile": isMobile, children: [_jsx(StyledWelcomeText, { children: SDKUI_Localizator.WelcomeTo.replaceParams('') }), _jsx(StyledLogo, { children: _jsx("img", { src: six, alt: "six", height: 50 }) }), _jsx(StyledWelcomeText, { children: welcomeAppName })] }), _jsxs(StyledToolbarContainer, { children: [_jsx(StyledLanguageChooser, { onClick: () => setShowCultureIDs(true), children: _jsx(TMTooltip, { content: SDKUI_Localizator.CultureID, children: _jsx("img", { src: getCultureIDImg(), alt: "Lang", width: 25, height: 25 }) }) }), loginStep !== 3 && _jsx(TMButton, { btnStyle: "icon", onClick: () => setShowRapidAccess(true), icon: _jsx(IconFastAccess, { fontSize: 20 }), caption: LOGINLocalizator.QuickAccess }), showPasswordOperations && _jsx(TMButton, { disabled: disablePasswordOperations, btnStyle: "icon", onClick: () => setShowChangePassword(true), icon: _jsx(IconPasswordOutline, { fontSize: 19 }), caption: SDKUI_Localizator.ChangePassword })] }), _jsxs(StyledFormContainer, { "$isMobile": isMobile, "$windowHeight": windowHeight, children: [loginStep === 1 &&
|
|
599
|
-
_jsxs(StyledStepContainer, { "$deviceType": deviceType, children: [_jsx(Chooser, { isDropDown: isDesktop, dataSource: props.endpoints, value: 'Description', columns: accessPointChooserColumns, additionalIcons: accessPointAdditionalIcons, icon: _jsx(IconAccessPoint, {}), label: SDKUI_Localizator.Endpoint, onSelectionChanged: (ep) => { setEndpoint(ep); setDcmtArchive(undefined); }, validationItems: fieldValidations('endpoint'), selectedRow: endpoint ?? undefined }), _jsx(Chooser, { isDropDown: isDesktop, dataSource: dcmtArchives, value: 'description', columns: dcmtArchiveChooserColumns, icon: _jsx(IconArchiveDoc, {}), label: SDKUI_Localizator.ArchiveID, onSelectionChanged: (arch) => setDcmtArchive(arch), validationItems: fieldValidations('dcmtArchive'), disabled: !endpoint, selectedRow: dcmtArchive ?? undefined })] }), loginStep === 2 &&
|
|
624
|
+
_jsxs(StyledStepContainer, { "$deviceType": deviceType, children: [_jsx(Chooser, { isDropDown: isDesktop, dataSource: props.endpoints, value: 'Description', columns: accessPointChooserColumns, additionalIcons: accessPointAdditionalIcons, icon: _jsx(IconAccessPoint, {}), label: SDKUI_Localizator.Endpoint, onSelectionChanged: (ep) => { setEndpoint(ep); setDcmtArchive(undefined); }, validationItems: fieldValidations('endpoint'), selectedRow: endpoint ?? undefined }), dcmtArchives.length > 0 ? (_jsx(Chooser, { isDropDown: isDesktop, dataSource: dcmtArchives, value: 'description', columns: dcmtArchiveChooserColumns, icon: _jsx(IconArchiveDoc, {}), label: SDKUI_Localizator.ArchiveID, onSelectionChanged: (arch) => setDcmtArchive(arch), validationItems: fieldValidations('dcmtArchive'), disabled: !endpoint, selectedRow: dcmtArchive ?? undefined })) : (_jsx(TextBox, { type: "text", icon: _jsx(IconArchiveDoc, {}), label: SDKUI_Localizator.ArchiveID, value: manualArchiveID, onValueChanged: (value) => setManualArchiveID(value), validationItems: fieldValidations('manualArchiveID'), disabled: !endpoint, placeHolder: 'Inserisci archivio' }))] }), loginStep === 2 &&
|
|
600
625
|
_jsxs(_Fragment, { children: [_jsxs(StyledSummaryContainer, { style: {
|
|
601
626
|
display: 'flex',
|
|
602
627
|
justifyContent: 'center',
|
|
@@ -606,7 +631,7 @@ const TMLoginForm = (props) => {
|
|
|
606
631
|
marginBottom: windowHeight === WindowHeight.SMALL ? '30px' : '25px',
|
|
607
632
|
width: '100%',
|
|
608
633
|
minHeight: '15px'
|
|
609
|
-
}, children: [_jsxs(StyledDescription, { children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Endpoint, children: _jsx(IconAccessPoint, { color: TMColors.primary, fontSize: 16 }) }), _jsx(TMTooltip, { content: endpoint?.Description ?? '', children: _jsx("p", { children: endpoint?.Description && endpoint.Description.length > 20 ? endpoint.Description.substring(0, 20) + '...' : endpoint?.Description }) })] }), _jsxs(StyledDescription, { children: [_jsx(TMTooltip, { content: SDKUI_Localizator.ArchiveID, children: _jsx(IconArchiveDoc, { color: TMColors.primary, fontSize: 16 }) }), _jsx(TMTooltip, { content: dcmtArchive
|
|
634
|
+
}, children: [_jsxs(StyledDescription, { children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Endpoint, children: _jsx(IconAccessPoint, { color: TMColors.primary, fontSize: 16 }) }), _jsx(TMTooltip, { content: endpoint?.Description ?? '', children: _jsx("p", { children: endpoint?.Description && endpoint.Description.length > 20 ? endpoint.Description.substring(0, 20) + '...' : endpoint?.Description }) })] }), _jsxs(StyledDescription, { children: [_jsx(TMTooltip, { content: SDKUI_Localizator.ArchiveID, children: _jsx(IconArchiveDoc, { color: TMColors.primary, fontSize: 16 }) }), _jsx(TMTooltip, { content: dcmtArchive ? (dcmtArchive.description ?? '') : manualArchiveID, children: _jsx(StyledArchiveText, { children: dcmtArchive ? (dcmtArchive.description ?? '') : manualArchiveID }) })] })] }), _jsxs(StyledStepContainer, { "$windowHeight": windowHeight, "$deviceType": deviceType, children: [_jsx(SelectBox, { value: authMode, options: authModeOptions, onValueChanged: (value) => setAuthMode(value), validationItems: fieldValidations('authenticationMode'), icon: _jsx(IconLogin, {}), label: SDKUI_Localizator.AuthMode }), _jsxs(StyledCredentialWrapper, { children: [authMode === AuthenticationModes.WindowsThroughTopMedia && _jsx(TextBox, { ref: authDomainRef, value: authDomain, onValueChanged: (e) => setAuthDomain(e), validationItems: fieldValidations('authDomain'), type: "text", icon: _jsx(IconWeb, {}), label: SDKUI_Localizator.Domain }), authMode !== AuthenticationModes.MSAzure && _jsx(CeredentialContainer, { isMobile: isMobile, ref: usernameRef, secondaryRef: passwordRef, usernameValidator: fieldValidations('username'), passwordValidator: fieldValidations('password'), authMode: authMode, username: username, password: password, onUsernameChanged: (un) => setUsername(un), onPasswordChanged: (ps) => setPassword(ps) }), authMode === AuthenticationModes.TopMediaOnBehalfOf &&
|
|
610
635
|
_jsxs(StyledCredentialWrapper, { children: [_jsx(TextBox, { value: authDomain, ref: authDomainRef, onValueChanged: (e) => setAuthDomain(e), validationItems: fieldValidations('authDomain'), type: "text", icon: _jsx(IconWeb, {}), label: SDKUI_Localizator.Domain }), _jsx(CeredentialContainer, { isMobile: isMobile, ref: usernameOnBehalfOfRef, secondaryRef: passwordOnBehalfOfRRef, usernameValidator: fieldValidations('usernameOnBehalfOf'), passwordValidator: fieldValidations('passwordOnBehalfOf'), authMode: AuthenticationModes.TopMediaOnBehalfOf, username: usernameOnBehalf, password: passwordOnBehalf, onUsernameChanged: (un) => setUsernameOnBehalf(un), onPasswordChanged: (ps) => setPasswordOnBehalf(ps) })] })] }), authMode !== AuthenticationModes.TopMediaWithMFA &&
|
|
611
636
|
_jsx(RapidAccessContainer, { isSaveEnable: saveLoginEnable, name: saveLoginName, nameValidationItems: fieldValidations('rapidAccessName'), onEnableSaveChange: () => setSaveLoginEnable(!saveLoginEnable), onNameChange: (name) => setSaveLoginName(name) })] })] }), loginStep === 3 &&
|
|
612
637
|
_jsxs(StyledStepThreeContainer, { "$isMobile": isMobile, children: [_jsx(OTPReader, { isMobile: isMobile, digits: otpCode, onChange: handleDigitChange, onFullChange: handleFullChange, text: _jsxs("div", { children: [" ", LOGINLocalizator.EnterOtpInstructions, " "] }), header: '', additionalButtons: [
|
|
@@ -705,6 +730,7 @@ const StyledLogo = styled.div ` display: flex; gap: 5px; align-items: center; `;
|
|
|
705
730
|
const StyledFormContainer = styled.div ` display: flex; flex-direction: column; padding: ${props => getPadding(props.$windowHeight, props.$isMobile)} ; align-items: center; justify-content: center; gap: 10px; width: 100%; height: fit-content; max-height: calc(100% - 100px); margin-top : ${props => !props.$isMobile && props.$windowHeight === WindowHeight.MEDIUM ? '70px' : '0'} ; `;
|
|
706
731
|
const StyledButtonContainer = styled.div ` display: flex; align-items: center; justify-content: center; padding: ${props => props.$windowHeight !== WindowHeight.SMALL ? '10px' : '0'}; width: 100%; margin-top: ${props => props.$windowHeight !== WindowHeight.SMALL ? '10px' : '0'}; `;
|
|
707
732
|
const StyledDescription = styled.div ` display: flex; align-items: center; gap: 2px; `;
|
|
733
|
+
const StyledArchiveText = styled.p ` max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `;
|
|
708
734
|
const StyledRapidLoginSave = styled.div ` display: flex; flex-direction: column; width: 100%; gap: 2px; `;
|
|
709
735
|
const StyledForgetPassword = styled.div ` position: absolute; bottom: ${props => props.$isMobile ? '15px' : '25px'}; left: 50%; transform: translateX(-50%); font-size: 0.8rem; `;
|
|
710
736
|
const StyledBackButton = styled.div ` position: absolute; top: 20px; left: 20px; `;
|
|
@@ -9,15 +9,19 @@ import { TMColors } from "../utils/theme";
|
|
|
9
9
|
let pdfjs;
|
|
10
10
|
let Document;
|
|
11
11
|
let Page;
|
|
12
|
+
let isReactPdfAvailable = false;
|
|
12
13
|
try {
|
|
13
14
|
const reactPdf = require('react-pdf');
|
|
14
15
|
pdfjs = reactPdf.pdfjs;
|
|
15
16
|
Document = reactPdf.Document;
|
|
16
17
|
Page = reactPdf.Page;
|
|
18
|
+
// Configura il worker PDF.js PRIMA del rendering
|
|
19
|
+
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
20
|
+
isReactPdfAvailable = true;
|
|
17
21
|
}
|
|
18
22
|
catch (error) {
|
|
19
|
-
// react-pdf not available
|
|
20
|
-
// console.warn('react-pdf is not installed. TMPdfViewer will use iframe fallback
|
|
23
|
+
// react-pdf not available - will use iframe fallback
|
|
24
|
+
// console.warn('react-pdf is not installed. TMPdfViewer will use iframe fallback.');
|
|
21
25
|
}
|
|
22
26
|
const PDFViewerContainer = styled.div `
|
|
23
27
|
width: 100%;
|
|
@@ -76,16 +80,6 @@ const TMPdfViewer = (props) => {
|
|
|
76
80
|
(window.matchMedia?.('(hover: none) and (pointer: coarse)').matches ?? false) ||
|
|
77
81
|
// Touch-capable devices excluding desktop OS
|
|
78
82
|
(navigator.maxTouchPoints > 1 && !/Win|Mac|Linux x86_64/i.test(userAgent));
|
|
79
|
-
// Configura il worker PDF.js solo per mobile (react-pdf)
|
|
80
|
-
if (isMobileDevice && !pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
81
|
-
try {
|
|
82
|
-
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
console.warn('Worker PDF.js locale non disponibile, uso CDN fallback');
|
|
86
|
-
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
83
|
setIsMobile(isMobileDevice);
|
|
90
84
|
};
|
|
91
85
|
checkIsMobile();
|
|
@@ -139,8 +133,8 @@ const TMPdfViewer = (props) => {
|
|
|
139
133
|
observerRef.current?.disconnect();
|
|
140
134
|
};
|
|
141
135
|
}, [pageObserverCallback]);
|
|
142
|
-
// Use iframe
|
|
143
|
-
if (!isMobile && pdfUrl) {
|
|
136
|
+
// Use iframe se react-pdf non è disponibile O se è desktop
|
|
137
|
+
if (!isReactPdfAvailable || (!isMobile && pdfUrl)) {
|
|
144
138
|
return (_jsx(PDFViewerContainer, { children: _jsx("iframe", { src: `${pdfUrl}#${enableFitToWidth ? 'view=FitH&' : ''}scrollbar=1`, title: title, style: {
|
|
145
139
|
width: '100%',
|
|
146
140
|
height: '100%',
|
|
@@ -149,6 +143,7 @@ const TMPdfViewer = (props) => {
|
|
|
149
143
|
pointerEvents: isResizingActive === true ? "none" : "auto"
|
|
150
144
|
} }, pdfUrl) }));
|
|
151
145
|
}
|
|
146
|
+
// Usa react-pdf solo per mobile e solo se disponibile
|
|
152
147
|
return _jsxs(PDFViewerContainer, { children: [loadedPagesNumber === 0 && totalPagesNumber > 0 && _jsx(LoadingOverlay, { children: _jsxs("div", { style: {
|
|
153
148
|
display: 'flex',
|
|
154
149
|
justifyContent: 'center',
|