@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 (!data.dcmtArchive?.description?.trim()) {
31
- addError("dcmtArchive", SDKUI_Localizator.RequiredField);
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?.description ?? '', children: _jsx("p", { children: dcmtArchive?.description && dcmtArchive.description.length > 20 ? dcmtArchive.description.substring(0, 20) + '...' : dcmtArchive?.description }) })] })] }), _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 &&
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 for all devices.');
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 for desktop, react-pdf for mobile
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',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev1.26",
3
+ "version": "6.20.0-dev1.28",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",