From c7acc74bf1c6e62c42472ce8457d053428e5871e Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Mon, 9 Oct 2023 19:18:36 -0400 Subject: [PATCH 01/11] add initial popup login from sharepoint login page --- .../SendToLaserficheLoginComponent.tsx | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index f53f52e..31b0558 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -59,6 +59,10 @@ export default function SendToLaserficheLoginComponent( } const loginText: JSX.Element | undefined = getLoginText(); + const autoLoginCompleted: () => Promise = async () => { + window.close(); + }; + const loginCompleted: () => Promise = async () => { setLoggedIn(true); if (spFileMetadata) { @@ -88,14 +92,34 @@ export default function SendToLaserficheLoginComponent( SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); await SPComponentLoader.loadScript(ZONE_JS_URL); await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); - loginComponent.current.addEventListener( - 'loginCompleted', - loginCompleted - ); - loginComponent.current.addEventListener( - 'logoutCompleted', - logoutCompleted - ); + + if (window.location.href.includes('autologin')) { + if (loginComponent.current.state !== LoginState.LoggedIn) { + if (!document.referrer.includes('accounts.')) { + loginComponent.current.initLoginFlowAsync(); + } else { + window.close(); + } + } else { + const loginbutton = loginComponent.current.querySelector( + '.login-button' + ) as HTMLButtonElement; + loginbutton.click(); + } + loginComponent.current.addEventListener( + 'loginCompleted', + autoLoginCompleted + ); + } else { + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompleted + ); + loginComponent.current.addEventListener( + 'logoutCompleted', + logoutCompleted + ); + } const isLoggedIn: boolean = loginComponent.current.state === LoginState.LoggedIn; @@ -191,6 +215,15 @@ export default function SendToLaserficheLoginComponent( Navigation.navigate(path, true); } + function clickLogin(): void { + const url = + props.context.pageContext.web.absoluteUrl + + '/SitePages/LaserficheSignIn.aspx?autologin'; + window.open(url, '_blank', 'popup'); + } + + let redirectURL = + window.location.origin + window.location.pathname + '?autologin'; return (
@@ -204,12 +237,16 @@ export default function SendToLaserficheLoginComponent(
{loginText}
@@ -117,7 +124,11 @@ export default function LaserficheAdminConfiguration( redirect_behavior='Replace' client_id={clientId} ref={loginComponent} + hidden /> +
Date: Tue, 10 Oct 2023 12:01:30 -0400 Subject: [PATCH 03/11] add styles to mock login buttons, clear page while waiting for login button to be clicked --- .../LaserficheRepositoryAccessWebPart.tsx | 7 ++- .../LaserficheAdminConfiguration.tsx | 53 +++++++++++-------- .../SendToLaserficheLoginComponent.tsx | 8 ++- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index b3272e0..99931ee 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -129,7 +129,12 @@ export default function LaserficheRepositoryAccessWebPart( ref={loginComponent} hidden /> - diff --git a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx index 5c33bb3..8e62502 100644 --- a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx @@ -9,7 +9,13 @@ import ManageConfigurationsPage from './ManageConfigurationsPage/ManageConfigura import ManageMappingsPage from './ManageMappingsPage/ManageMappingsPage'; import EditManageConfiguration from './EditManageConfiguration/EditManageConfiguration'; import AddNewManageConfiguration from './AddNewManageConfiguration/AddNewManageConfiguration'; -import { clientId, LF_INDIGO_PINK_CSS_URL, LF_MS_OFFICE_LITE_CSS_URL, LF_UI_COMPONENTS_URL, ZONE_JS_URL } from '../../constants'; +import { + clientId, + LF_INDIGO_PINK_CSS_URL, + LF_MS_OFFICE_LITE_CSS_URL, + LF_UI_COMPONENTS_URL, + ZONE_JS_URL, +} from '../../constants'; import { NgElement, WithProperties } from '@angular/elements'; import { LfLoginComponent } from '@laserfiche/types-lf-ui-components'; import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; @@ -19,7 +25,8 @@ import { getRegion } from '../../../Utils/Funcs'; import styles from './LaserficheAdminConfiguration.module.scss'; import { SPPermission } from '@microsoft/sp-page-context'; -const YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN = 'You do not have the necessary rights to view or edit the Laserfiche SharePoint Integration configuration. Please contact your administrator for help.'; +const YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN = + 'You do not have the necessary rights to view or edit the Laserfiche SharePoint Integration configuration. Please contact your administrator for help.'; export default function LaserficheAdminConfiguration( props: ILaserficheAdminConfigurationProps @@ -66,18 +73,10 @@ export default function LaserficheAdminConfiguration( React.useEffect(() => { const initializeComponentAsync: () => Promise = async () => { try { - SPComponentLoader.loadCss( - LF_INDIGO_PINK_CSS_URL - ); - SPComponentLoader.loadCss( - LF_MS_OFFICE_LITE_CSS_URL - ); - await SPComponentLoader.loadScript( - ZONE_JS_URL - ); - await SPComponentLoader.loadScript( - LF_UI_COMPONENTS_URL - ); + SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); + SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); + await SPComponentLoader.loadScript(ZONE_JS_URL); + await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); const loginCompleted: () => Promise = async () => { await getAndInitializeRepositoryClientAndServicesAsync(); setLoggedIn(true); @@ -85,8 +84,11 @@ export default function LaserficheAdminConfiguration( const logoutCompleted: () => Promise = async () => { setLoggedIn(false); }; - - loginComponent.current.addEventListener('loginCompleted', loginCompleted); + + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompleted + ); loginComponent.current.addEventListener( 'logoutCompleted', logoutCompleted @@ -95,8 +97,7 @@ export default function LaserficheAdminConfiguration( await getAndInitializeRepositoryClientAndServicesAsync(); setLoggedIn(true); } - } - catch (err) { + } catch (err) { console.error(`Error initializing configuration page: ${err}`); } }; @@ -126,7 +127,12 @@ export default function LaserficheAdminConfiguration( ref={loginComponent} hidden /> - @@ -188,8 +194,13 @@ export default function LaserficheAdminConfiguration( )} - {!isAdmin() && - {YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN}} + {!isAdmin() && ( + + + {YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN} + + + )}
diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index 31b0558..c9c87ba 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -94,6 +94,7 @@ export default function SendToLaserficheLoginComponent( await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); if (window.location.href.includes('autologin')) { + document.body.style.display = 'none'; if (loginComponent.current.state !== LoginState.LoggedIn) { if (!document.referrer.includes('accounts.')) { loginComponent.current.initLoginFlowAsync(); @@ -244,7 +245,12 @@ export default function SendToLaserficheLoginComponent( ref={loginComponent} hidden /> -
From f0c2dd06ecf116d5fe42a1e2e0f6bbd347efec41 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 10 Oct 2023 12:11:43 -0400 Subject: [PATCH 04/11] fix lint --- .../components/SendToLaserficheLoginComponent.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index c9c87ba..5620305 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -97,7 +97,7 @@ export default function SendToLaserficheLoginComponent( document.body.style.display = 'none'; if (loginComponent.current.state !== LoginState.LoggedIn) { if (!document.referrer.includes('accounts.')) { - loginComponent.current.initLoginFlowAsync(); + await loginComponent.current.initLoginFlowAsync(); } else { window.close(); } @@ -223,8 +223,9 @@ export default function SendToLaserficheLoginComponent( window.open(url, '_blank', 'popup'); } - let redirectURL = + const redirectURL = window.location.origin + window.location.pathname + '?autologin'; + return (
From ab6715eb41e4b805c467aa67c301e42ee0f5f6f5 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Fri, 13 Oct 2023 16:17:24 -0400 Subject: [PATCH 05/11] Microsoft and QA mob fixes - fix popup login - Page --> Pages - don't clear number metadata - strings for data type mismatch should match Laserfiche (i.e. string --> text) - user notification of automatic rename when creating or importing docs - don't restrict filename, / is the only thing not permitted --- src/Utils/Funcs.ts | 19 +++ .../savetoLaserfiche/CommonDialogs.tsx | 76 +++++++++ .../GetDocumentDataDialog.tsx | 31 +--- .../SaveDocumentToLaserfiche.tsx | 81 +++------ .../SaveToLaserficheDialog.tsx | 100 ++++++++++- .../SendToLaserFiche.module.scss | 6 + .../LaserficheRepositoryAccessWebPart.tsx | 20 ++- .../components/RepositoryViewWebPart.tsx | 160 +++++++++++------- src/webparts/constants.ts | 8 +- .../LaserficheAdminConfiguration.tsx | 20 ++- .../ProfileConfigurationComponents.tsx | 11 +- .../SendToLaserficheLoginComponent.tsx | 129 ++++++++++---- 12 files changed, 469 insertions(+), 192 deletions(-) diff --git a/src/Utils/Funcs.ts b/src/Utils/Funcs.ts index 774c087..1e51652 100644 --- a/src/Utils/Funcs.ts +++ b/src/Utils/Funcs.ts @@ -1,4 +1,5 @@ import { UrlUtils } from '@laserfiche/lf-js-utils'; +import { WFieldType } from '@laserfiche/lf-repository-api-client'; import { BaseComponentContext } from '@microsoft/sp-component-base'; import { SPDEVMODE_LOCAL_STORAGE_KEY } from '../webparts/constants'; @@ -46,3 +47,21 @@ export function getRegion(): string { const region = spDevModeTrue ? 'a.clouddev.laserfiche.com' : 'laserfiche.com'; return region; } + +export function getCorrespondingTypeFieldName(fieldType: WFieldType): string { + switch (fieldType) { + case WFieldType.Date: + case WFieldType.List: + case WFieldType.Time: + case WFieldType.Number: + return fieldType; + case WFieldType.DateTime: + return 'Date/Time'; + case WFieldType.String: + return 'Text'; + case WFieldType.ShortInteger: + return 'Integer'; + case WFieldType.LongInteger: + return 'Long Integer'; + } +} \ No newline at end of file diff --git a/src/extensions/savetoLaserfiche/CommonDialogs.tsx b/src/extensions/savetoLaserfiche/CommonDialogs.tsx index cf226be..caacf9b 100644 --- a/src/extensions/savetoLaserfiche/CommonDialogs.tsx +++ b/src/extensions/savetoLaserfiche/CommonDialogs.tsx @@ -133,3 +133,79 @@ export function SavedToLaserficheSuccessDialogButtons(props: { ); } + +const createPromise: () => Promise[] = () => { + let resolver; + return [ + new Promise((resolve, reject) => { + resolver = resolve; + }), + resolver, + ]; +}; + +export const useConfirm: () => [ + (text: string) => Promise, + (props: { cancelButtonText: string }) => JSX.Element +] = () => { + const [open, setOpen] = React.useState(false); + const [resolver, setResolver] = React.useState({ resolve: null }); + const [label, setLabel] = React.useState(''); + + const getConfirmation: (text: string) => Promise = async (text: string) => { + setLabel(text); + setOpen(true); + const [promise, resolve] = await createPromise(); + setResolver({ resolve: resolve }); + return promise; + }; + + const onClick: (status: boolean) => Promise = async (status: boolean) => { + setOpen(false); + resolver.resolve(status); + }; + + const Confirmation: (props: { + cancelButtonText: string; + }) => JSX.Element = (props: { cancelButtonText: string }) => ( + <> + {open && ( + <> +
+
+
+ + + Document already exists + +
+
+
+
+ {label} +
+
+ + +
+ + )} + + ); + + return [getConfirmation, Confirmation]; +}; diff --git a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx index ebf76a8..7cbe5c7 100644 --- a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx +++ b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx @@ -416,32 +416,13 @@ function GetDocumentDialogData(props: { // automatically trims length to match constraint spDocFieldValue = spDocFieldValue.slice(0, lfField.length); } - } else if (lfField.fieldType === WFieldType.ShortInteger) { + } else if ( + lfField.fieldType === WFieldType.ShortInteger || + lfField.fieldType === WFieldType.LongInteger || + lfField.fieldType === WFieldType.Number + ) { const extractOnlyNumbers = spDocFieldValue.replace(/[^0-9]/g, ''); - const valueAsNumber = Number.parseInt(extractOnlyNumbers, 10); - if (valueAsNumber > 64999 || valueAsNumber < 0) { - // TODO invalid field -- should it truncate??? - spDocFieldValue = ''; - } else { - spDocFieldValue = extractOnlyNumbers; - } - } else if (lfField.fieldType === WFieldType.LongInteger) { - const extractOnlyNumbers = spDocFieldValue.replace(/[^0-9]/g, ''); - const valueAsNumber = Number.parseInt(extractOnlyNumbers, 10); - if (valueAsNumber > 3999999999 || valueAsNumber < 0) { - // TODO invalid field -- should it truncate??? - spDocFieldValue = ''; - } else { - spDocFieldValue = extractOnlyNumbers; - } - } else if (lfField.fieldType === WFieldType.Number) { - const valueRemoveNonNumbers = spDocFieldValue.replace(/[^0-9.]/g, ''); - if (!isNaN(Number.parseFloat(valueRemoveNonNumbers))) { - spDocFieldValue = valueRemoveNonNumbers; - } else { - // TODO invalid field -- should it truncate??? - spDocFieldValue = ''; - } + spDocFieldValue = extractOnlyNumbers; } return spDocFieldValue; } diff --git a/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx b/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx index 87e0ee5..d599012 100644 --- a/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx +++ b/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx @@ -10,7 +10,6 @@ import { SetFields, APIServerException, } from '@laserfiche/lf-repository-api-client'; -import { RepositoryClientExInternal } from '../../repository-client/repository-client'; import { IRepositoryApiClientExInternal } from '../../repository-client/repository-client-types'; import { getEntryWebAccessUrl } from '../../Utils/Funcs'; import { ISPDocumentData } from '../../Utils/Types'; @@ -32,46 +31,35 @@ export interface SavedToLaserficheDocumentData { } export class SaveDocumentToLaserfiche { - constructor(private spFileMetadata: ISPDocumentData) {} + constructor( + private spFileMetadata: ISPDocumentData, + private validRepoClient: IRepositoryApiClientExInternal + ) {} - async trySaveDocumentToLaserficheAsync(): Promise< - SavedToLaserficheDocumentData - > { + async trySaveDocumentToLaserficheAsync(): Promise { const loginComponent: NgElement & WithProperties = document.querySelector('lf-login'); const accessToken = loginComponent?.authorization_credentials?.accessToken; if (accessToken) { - const validRepoClient = await this.tryGetValidRepositoryClientAsync(); const webClientUrl = loginComponent?.account_endpoints.webClientUrl; - if (validRepoClient && this.spFileMetadata) { + if (this.validRepoClient && this.spFileMetadata) { const spFileData = await this.GetFileData(); const result = await this.saveFileToLaserficheAsync( spFileData, - validRepoClient, webClientUrl ); return result; } else { - throw Error('You are not signed in or there was an issue retrieving data from SharePoint. Please try again.') + throw Error( + 'You are not signed in or there was an issue retrieving data from SharePoint. Please try again.' + ); } } else { // user is not logged in } } - async tryGetValidRepositoryClientAsync(): Promise { - const repoClientCreator = new RepositoryClientExInternal(); - const newRepoClient = await repoClientCreator.createRepositoryClientAsync(); - try { - // test accessToken validity - await newRepoClient.repositoriesClient.getRepositoryList({}); - } catch { - return undefined; - } - return newRepoClient; - } - async GetFileData(): Promise { const spFileUrl = this.spFileMetadata.fileUrl; const fileNameWithExt = this.spFileMetadata.fileName; @@ -99,22 +87,19 @@ export class SaveDocumentToLaserfiche { async saveFileToLaserficheAsync( spFileData: Blob, - repoClient: IRepositoryApiClientExInternal, webClientUrl: string ): Promise { - if (spFileData && repoClient) { + if (spFileData && this.validRepoClient) { const laserficheProfileName = this.spFileMetadata.lfProfile; let result: SavedToLaserficheDocumentData | undefined; if (laserficheProfileName) { result = await this.sendToLaserficheWithMappingAsync( spFileData, - repoClient, webClientUrl ); } else { result = await this.sendToLaserficheNoMappingAsync( spFileData, - repoClient, webClientUrl ); } @@ -125,7 +110,6 @@ export class SaveDocumentToLaserfiche { async sendToLaserficheWithMappingAsync( fileData: Blob, - repoClient: IRepositoryApiClientExInternal, webClientUrl: string ): Promise { let request: PostEntryWithEdocMetadataRequest; @@ -145,7 +129,7 @@ export class SaveDocumentToLaserfiche { this.spFileMetadata.documentName.includes('FileName'); const parentEntryId = Number(this.spFileMetadata.entryId); - const repoId = await repoClient.getCurrentRepoId(); + const repoId = await this.validRepoClient.getCurrentRepoId(); let fileName: string | undefined; let fileNameInEdoc: string | undefined; @@ -185,7 +169,7 @@ export class SaveDocumentToLaserfiche { try { const entryCreateResult: CreateEntryResult = - await repoClient.entriesClient.importDocument(entryRequest); + await this.validRepoClient.entriesClient.importDocument(entryRequest); const entryId = entryCreateResult.operations.entryCreate.entryId ?? 1; const fileLink = getEntryWebAccessUrl( entryId.toString(), @@ -211,15 +195,10 @@ export class SaveDocumentToLaserfiche { pathBack: path, metadataSaved: true, fileName, - action: this.spFileMetadata.action + action: this.spFileMetadata.action, }; - await this.tryUpdateFileNameAsync( - repoClient, - repoId, - entryCreateResult, - fileInfo - ); + await this.tryUpdateFileNameAsync(repoId, entryCreateResult, fileInfo); return fileInfo; } catch (error) { const conflict409 = @@ -260,10 +239,10 @@ export class SaveDocumentToLaserfiche { metadataSaved: false, failedMetadata, fileName, - action: undefined + action: undefined, }; - await this.tryUpdateFileNameAsync(repoClient, repoId, error, fileInfo); + await this.tryUpdateFileNameAsync(repoId, error, fileInfo); return fileInfo; } else { window.localStorage.removeItem(SP_LOCAL_STORAGE_KEY); @@ -302,7 +281,6 @@ export class SaveDocumentToLaserfiche { async sendToLaserficheNoMappingAsync( fileData: Blob, - repoClient: IRepositoryApiClientExInternal, webClientUrl: string ): Promise { const fileNameWithExt = this.spFileMetadata.fileName; @@ -314,7 +292,7 @@ export class SaveDocumentToLaserfiche { const parentEntryId = 1; try { - const repoId = await repoClient.getCurrentRepoId(); + const repoId = await this.validRepoClient.getCurrentRepoId(); const electronicDocument: FileParameter = { fileName: fileNameWithExt, data: fileData, @@ -330,7 +308,7 @@ export class SaveDocumentToLaserfiche { }; const entryCreateResult: CreateEntryResult = - await repoClient.entriesClient.importDocument(entryRequest); + await this.validRepoClient.entriesClient.importDocument(entryRequest); const entryId = entryCreateResult.operations.entryCreate.entryId; const fileLink = getEntryWebAccessUrl( entryId.toString(), @@ -348,14 +326,9 @@ export class SaveDocumentToLaserfiche { pathBack: path, metadataSaved: true, fileName: fileNameWithExt, - action: this.spFileMetadata.action + action: this.spFileMetadata.action, }; - await this.tryUpdateFileNameAsync( - repoClient, - repoId, - entryCreateResult, - fileInfo - ); + await this.tryUpdateFileNameAsync(repoId, entryCreateResult, fileInfo); return fileInfo; } catch (error) { window.localStorage.removeItem(SP_LOCAL_STORAGE_KEY); @@ -364,16 +337,16 @@ export class SaveDocumentToLaserfiche { } private async tryUpdateFileNameAsync( - repoClient: IRepositoryApiClientExInternal, repoId: string, entryCreateResult: CreateEntryResult, fileInfo: SavedToLaserficheDocumentData ): Promise { try { - const entryInfo: Entry = await repoClient.entriesClient.getEntry({ - repoId, - entryId: entryCreateResult.operations.entryCreate.entryId, - }); + const entryInfo: Entry = + await this.validRepoClient.entriesClient.getEntry({ + repoId, + entryId: entryCreateResult.operations.entryCreate.entryId, + }); fileInfo.fileName = entryInfo.name; } catch { @@ -385,7 +358,9 @@ export class SaveDocumentToLaserfiche { const response = await this.deleteFileAsync(); window.localStorage.removeItem(SP_LOCAL_STORAGE_KEY); if (!response.ok) { - throw Error(`An error occurred while deleting file: ${response.statusText}`); + throw Error( + `An error occurred while deleting file: ${response.statusText}` + ); } } diff --git a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx index 8b6104b..08de20c 100644 --- a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx +++ b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx @@ -5,11 +5,13 @@ import { ISPDocumentData } from '../../Utils/Types'; import { clientId, LF_UI_COMPONENTS_URL, + SP_LOCAL_STORAGE_KEY, ZONE_JS_URL, } from '../../webparts/constants'; import LoadingDialog, { SavedToLaserficheSuccessDialogButtons, SavedToLaserficheSuccessDialogText, + useConfirm, } from './CommonDialogs'; import { SaveDocumentToLaserfiche, @@ -20,6 +22,13 @@ import { SPComponentLoader } from '@microsoft/sp-loader'; import * as ReactDOM from 'react-dom'; import { BaseDialog } from '@microsoft/sp-dialog'; import { getRegion } from '../../Utils/Funcs'; +import { + APIServerException, + Entry, +} from '@laserfiche/lf-repository-api-client'; +import { RepositoryClientExInternal } from '../../repository-client/repository-client'; +import { IRepositoryApiClientExInternal } from '../../repository-client/repository-client-types'; +import { PathUtils } from '@laserfiche/lf-js-utils'; export default class SaveToLaserficheCustomDialog extends BaseDialog { successful = false; @@ -81,23 +90,71 @@ function SaveToLaserficheDialog(props: { SavedToLaserficheDocumentData | undefined >(); const [error, setError] = React.useState(); + const [showSaveTo, setShowSaveTo] = React.useState(true); + const [getConfirmation, Confirmation] = useConfirm(); const saveToDialogCloseClick: () => Promise = async () => { await props.closeClick(success); }; + async function tryGetValidRepositoryClientAsync(): Promise { + const repoClientCreator = new RepositoryClientExInternal(); + const newRepoClient = await repoClientCreator.createRepositoryClientAsync(); + try { + // test accessToken validity + await newRepoClient.repositoriesClient.getRepositoryList({}); + } catch { + return undefined; + } + return newRepoClient; + } + React.useEffect(() => { const initializeComponentAsync: () => Promise = async () => { try { await SPComponentLoader.loadScript(ZONE_JS_URL); await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); if (loginComponent.current?.authorization_credentials) { - const saveToLF = new SaveDocumentToLaserfiche(props.spFileMetadata); + const validRepoClient = await tryGetValidRepositoryClientAsync(); + const saveToLF = new SaveDocumentToLaserfiche( + props.spFileMetadata, + validRepoClient + ); try { - const successSaveToLF = - await saveToLF.trySaveDocumentToLaserficheAsync(); - props.isSuccessfulLoggedIn(true); - setSuccess(successSaveToLF); + try { + const repoId = await validRepoClient.getCurrentRepoId(); + const entryInfo: Entry = + await validRepoClient.entriesClient.getEntry({ + repoId, + entryId: Number.parseInt(props.spFileMetadata.entryId, 10), + }); + const name = validRepoClient.entriesClient.getEntryByPath({ + repoId, + fullPath: PathUtils.combinePaths( + entryInfo.fullPath, + props.spFileMetadata.fileName + ), + }); + if (name) { + setShowSaveTo(false); + const status = await getConfirmation( + 'An entry with the same name already exists in the specified folder. If you continue, the document will be automatically renamed.' + ); + if (status) { + setShowSaveTo(true); + await continueSavingDocumentAsync(saveToLF); + } else { + window.localStorage.removeItem(SP_LOCAL_STORAGE_KEY); + props.isSuccessfulLoggedIn(true); + await props.closeClick(); + } + } + } catch (err) { + const docDoesNotAlreadyExists = (err as APIServerException).statusCode === 404; + if (docDoesNotAlreadyExists) { + await continueSavingDocumentAsync(saveToLF); + } + } } catch (err) { if (err.status === 401 || err.status === 403) { props.isSuccessfulLoggedIn(false); @@ -131,7 +188,11 @@ function SaveToLaserficheDialog(props: { return (
-
+
-
+
{!success && !error && } {success && ( )} - {error && {`Error saving:` } {error}} + {error && ( + + {`Error saving:`} {error} + + )}
-
+
+
); + + async function continueSavingDocumentAsync( + saveToLF: SaveDocumentToLaserfiche + ): Promise { + const successSaveToLF = await saveToLF.trySaveDocumentToLaserficheAsync(); + props.isSuccessfulLoggedIn(true); + setSuccess(successSaveToLF); + } } diff --git a/src/extensions/savetoLaserfiche/SendToLaserFiche.module.scss b/src/extensions/savetoLaserfiche/SendToLaserFiche.module.scss index 14d061a..7794879 100644 --- a/src/extensions/savetoLaserfiche/SendToLaserFiche.module.scss +++ b/src/extensions/savetoLaserfiche/SendToLaserFiche.module.scss @@ -11,6 +11,12 @@ min-width: 400px; } +.hideImport.header, +.hideImport.contentBox, +.hideImport.footer { + display: none; +} + .header { display: flex; justify-content: space-between; diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index 99931ee..f571423 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -1,7 +1,10 @@ import * as React from 'react'; import SvgHtmlIcons from '../components/SVGHtmlIcons'; import { SPComponentLoader } from '@microsoft/sp-loader'; -import { LfLoginComponent } from '@laserfiche/types-lf-ui-components'; +import { + AbortedLoginError, + LfLoginComponent, +} from '@laserfiche/types-lf-ui-components'; import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; import { @@ -111,7 +114,20 @@ export default function LaserficheRepositoryAccessWebPart( const url = props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - window.open(url, '_blank', 'popup'); + const loginWindow = window.open(url, '_blank', 'popup'); + window.addEventListener('message', (event) => { + if (event.origin === window.origin) { + if (event.data === 'loginWindowSuccess') { + loginWindow.close(); + } else if (event.data) { + const parsedError: AbortedLoginError = event.data; + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } + } + }); } return ( diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx index 973e3c7..338a203 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx @@ -9,6 +9,7 @@ import { PostEntryWithEdocMetadataRequest, PutFieldValsRequest, FileParameter, + APIServerException, } from '@laserfiche/lf-repository-api-client'; import { LfRepoTreeNodeService, @@ -26,6 +27,7 @@ import { IRepositoryApiClientExInternal } from '../../../repository-client/repos import { ChangeEvent } from 'react'; import { getEntryWebAccessUrl } from '../../../Utils/Funcs'; import styles from './LaserficheRepositoryAccess.module.scss'; +import { useConfirm } from './../../../extensions/savetoLaserfiche/CommonDialogs'; require('./../../../Assets/CSS/commonStyles.css'); const cols: ColumnDef[] = [ @@ -65,8 +67,7 @@ const fileNameValidation = 'Please provide a valid filename'; const fileNameWithBacklash = 'Please provide a valid filename without backslash'; const folderValidation = 'Please provide a folder name'; -const folderNameValidation = - 'Invalid Name, only alphanumeric characters are allowed.'; +const folderNameValidation = 'Entry names cannot contain backslash'; const folderExists = 'Object already exists'; export default function RepositoryViewComponent(props: { @@ -407,6 +408,9 @@ function ImportFileModal(props: { React.useState(false); const [error, setError] = React.useState(undefined); + const [showImport, setShowImport] = React.useState(true); + const [getConfirmation, Confirmation] = useConfirm(); + const onDialogOpened: () => void = () => { setAdhocDialogOpened(true); }; @@ -461,67 +465,35 @@ function ImportFileModal(props: { const extension = PathUtils.getCleanedExtension(fileData.name); const renamedFile = new File([fileData], fileName + extension); const fileContainsBacklash = fileName.includes('\\'); + try { + const name = await props.repoClient.entriesClient.getEntryByPath({ + repoId, + fullPath: PathUtils.combinePaths(props.parentItem.path, fileName), + }); + if (name) { + setShowImport(false); + const status = await getConfirmation( + 'An entry with the same name already exists in the specified folder. If you continue, the document will be automatically renamed.' + ); + setShowImport(true); + if (status) { + // continue + } else { + setFileUploadPercentage(0); + return; + } + } + } catch (err) { + if ((err as APIServerException).statusCode === 404) { + // doesn't exist, good to go + } + } if (fileContainsBacklash) { setFileUploadPercentage(0); setImportFileValidationMessage(fileNameWithBacklash); return; } - const fieldValidation = fieldContainer.current.forceValidation(); - if (fieldValidation) { - const fieldValues = fieldContainer.current.getFieldValues(); - const formattedFieldValues: - | { - [key: string]: FieldToUpdate; - } - | undefined = {}; - - for (const key in fieldValues) { - const value = fieldValues[key]; - formattedFieldValues[key] = new FieldToUpdate({ - ...value, - values: value.values.map((val) => new ValueToUpdate(val)), - }); - } - - const templateValue = getTemplateName(); - let templateName; - if (templateValue) { - templateName = templateValue; - } - - setFileUploadPercentage(80); - const fieldsmetadata: PostEntryWithEdocMetadataRequest = - new PostEntryWithEdocMetadataRequest({ - template: templateName, - metadata: new PutFieldValsRequest({ - fields: formattedFieldValues, - }), - }); - const fileNameWithExt = fileName + extension; - const fileextensionperiod = extension; - const fileNameNoPeriod = fileName; - const parentEntryId = props.parentItem.id; - - const file: FileParameter = { - data: renamedFile, - fileName: fileNameWithExt, - }; - const requestParameters = { - repoId, - parentEntryId: Number.parseInt(parentEntryId, 10), - electronicDocument: file, - autoRename: true, - fileName: fileNameNoPeriod, - request: fieldsmetadata, - extension: fileextensionperiod, - }; - - await props.repoClient.entriesClient.importDocument(requestParameters); - setFileUploadPercentage(100); - props.closeImportModal(); - } else { - fieldContainer.current.forceValidation(); - } + await continueImportAsync(extension, renamedFile, repoId); } catch (err) { setFileUploadPercentage(0); setError(err.message); @@ -529,6 +501,69 @@ function ImportFileModal(props: { } }; + async function continueImportAsync( + extension: string, + renamedFile: File, + repoId: string + ): Promise { + const fieldValidation = fieldContainer.current.forceValidation(); + if (fieldValidation) { + const fieldValues = fieldContainer.current.getFieldValues(); + const formattedFieldValues: + | { + [key: string]: FieldToUpdate; + } + | undefined = {}; + + for (const key in fieldValues) { + const value = fieldValues[key]; + formattedFieldValues[key] = new FieldToUpdate({ + ...value, + values: value.values.map((val) => new ValueToUpdate(val)), + }); + } + + const templateValue = getTemplateName(); + let templateName; + if (templateValue) { + templateName = templateValue; + } + + setFileUploadPercentage(80); + const fieldsmetadata: PostEntryWithEdocMetadataRequest = + new PostEntryWithEdocMetadataRequest({ + template: templateName, + metadata: new PutFieldValsRequest({ + fields: formattedFieldValues, + }), + }); + const fileNameWithExt = fileName + extension; + const fileextensionperiod = extension; + const fileNameNoPeriod = fileName; + const parentEntryId = props.parentItem.id; + + const file: FileParameter = { + data: renamedFile, + fileName: fileNameWithExt, + }; + const requestParameters = { + repoId, + parentEntryId: Number.parseInt(parentEntryId, 10), + electronicDocument: file, + autoRename: true, + fileName: fileNameNoPeriod, + request: fieldsmetadata, + extension: fileextensionperiod, + }; + + await props.repoClient.entriesClient.importDocument(requestParameters); + setFileUploadPercentage(100); + props.closeImportModal(); + } else { + fieldContainer.current.forceValidation(); + } + } + function getTemplateName(): string { const templateValue = fieldContainer.current.getTemplateValue(); if (templateValue) { @@ -570,7 +605,7 @@ function ImportFileModal(props: { return (
-
+
-
+ ); @@ -684,7 +720,7 @@ function CreateFolderModal(props: { const createNewFolderAsync: () => Promise = async () => { if (folderName) { - if (/[^ A-Za-z0-9]/.test(folderName)) { + if (/^[^\\\\]*$/.test(folderName)) { setCreateFolderNameValidationMessage(folderNameValidation); } else { setCreateFolderNameValidationMessage(undefined); diff --git a/src/webparts/constants.ts b/src/webparts/constants.ts index d2a4925..a027f3c 100644 --- a/src/webparts/constants.ts +++ b/src/webparts/constants.ts @@ -7,7 +7,7 @@ export const MANAGE_CONFIGURATIONS = 'ManageConfigurations'; export const SP_LOCAL_STORAGE_KEY = 'spdocdata'; export const SPDEVMODE_LOCAL_STORAGE_KEY = 'spDevMode'; -export const LF_UI_COMPONENTS_URL = 'https://cdn.jsdelivr.net/npm/@laserfiche/lf-ui-components@15/cdn/lf-ui-components.js'; -export const LF_MS_OFFICE_LITE_CSS_URL = 'https://cdn.jsdelivr.net/npm/@laserfiche/lf-ui-components@15/cdn/lf-ms-office-lite.css'; -export const LF_INDIGO_PINK_CSS_URL = 'https://cdn.jsdelivr.net/npm/@laserfiche/lf-ui-components@15/cdn/indigo-pink.css'; -export const ZONE_JS_URL = 'https://cdn.jsdelivr.net/npm/zone.js@0.11.4/bundles/zone.umd.min.js'; +export const LF_UI_COMPONENTS_URL = 'https://lfxstatic.com/npm/@laserfiche/lf-ui-components@15/cdn/lf-ui-components.js'; +export const LF_MS_OFFICE_LITE_CSS_URL = 'https://lfxstatic.com/npm/@laserfiche/lf-ui-components@15/cdn/lf-ms-office-lite.css'; +export const LF_INDIGO_PINK_CSS_URL = 'https://lfxstatic.com/npm/@laserfiche/lf-ui-components@15/cdn/indigo-pink.css'; +export const ZONE_JS_URL = 'https://lfxstatic.com/npm/-/zone.js@0.11.4/bundles/zone.umd.min.js'; diff --git a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx index 8e62502..730dc00 100644 --- a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx @@ -17,7 +17,10 @@ import { ZONE_JS_URL, } from '../../constants'; import { NgElement, WithProperties } from '@angular/elements'; -import { LfLoginComponent } from '@laserfiche/types-lf-ui-components'; +import { + AbortedLoginError, + LfLoginComponent, +} from '@laserfiche/types-lf-ui-components'; import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; import { SPComponentLoader } from '@microsoft/sp-loader'; @@ -109,7 +112,20 @@ export default function LaserficheAdminConfiguration( const url = props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - window.open(url, '_blank', 'popup'); + const loginWindow = window.open(url, '_blank', 'popup'); + window.addEventListener('message', (event) => { + if (event.origin === window.origin) { + if (event.data === 'loginWindowSuccess') { + loginWindow.close(); + } else if (event.data) { + const parsedError: AbortedLoginError = event.data; + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } + } + }); } return ( diff --git a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx index c4c127e..b3a7499 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx @@ -13,6 +13,7 @@ import { LfRepositoryBrowserComponent } from '@laserfiche/types-lf-ui-components import * as React from 'react'; import { ChangeEvent, useState } from 'react'; import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; +import { getCorrespondingTypeFieldName } from '../../../Utils/Funcs'; import styles from './LaserficheAdminConfiguration.module.scss'; export interface ProfileConfiguration { @@ -499,7 +500,7 @@ export function SharePointLaserficheColumnMatching(props: { const laserficheFields = props.lfFieldsForSelectedTemplate?.map((items) => { return ( ); }); @@ -532,7 +533,7 @@ export function SharePointLaserficheColumnMatching(props: { ?.map((items) => { return ( ); }); @@ -698,7 +699,7 @@ function getMappingErrorMessage( ): JSX.Element | undefined { if (mappedField.lfField && mappedField.spField) { const spFieldtype = mappedField.spField.TypeAsString; - const lfFieldtype = mappedField.lfField.fieldType; + const lfFieldTypeDisplayName = getCorrespondingTypeFieldName(mappedField.lfField.fieldType); const hasMismatch = hasFieldTypeMismatch(mappedField); if (hasMismatch) { @@ -710,7 +711,7 @@ function getMappingErrorMessage( display: 'flex', alignItems: 'center', }} - title={`SharePoint field type of ${spFieldtype} cannot be mapped with Laserfiche field type of ${lfFieldtype}`} + title={`SharePoint field type of ${spFieldtype} cannot be mapped with Laserfiche field type of ${getCorrespondingTypeFieldName}}`} > Data types mismatch. SharePoint field type of {spFieldtype} cannot be - mapped with Laserfiche field type of {lfFieldtype} + mapped with Laserfiche field type of {lfFieldTypeDisplayName}
); } else { diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index 5620305..5ec2aeb 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { SPComponentLoader } from '@microsoft/sp-loader'; import { Navigation } from 'spfx-navigation'; import { + AbortedLoginError, LfLoginComponent, LoginState, } from '@laserfiche/types-lf-ui-components'; @@ -60,7 +61,7 @@ export default function SendToLaserficheLoginComponent( const loginText: JSX.Element | undefined = getLoginText(); const autoLoginCompleted: () => Promise = async () => { - window.close(); + window.opener.postMessage('loginWindowSuccess', window.origin); }; const loginCompleted: () => Promise = async () => { @@ -81,25 +82,84 @@ export default function SendToLaserficheLoginComponent( } }; - const logoutCompleted: () => void = () => { - setLoggedIn(false); + const logoutCompleted: ( + ev: CustomEvent, + autoLogout?: boolean + ) => void = ( + ev: CustomEvent, + autoLogout: boolean = false + ) => { + const logOutError = ev.detail; + if (autoLogout && !logOutError) { + window.opener.postMessage('loginWindowSuccess', window.origin); + } else if (logOutError) { + window.opener.postMessage(logOutError, window.origin); + } else { + setLoggedIn(false); + } }; React.useEffect(() => { + const logoutCompleteCallBackTrue: (ev: Event) => void = (ev: Event) => { + const errorOccurred = (ev as CustomEvent).detail; + if (errorOccurred) { + logoutCompleted(ev as CustomEvent, true); + } + }; + + const logoutCompleteCallBackFalse: (ev: Event) => void = (ev: Event) => { + logoutCompleted(ev as CustomEvent); + }; + + const cleanUpFunction: () => void = () => { + loginComponent.current.removeEventListener( + 'loginCompleted', + loginCompleted + ); + loginComponent.current.removeEventListener( + 'loginCompleted', + autoLoginCompleted + ); + loginComponent.current.removeEventListener( + 'logoutCompleted', + logoutCompleteCallBackTrue + ); + loginComponent.current.removeEventListener( + 'logoutCompleted', + logoutCompleteCallBackFalse + ); + }; + const setUpLoginComponentAsync: () => Promise = async () => { try { SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); + loginComponent.current.addEventListener( + 'logoutCompleted', + logoutCompleteCallBackTrue + ); await SPComponentLoader.loadScript(ZONE_JS_URL); await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); if (window.location.href.includes('autologin')) { document.body.style.display = 'none'; if (loginComponent.current.state !== LoginState.LoggedIn) { - if (!document.referrer.includes('accounts.')) { + if ( + !document.referrer.includes('accounts.') && + !document.referrer.includes('signin.') + ) { await loginComponent.current.initLoginFlowAsync(); + loginComponent.current.addEventListener( + 'loginCompleted', + autoLoginCompleted + ); + } else if (loginComponent.current.state === LoginState.LoggedOut) { + window.opener.postMessage('loginWindowSuccess', window.origin); } else { - window.close(); + loginComponent.current.addEventListener( + 'loginCompleted', + autoLoginCompleted + ); } } else { const loginbutton = loginComponent.current.querySelector( @@ -107,39 +167,32 @@ export default function SendToLaserficheLoginComponent( ) as HTMLButtonElement; loginbutton.click(); } - loginComponent.current.addEventListener( - 'loginCompleted', - autoLoginCompleted - ); } else { loginComponent.current.addEventListener( 'loginCompleted', loginCompleted ); - loginComponent.current.addEventListener( - 'logoutCompleted', - logoutCompleted + loginComponent.current.addEventListener('logoutCompleted', (ev) => + logoutCompleted(ev as CustomEvent) ); - } + const isLoggedIn: boolean = + loginComponent.current.state === LoginState.LoggedIn; - const isLoggedIn: boolean = - loginComponent.current.state === LoginState.LoggedIn; - - setLoggedIn(isLoggedIn); - - if (isLoggedIn && spFileMetadata) { - const dialog = new SaveToLaserficheCustomDialog( - spFileMetadata, - async (success) => { - if (success) { - Navigation.navigate(success.pathBack, true); + setLoggedIn(isLoggedIn); + if (isLoggedIn && spFileMetadata) { + const dialog = new SaveToLaserficheCustomDialog( + spFileMetadata, + async (success) => { + if (success) { + Navigation.navigate(success.pathBack, true); + } } - } - ); + ); - await dialog.show(); - if (!dialog.successful) { - console.warn('Could not sign in successfully'); + await dialog.show(); + if (!dialog.successful) { + console.warn('Could not sign in successfully'); + } } } } catch (err) { @@ -148,6 +201,8 @@ export default function SendToLaserficheLoginComponent( }; void setUpLoginComponentAsync(); + + return cleanUpFunction; }, []); function getLoginText(): JSX.Element { @@ -220,7 +275,21 @@ export default function SendToLaserficheLoginComponent( const url = props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - window.open(url, '_blank', 'popup'); + + const loginWindow = window.open(url, '_blank', 'popup'); + window.addEventListener('message', (event) => { + if (event.origin === window.origin) { + if (event.data === 'loginWindowSuccess') { + loginWindow.close(); + } else if (event.data) { + const parsedError: AbortedLoginError = event.data; + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } + } + }); } const redirectURL = From 6e2c694eb16009b14be5c1a3edabafb84b866b2a Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Fri, 13 Oct 2023 17:04:11 -0400 Subject: [PATCH 06/11] resize window --- .../components/LaserficheRepositoryAccessWebPart.tsx | 3 ++- .../components/LaserficheAdminConfiguration.tsx | 3 ++- .../components/SendToLaserficheLoginComponent.tsx | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index f571423..18a16d0 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -114,7 +114,8 @@ export default function LaserficheRepositoryAccessWebPart( const url = props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - const loginWindow = window.open(url, '_blank', 'popup'); + const loginWindow = window.open(url, 'loginWindow', 'popup'); + loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { if (event.data === 'loginWindowSuccess') { diff --git a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx index 730dc00..4626301 100644 --- a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx @@ -112,7 +112,8 @@ export default function LaserficheAdminConfiguration( const url = props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - const loginWindow = window.open(url, '_blank', 'popup'); + const loginWindow = window.open(url, 'loginWindow', 'popup'); + loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { if (event.data === 'loginWindowSuccess') { diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index 5ec2aeb..887a97a 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -276,7 +276,8 @@ export default function SendToLaserficheLoginComponent( props.context.pageContext.web.absoluteUrl + '/SitePages/LaserficheSignIn.aspx?autologin'; - const loginWindow = window.open(url, '_blank', 'popup'); + const loginWindow = window.open(url, 'loginWindow', 'popup'); + loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { if (event.data === 'loginWindowSuccess') { From f87915a1ec92ba2efbb510febea820d401b764df Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Fri, 13 Oct 2023 17:30:02 -0400 Subject: [PATCH 07/11] change Page column to Pages --- .../components/RepositoryViewWebPart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx index 338a203..a88687d 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx @@ -47,7 +47,7 @@ const cols: ColumnDef[] = [ }, { id: 'pageCount', - displayName: 'Page', + displayName: 'Pages', defaultWidth: '100px', resizable: true, sortable: true, From 285e7d37fb30f4432cbff940baa463aad9a6213c Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Mon, 16 Oct 2023 11:26:30 -0400 Subject: [PATCH 08/11] only post to parent once --- .../LaserficheRepositoryAccessWebPart.tsx | 10 +++--- .../components/RepositoryViewWebPart.tsx | 6 ++-- .../LaserficheAdminConfiguration.tsx | 10 +++--- .../SendToLaserficheLoginComponent.tsx | 32 ++++++++++++++----- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index 18a16d0..c37f894 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -122,10 +122,12 @@ export default function LaserficheRepositoryAccessWebPart( loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; - loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` - ); + if (parsedError.ErrorMessage && parsedError.ErrorType) { + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } } } }); diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx index a88687d..9b6b350 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx @@ -67,7 +67,7 @@ const fileNameValidation = 'Please provide a valid filename'; const fileNameWithBacklash = 'Please provide a valid filename without backslash'; const folderValidation = 'Please provide a folder name'; -const folderNameValidation = 'Entry names cannot contain backslash'; +const folderBackslashNameValidation = 'Entry names cannot contain backslash'; const folderExists = 'Object already exists'; export default function RepositoryViewComponent(props: { @@ -720,8 +720,8 @@ function CreateFolderModal(props: { const createNewFolderAsync: () => Promise = async () => { if (folderName) { - if (/^[^\\\\]*$/.test(folderName)) { - setCreateFolderNameValidationMessage(folderNameValidation); + if (/^[\\\\]*$/.test(folderName)) { + setCreateFolderNameValidationMessage(folderBackslashNameValidation); } else { setCreateFolderNameValidationMessage(undefined); diff --git a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx index 4626301..a034583 100644 --- a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx @@ -120,10 +120,12 @@ export default function LaserficheAdminConfiguration( loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; - loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` - ); + if (parsedError.ErrorMessage && parsedError.ErrorType) { + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } } } }); diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index 887a97a..635ae3a 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -43,6 +43,7 @@ export default function SendToLaserficheLoginComponent( > = React.useRef(); const [loggedIn, setLoggedIn] = React.useState(false); + let sentPostMessage = false; const region = getRegion(); @@ -61,7 +62,10 @@ export default function SendToLaserficheLoginComponent( const loginText: JSX.Element | undefined = getLoginText(); const autoLoginCompleted: () => Promise = async () => { - window.opener.postMessage('loginWindowSuccess', window.origin); + if (!sentPostMessage) { + window.opener.postMessage('loginWindowSuccess', window.origin); + sentPostMessage = true; + } }; const loginCompleted: () => Promise = async () => { @@ -91,9 +95,15 @@ export default function SendToLaserficheLoginComponent( ) => { const logOutError = ev.detail; if (autoLogout && !logOutError) { - window.opener.postMessage('loginWindowSuccess', window.origin); + if (!sentPostMessage) { + window.opener.postMessage('loginWindowSuccess', window.origin); + sentPostMessage = true; + } } else if (logOutError) { - window.opener.postMessage(logOutError, window.origin); + if (!sentPostMessage) { + window.opener.postMessage(logOutError, window.origin); + sentPostMessage = true; + } } else { setLoggedIn(false); } @@ -154,7 +164,10 @@ export default function SendToLaserficheLoginComponent( autoLoginCompleted ); } else if (loginComponent.current.state === LoginState.LoggedOut) { - window.opener.postMessage('loginWindowSuccess', window.origin); + if (!sentPostMessage) { + window.opener.postMessage('loginWindowSuccess', window.origin); + sentPostMessage = true; + } } else { loginComponent.current.addEventListener( 'loginCompleted', @@ -200,6 +213,7 @@ export default function SendToLaserficheLoginComponent( } }; + cleanUpFunction(); void setUpLoginComponentAsync(); return cleanUpFunction; @@ -284,10 +298,12 @@ export default function SendToLaserficheLoginComponent( loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; - loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` - ); + if (parsedError.ErrorMessage && parsedError.ErrorType) { + loginWindow.close(); + window.alert( + `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + ); + } } } }); From 45cec133fbdb0d1de8bceea82bb7ce1126cfde87 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Mon, 16 Oct 2023 12:39:58 -0400 Subject: [PATCH 09/11] update confirmation string --- src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx | 3 ++- .../components/RepositoryViewWebPart.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx index 08de20c..1acc414 100644 --- a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx +++ b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx @@ -76,6 +76,7 @@ export default class SaveToLaserficheCustomDialog extends BaseDialog { } } +const ENTRY_WITH_SAME_NAME_EXISTS_IN_FOLDER_IF_CONTINUE_LF_WILL_RENAME = 'An entry with the same name already exists in the specified folder. If you continue, Laserfiche will automatically rename the new document.'; function SaveToLaserficheDialog(props: { isSuccessfulLoggedIn: (success: boolean) => void; closeClick: (success?: SavedToLaserficheDocumentData) => Promise; @@ -138,7 +139,7 @@ function SaveToLaserficheDialog(props: { if (name) { setShowSaveTo(false); const status = await getConfirmation( - 'An entry with the same name already exists in the specified folder. If you continue, the document will be automatically renamed.' + ENTRY_WITH_SAME_NAME_EXISTS_IN_FOLDER_IF_CONTINUE_LF_WILL_RENAME ); if (status) { setShowSaveTo(true); diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx index 9b6b350..62e60aa 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx @@ -388,6 +388,7 @@ function RepositoryBrowserToolbar(props: { ); } +const ENTRY_WITH_SAME_NAME_EXISTS_IN_FOLDER_IF_CONTINUE_LF_WILL_RENAME = 'An entry with the same name already exists in the specified folder. If you continue, Laserfiche will automatically rename the new document.'; function ImportFileModal(props: { repoClient: IRepositoryApiClientExInternal; loggedIn: boolean; @@ -473,7 +474,7 @@ function ImportFileModal(props: { if (name) { setShowImport(false); const status = await getConfirmation( - 'An entry with the same name already exists in the specified folder. If you continue, the document will be automatically renamed.' + ENTRY_WITH_SAME_NAME_EXISTS_IN_FOLDER_IF_CONTINUE_LF_WILL_RENAME ); setShowImport(true); if (status) { From 431227223e271084395ca35afcf973b58fd5f24e Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Mon, 16 Oct 2023 13:01:09 -0400 Subject: [PATCH 10/11] allow decimal points in numbers, allow server to validate --- src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx index 7cbe5c7..b630c3b 100644 --- a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx +++ b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx @@ -421,7 +421,7 @@ function GetDocumentDialogData(props: { lfField.fieldType === WFieldType.LongInteger || lfField.fieldType === WFieldType.Number ) { - const extractOnlyNumbers = spDocFieldValue.replace(/[^0-9]/g, ''); + const extractOnlyNumbers = spDocFieldValue.replace(/[^0-9.]/g, ''); spDocFieldValue = extractOnlyNumbers; } return spDocFieldValue; From 821e22d9f6943e8fcf9192b961c0d2475dcaefb6 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Mon, 16 Oct 2023 16:10:39 -0400 Subject: [PATCH 11/11] change window.alert to modal, refactor sign in component --- .../savetoLaserfiche/CommonDialogs.tsx | 37 ++- .../SaveToLaserficheDialog.tsx | 11 +- .../LaserficheRepositoryAccessWebPart.tsx | 28 ++- .../components/RepositoryViewWebPart.tsx | 11 +- src/webparts/constants.ts | 2 + .../LaserficheAdminConfiguration.tsx | 28 ++- .../ProfileConfigurationComponents.tsx | 2 +- ...SendToLaserficheLoginComponent.module.scss | 13 ++ .../SendToLaserficheLoginComponent.tsx | 213 ++++++++++-------- 9 files changed, 234 insertions(+), 111 deletions(-) diff --git a/src/extensions/savetoLaserfiche/CommonDialogs.tsx b/src/extensions/savetoLaserfiche/CommonDialogs.tsx index caacf9b..ab99477 100644 --- a/src/extensions/savetoLaserfiche/CommonDialogs.tsx +++ b/src/extensions/savetoLaserfiche/CommonDialogs.tsx @@ -134,6 +134,35 @@ export function SavedToLaserficheSuccessDialogButtons(props: { ); } +export function MessageDialog(props: { + title: string; + message: string; + clickOkay: () => void; +}): JSX.Element { + return ( +
+
+
+
+ {props.title} +
+
+
{props.message}
+
+ +
+
+
+ ); +} + const createPromise: () => Promise[] = () => { let resolver; return [ @@ -152,7 +181,9 @@ export const useConfirm: () => [ const [resolver, setResolver] = React.useState({ resolve: null }); const [label, setLabel] = React.useState(''); - const getConfirmation: (text: string) => Promise = async (text: string) => { + const getConfirmation: (text: string) => Promise = async ( + text: string + ) => { setLabel(text); setOpen(true); const [promise, resolve] = await createPromise(); @@ -160,7 +191,9 @@ export const useConfirm: () => [ return promise; }; - const onClick: (status: boolean) => Promise = async (status: boolean) => { + const onClick: (status: boolean) => Promise = async ( + status: boolean + ) => { setOpen(false); resolver.resolve(status); }; diff --git a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx index 1acc414..aec1fc3 100644 --- a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx +++ b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx @@ -129,19 +129,19 @@ function SaveToLaserficheDialog(props: { repoId, entryId: Number.parseInt(props.spFileMetadata.entryId, 10), }); - const name = validRepoClient.entriesClient.getEntryByPath({ + const entryWithPathExists = validRepoClient.entriesClient.getEntryByPath({ repoId, fullPath: PathUtils.combinePaths( entryInfo.fullPath, props.spFileMetadata.fileName ), }); - if (name) { + if (entryWithPathExists) { setShowSaveTo(false); - const status = await getConfirmation( + const confirmSave = await getConfirmation( ENTRY_WITH_SAME_NAME_EXISTS_IN_FOLDER_IF_CONTINUE_LF_WILL_RENAME ); - if (status) { + if (confirmSave) { setShowSaveTo(true); await continueSavingDocumentAsync(saveToLF); } else { @@ -155,6 +155,9 @@ function SaveToLaserficheDialog(props: { if (docDoesNotAlreadyExists) { await continueSavingDocumentAsync(saveToLF); } + else { + throw err; + } } } catch (err) { if (err.status === 401 || err.status === 403) { diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index c37f894..62f95e7 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -12,6 +12,7 @@ import { LF_INDIGO_PINK_CSS_URL, LF_MS_OFFICE_LITE_CSS_URL, LF_UI_COMPONENTS_URL, + LOGIN_WINDOW_SUCCESS, ZONE_JS_URL, } from '../../constants'; import { NgElement, WithProperties } from '@angular/elements'; @@ -23,6 +24,7 @@ import './LaserficheRepositoryAccess.module.scss'; import { ILaserficheRepositoryAccessWebPartProps } from './ILaserficheRepositoryAccessWebPartProps'; import { getRegion } from '../../../Utils/Funcs'; import styles from './LaserficheRepositoryAccess.module.scss'; +import { MessageDialog } from '../../../extensions/savetoLaserfiche/CommonDialogs'; declare global { // eslint-disable-next-line @@ -47,6 +49,9 @@ export default function LaserficheRepositoryAccessWebPart( const [repoClient, setRepoClient] = useState< IRepositoryApiClientExInternal | undefined >(undefined); + const [messageErrorModal, setMessageErrorModal] = useState< + JSX.Element | undefined + >(undefined); const region = getRegion(); @@ -118,15 +123,22 @@ export default function LaserficheRepositoryAccessWebPart( loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { - if (event.data === 'loginWindowSuccess') { + if (event.data === LOGIN_WINDOW_SUCCESS) { loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; if (parsedError.ErrorMessage && parsedError.ErrorType) { loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> ); + setMessageErrorModal(mes); } } } @@ -157,6 +169,16 @@ export default function LaserficheRepositoryAccessWebPart( {loggedIn ? 'Sign out' : 'Sign in'}
+ {messageErrorModal !== undefined && ( +
+ {messageErrorModal} +
+ )} (undefined); + const [messageErrorModal, setMessageErrorModal] = useState< + JSX.Element | undefined + >(undefined); const region = getRegion(); @@ -116,15 +121,22 @@ export default function LaserficheAdminConfiguration( loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { - if (event.data === 'loginWindowSuccess') { + if (event.data === LOGIN_WINDOW_SUCCESS) { loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; if (parsedError.ErrorMessage && parsedError.ErrorType) { loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> ); + setMessageErrorModal(mes); } } } @@ -220,6 +232,16 @@ export default function LaserficheAdminConfiguration( )} + {messageErrorModal !== undefined && ( +
+ {messageErrorModal} +
+ )} diff --git a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx index b3a7499..1e0c873 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx @@ -711,7 +711,7 @@ function getMappingErrorMessage( display: 'flex', alignItems: 'center', }} - title={`SharePoint field type of ${spFieldtype} cannot be mapped with Laserfiche field type of ${getCorrespondingTypeFieldName}}`} + title={`SharePoint field type of ${spFieldtype} cannot be mapped with Laserfiche field type of ${lfFieldTypeDisplayName}`} > = React.useRef(); const [loggedIn, setLoggedIn] = React.useState(false); + const [messageErrorModal, setMessageErrorModal] = React.useState< + JSX.Element | undefined + >(undefined); + let sentPostMessage = false; const region = getRegion(); @@ -61,14 +67,14 @@ export default function SendToLaserficheLoginComponent( } const loginText: JSX.Element | undefined = getLoginText(); - const autoLoginCompleted: () => Promise = async () => { + const loginCompletedInPopup: () => Promise = async () => { if (!sentPostMessage) { - window.opener.postMessage('loginWindowSuccess', window.origin); + window.opener.postMessage(LOGIN_WINDOW_SUCCESS, window.origin); sentPostMessage = true; } }; - const loginCompleted: () => Promise = async () => { + const loginCompletedInMainWindow: () => Promise = async () => { setLoggedIn(true); if (spFileMetadata) { const dialog = new SaveToLaserficheCustomDialog( @@ -86,57 +92,44 @@ export default function SendToLaserficheLoginComponent( } }; - const logoutCompleted: ( - ev: CustomEvent, - autoLogout?: boolean - ) => void = ( - ev: CustomEvent, - autoLogout: boolean = false - ) => { - const logOutError = ev.detail; - if (autoLogout && !logOutError) { - if (!sentPostMessage) { - window.opener.postMessage('loginWindowSuccess', window.origin); - sentPostMessage = true; - } - } else if (logOutError) { - if (!sentPostMessage) { - window.opener.postMessage(logOutError, window.origin); - sentPostMessage = true; + const logoutCompletedInMainWindow: () => void = () => { + setLoggedIn(false); + }; + + const logoutCompletedInPopup: (ev: Event) => void = (ev: Event) => { + const errorOccurred = (ev as CustomEvent).detail; + if (errorOccurred) { + if (!errorOccurred) { + if (!sentPostMessage) { + window.opener.postMessage(LOGIN_WINDOW_SUCCESS, window.origin); + sentPostMessage = true; + } + } else if (errorOccurred) { + if (!sentPostMessage) { + window.opener.postMessage(errorOccurred, window.origin); + sentPostMessage = true; + } } - } else { - setLoggedIn(false); } }; React.useEffect(() => { - const logoutCompleteCallBackTrue: (ev: Event) => void = (ev: Event) => { - const errorOccurred = (ev as CustomEvent).detail; - if (errorOccurred) { - logoutCompleted(ev as CustomEvent, true); - } - }; - - const logoutCompleteCallBackFalse: (ev: Event) => void = (ev: Event) => { - logoutCompleted(ev as CustomEvent); - }; - const cleanUpFunction: () => void = () => { loginComponent.current.removeEventListener( 'loginCompleted', - loginCompleted + loginCompletedInMainWindow ); loginComponent.current.removeEventListener( 'loginCompleted', - autoLoginCompleted + loginCompletedInPopup ); loginComponent.current.removeEventListener( 'logoutCompleted', - logoutCompleteCallBackTrue + logoutCompletedInPopup ); loginComponent.current.removeEventListener( 'logoutCompleted', - logoutCompleteCallBackFalse + logoutCompletedInMainWindow ); }; @@ -146,67 +139,16 @@ export default function SendToLaserficheLoginComponent( SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); loginComponent.current.addEventListener( 'logoutCompleted', - logoutCompleteCallBackTrue + logoutCompletedInPopup ); await SPComponentLoader.loadScript(ZONE_JS_URL); await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); if (window.location.href.includes('autologin')) { document.body.style.display = 'none'; - if (loginComponent.current.state !== LoginState.LoggedIn) { - if ( - !document.referrer.includes('accounts.') && - !document.referrer.includes('signin.') - ) { - await loginComponent.current.initLoginFlowAsync(); - loginComponent.current.addEventListener( - 'loginCompleted', - autoLoginCompleted - ); - } else if (loginComponent.current.state === LoginState.LoggedOut) { - if (!sentPostMessage) { - window.opener.postMessage('loginWindowSuccess', window.origin); - sentPostMessage = true; - } - } else { - loginComponent.current.addEventListener( - 'loginCompleted', - autoLoginCompleted - ); - } - } else { - const loginbutton = loginComponent.current.querySelector( - '.login-button' - ) as HTMLButtonElement; - loginbutton.click(); - } + await handleLoginOrLogoutInPopupAsync(); } else { - loginComponent.current.addEventListener( - 'loginCompleted', - loginCompleted - ); - loginComponent.current.addEventListener('logoutCompleted', (ev) => - logoutCompleted(ev as CustomEvent) - ); - const isLoggedIn: boolean = - loginComponent.current.state === LoginState.LoggedIn; - - setLoggedIn(isLoggedIn); - if (isLoggedIn && spFileMetadata) { - const dialog = new SaveToLaserficheCustomDialog( - spFileMetadata, - async (success) => { - if (success) { - Navigation.navigate(success.pathBack, true); - } - } - ); - - await dialog.show(); - if (!dialog.successful) { - console.warn('Could not sign in successfully'); - } - } + await handleLoginOrLogoutInMainWindowAsync(); } } catch (err) { console.error(`Unable to initialize sign-in page: ${err}`); @@ -219,6 +161,72 @@ export default function SendToLaserficheLoginComponent( return cleanUpFunction; }, []); + async function handleLoginOrLogoutInMainWindowAsync(): Promise { + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompletedInMainWindow + ); + loginComponent.current.addEventListener( + 'logoutCompleted', + logoutCompletedInMainWindow + ); + const isLoggedIn: boolean = + loginComponent.current.state === LoginState.LoggedIn; + + setLoggedIn(isLoggedIn); + if (isLoggedIn && spFileMetadata) { + await trySaveToLaserficheAsync(); + } + } + + async function trySaveToLaserficheAsync(): Promise { + const dialog = new SaveToLaserficheCustomDialog( + spFileMetadata, + async (success) => { + if (success) { + Navigation.navigate(success.pathBack, true); + } + } + ); + + await dialog.show(); + if (!dialog.successful) { + console.warn('Could not sign in successfully'); + } + } + + async function handleLoginOrLogoutInPopupAsync(): Promise { + if (loginComponent.current.state !== LoginState.LoggedIn) { + const redirectedFromACS = + document.referrer.includes('accounts.') || + document.referrer.includes('signin.'); + const loggedOut: boolean = + loginComponent.current.state === LoginState.LoggedOut; + if (!redirectedFromACS) { + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompletedInPopup + ); + await loginComponent.current.initLoginFlowAsync(); + } else if (loggedOut && redirectedFromACS) { + if (!sentPostMessage) { + window.opener.postMessage(LOGIN_WINDOW_SUCCESS, window.origin); + sentPostMessage = true; + } + } else { + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompletedInPopup + ); + } + } else { + const logoutButton = loginComponent.current.querySelector( + '.login-button' + ) as HTMLButtonElement; + logoutButton.click(); + } + } + function getLoginText(): JSX.Element { let loginText: JSX.Element | undefined; if (!spFileMetadata) { @@ -294,15 +302,22 @@ export default function SendToLaserficheLoginComponent( loginWindow.resizeTo(800, 600); window.addEventListener('message', (event) => { if (event.origin === window.origin) { - if (event.data === 'loginWindowSuccess') { + if (event.data === LOGIN_WINDOW_SUCCESS) { loginWindow.close(); } else if (event.data) { const parsedError: AbortedLoginError = event.data; if (parsedError.ErrorMessage && parsedError.ErrorType) { loginWindow.close(); - window.alert( - `Error retrieving login credentials: ${parsedError.ErrorMessage}. Please try again.` + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> ); + setMessageErrorModal(mes); } } } @@ -347,6 +362,16 @@ export default function SendToLaserficheLoginComponent( )}
+ {messageErrorModal !== undefined && ( +
+ {messageErrorModal} +
+ )} ); }