UNPKG

cv-dialog-sdk

Version:

Catavolt Dialog Javascript API

690 lines (653 loc) 106 kB
import {BlobClientResponse} from "../client/BlobClientResponse"; import {ClientEvent} from "../client/ClientEvent"; import {ClientEventType} from "../client/ClientEventType"; import {JsonClientResponse} from "../client/JsonClientResponse"; import {TextClientResponse} from "../client/TextClientResponse"; import {VoidClientResponse} from "../client/VoidClientResponse"; import {StreamProducer} from '../io/StreamProducer'; import {ActionParametersVisitor} from "../proxy/ActionParametersVisitor"; import {ContentRedirectionVisitor} from "../proxy/ContentRedirectionVisitor"; import {DialogDelegate} from "../proxy/DialogDelegate"; import {DialogProxy} from "../proxy/DialogProxy"; import {DialogProxyTools} from "../proxy/DialogProxyTools"; import {DialogRedirectionVisitor} from "../proxy/DialogRedirectionVisitor"; import {DialogRequest} from "../proxy/DialogRequest"; import {DialogVisitor} from "../proxy/DialogVisitor"; import {LargePropertyVisitor} from "../proxy/LargePropertyVisitor"; import {LoginVisitor} from "../proxy/LoginVisitor"; import {RecordSetVisitor} from "../proxy/RecordSetVisitor"; import {RecordVisitor} from "../proxy/RecordVisitor"; import {RedirectionVisitor} from "../proxy/RedirectionVisitor"; import {SessionVisitor} from "../proxy/SessionVisitor"; import {ValueIterator} from "../proxy/ValueIterator"; import {WriteLargePropertyParametersVisitor} from "../proxy/WriteLargePropertyParametersVisitor"; import {storage as clientStorage } from "../storage"; import {Base64} from "../util/Base64"; import {Log} from '../util/Log'; import {StringDictionary} from '../util/StringDictionary'; import {BriefcaseVisitor} from "./BriefcaseVisitor"; import {Briefcase_Briefcase_FORM} from "./samples/Briefcase_Briefcase_FORM"; import {Briefcase_Briefcase_FORM_REDIRECTION} from "./samples/Briefcase_Briefcase_FORM_REDIRECTION"; import {Briefcase_EnterOfflineMode_FORM} from "./samples/Briefcase_EnterOfflineMode_FORM"; import {Briefcase_EnterOfflineMode_RECORD} from "./samples/Briefcase_EnterOfflineMode_RECORD"; import {Briefcase_EnterOfflineMode_REDIRECTION} from "./samples/Briefcase_EnterOfflineMode_REDIRECTION"; import {Documents_CreateComment_FORM} from "./samples/Documents_CreateComment_FORM"; import {Documents_CreateComment_FORM_REDIRECTION} from "./samples/Documents_CreateComment_FORM_REDIRECTION"; import {Documents_CreateComment_RECORD} from "./samples/Documents_CreateComment_RECORD"; import {MobileComment_CommentNotAvailable_FORM} from "./samples/MobileComment_CommentNotAvailable_FORM"; import {MobileComment_CommentNotAvailable_FORM_REDIRECTION} from "./samples/MobileComment_CommentNotAvailable_FORM_REDIRECTION"; import {MobileComment_CommentNotAvailable_RECORD} from "./samples/MobileComment_CommentNotAvailable_RECORD"; import {MobileComment_Details_FORM} from "./samples/MobileComment_Details_FORM"; import {MobileComment_Details_FORM_REDIRECTION} from "./samples/MobileComment_Details_FORM_REDIRECTION"; import {MobileComment_Details_RECORD} from "./samples/MobileComment_Details_RECORD"; import {MobileComment_ImageNotAvailable_FORM} from "./samples/MobileComment_ImageNotAvailable_FORM"; import {MobileComment_ImageNotAvailable_FORM_REDIRECTION} from "./samples/MobileComment_ImageNotAvailable_FORM_REDIRECTION"; import {MobileComment_ImageNotAvailable_RECORD} from "./samples/MobileComment_ImageNotAvailable_RECORD"; import {SdaPostWorkPackagesRecords1JsonSample} from "./samples/SdaPostWorkPackagesRecords1JsonSample"; import {SdaDialogDelegateStateVisitor} from "./SdaDialogDelegateStateVisitor"; import {SdaDialogDelegateTools} from "./SdaDialogDelegateTools"; import {SelectedWorkPackageVisitor} from "./SelectedWorkPackageVisitor"; import {WorkPackagesRecordSetVisitor} from "./WorkPackagesRecordSetVisitor"; // @FIX_THIS // remove this: const storage = clientStorage; // uncomment this // const storage = clientStorage.getSecureInstance(); // Set the secret key like this: // storage.secretKey = 'secret_key'; export class SdaDialogDelegate implements DialogDelegate { private static ALIAS_CREATE_COMMENT_MENU_ACTION_ID = 'alias_CreateComment'; private static ALIAS_OPEN_MENU_ACTION_ID = 'alias_Open'; private static ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID = 'alias_OpenLatestFile'; private static ALIAS_SHOW_LATEST_MENU_ACTION_ID = 'alias_ShowLatest'; private static ALIAS_SHOW_TAGS_MENU_ACTION_ID = 'alias_ShowTags'; private static OPEN_MENU_ACTION_ID = 'open'; private _dialogProxy: DialogProxy; private _dialogDelegateStateVisitor: SdaDialogDelegateStateVisitor = null; public initialize(dialogProxy: DialogProxy): Promise<void> { // Log.info("SdaDialogDelegate::initialize -- setting dialog proxy"); this._dialogProxy = dialogProxy; return Promise.resolve(); } public async isAnyUserInBriefcaseMode(tenantId: string): Promise<boolean> { const dialogDelegateStateKeys: string[] = await SdaDialogDelegateTools.readDialogDelegateStateKeys(tenantId); for (const k of dialogDelegateStateKeys) { const fields: string[] = k.split('.'); const userId = fields[0]; if (await this.isUserInBriefcaseMode({userId, tenantId})) { return true; } } } public async isUserInBriefcaseMode(userInfo: {}): Promise<boolean> { // Log.info(`SdaDialogDelegate::isUserInBriefcaseMode userInfo -- ${JSON.stringify(userInfo)}`); const userId = userInfo['userId']; const tenantId = userInfo['tenantId']; const dialogDelegateStateVisitor = await SdaDialogDelegateTools.readDialogDelegateStateVisitor(tenantId, userId); return dialogDelegateStateVisitor && dialogDelegateStateVisitor.visitBriefcase() && !dialogDelegateStateVisitor.visitBriefcase().visitOnline(); } // --- Request Handlers --- // public getBlob(request: DialogRequest): Promise<BlobClientResponse> | null { // Log.info("SdaDialogDelegate::getBlob -- path: " + request.resourcePath()); if (!this.delegateOnline()) { throw new Error(`Blob request is not valid during offline mode: ${request.resourcePath()}`); } return null; } public getText(request: DialogRequest): Promise<TextClientResponse> | null { // Log.info("SdaDialogDelegate::getText -- path: " + request.resourcePath()); if (!this.delegateOnline()) { throw new Error(`Text request is not valid during offline mode: ${request.resourcePath()}`); } return null; } public openStream(request: DialogRequest): Promise<StreamProducer> | null { // Log.info("SdaDialogDelegate::openStream -- path: " + request.resourcePath()); if (!this.delegateOnline()) { throw new Error(`Stream request is not valid during offline mode: ${request.resourcePath()}`); } return null; } public postMultipart<T>(request: DialogRequest): Promise<VoidClientResponse> | null { // Log.info("SdaDialogDelegate::postMultipart -- path: " + request); if (!this.delegateOnline()) { throw new Error(`Multipart request is not valid during offline mode: ${request.resourcePath()}`); } return null; } public getJson(request: DialogRequest): Promise<JsonClientResponse> | null { const thisMethod = 'SdaDialogDelegate::getJson'; // Log.info(`${thisMethod} -- path: ${request.resourcePath()}`); if (request.isGetDialogPath()) { const pathFields = request.deconstructGetDialogPath(); if (SdaDialogDelegateTools.isBriefcaseEnterOfflineDialogId(pathFields.dialogId)) { const response = Briefcase_EnterOfflineMode_FORM.copyOfResponse(); const enterOfflineVisitor = new DialogVisitor(response); enterOfflineVisitor.propagateTenantIdAndSessionId(pathFields.tenantId, pathFields.sessionId); enterOfflineVisitor.visitAndSetId(SdaDialogDelegateTools.BRIEFCASE_ENTER_OFFLINE_ROOT_DIALOG_ID); enterOfflineVisitor.visitChildAtNameAndSetId(SdaDialogDelegateTools.BRIEFCASE_ENTER_OFFLINE_DETAILS_DIALOG_NAME, SdaDialogDelegateTools.BRIEFCASE_ENTER_OFFLINE_DETAILS_DIALOG_ID); return Promise.resolve(new JsonClientResponse(response, 200)); } if (SdaDialogDelegateTools.isOfflineBriefcaseDialogId(pathFields.dialogId)) { const response = Briefcase_Briefcase_FORM.copyOfResponse(); const briefcaseVisitor = new DialogVisitor(response); briefcaseVisitor.propagateTenantIdAndSessionId(pathFields.tenantId, pathFields.sessionId); briefcaseVisitor.visitAndSetId(SdaDialogDelegateTools.BRIEFCASE_ROOT_DIALOG_ID); briefcaseVisitor.visitChildAtNameAndSetId(SdaDialogDelegateTools.BRIEFCASE_DETAILS_DIALOG_NAME, SdaDialogDelegateTools.BRIEFCASE_DETAILS_DIALOG_ID); briefcaseVisitor.visitChildAtNameAndSetId(SdaDialogDelegateTools.BRIEFCASE_WORK_PACKAGES_DIALOG_NAME, SdaDialogDelegateTools.BRIEFCASE_WORK_PACKAGES_DIALOG_ID); briefcaseVisitor.visitChildAtNameAndSetId(SdaDialogDelegateTools.BRIEFCASE_MOBILE_COMMENTS_DIALOG_NAME, SdaDialogDelegateTools.BRIEFCASE_COMMENTS_DIALOG_ID); return Promise.resolve(new JsonClientResponse(response, 200)); } } else if (request.isGetRecordPath()) { const pathFields = request.deconstructGetRecordPath(); if (SdaDialogDelegateTools.isBriefcaseEnterOfflineDetailsDialogId(pathFields.dialogId)) { const response = Briefcase_EnterOfflineMode_RECORD.copyOfResponse(); const recordVisitor = new RecordVisitor(response); recordVisitor.visitAndSetPropertyValueAt('P_USERID', this.delegateUserId()); return Promise.resolve(new JsonClientResponse(recordVisitor.enclosedJsonObject(), 200)); } if (SdaDialogDelegateTools.isOfflineBriefcaseDetailsDialogId(pathFields.dialogId)) { const response = this.delegateBriefcaseVisitor().enclosedJsonObject(); return Promise.resolve(new JsonClientResponse(response, 200)); } if (SdaDialogDelegateTools.isOfflineDocumentsPropertiesDialogId(pathFields.dialogId)) { return this.performOfflineDocumentsPropertiesRecordRequest(request); } if (SdaDialogDelegateTools.isOfflineTagsPropertiesDialogId(pathFields.dialogId)) { return this.performOfflineTagsPropertiesRecordRequest(request); } if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_ID) { const recordJson = MobileComment_ImageNotAvailable_RECORD.copyOfResponse(); return Promise.resolve(new JsonClientResponse(recordJson, 200)); } if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_ID) { const recordJson = MobileComment_CommentNotAvailable_RECORD.copyOfResponse(); return Promise.resolve(new JsonClientResponse(recordJson, 200)); } } if (!this.delegateOnline()) { if (request.isGetDialogPath()) { const pathFields = request.deconstructGetDialogPath(); if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_ROOT_DIALOG_ID) { const dialogJson = MobileComment_ImageNotAvailable_FORM.copyOfResponse(); const dialogVisitor = new DialogVisitor(dialogJson); dialogVisitor.visitAndSetId(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_ROOT_DIALOG_ID); dialogVisitor.propagateTenantIdAndSessionId(pathFields.tenantId, pathFields.sessionId); dialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_NAME).visitAndSetId(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_ID); dialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_NAME).visitAndSetRootDialogId(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_ROOT_DIALOG_ID); return Promise.resolve(new JsonClientResponse(dialogJson, 200)); } if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_ROOT_DIALOG_ID) { const dialogJson = MobileComment_CommentNotAvailable_FORM.copyOfResponse(); const dialogVisitor = new DialogVisitor(dialogJson); dialogVisitor.visitAndSetId(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_ROOT_DIALOG_ID); dialogVisitor.propagateTenantIdAndSessionId(pathFields.tenantId, pathFields.sessionId); dialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_NAME).visitAndSetId(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_ID); dialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_NAME).visitAndSetRootDialogId(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_ROOT_DIALOG_ID); return Promise.resolve(new JsonClientResponse(dialogJson, 200)); } return DialogProxyTools.readDialogAsOfflineResponse(this.delegateUserId(), request); } if (request.isGetRecordPath()) { return DialogProxyTools.readRecordAsOfflineResponse(this.delegateUserId(), request); } return Promise.resolve(DialogProxyTools.constructRequestNotValidDuringOfflineMode('getJson', request.resourcePath())); } return null; } public postJson(request: DialogRequest): Promise<JsonClientResponse> | null { const thisMethod = 'SdaDialogDelegate::postJson'; // Log.info(`${thisMethod} -- path: ${request.resourcePath()}`); // Log.info(`${thisMethod} -- body: ${JSON.stringify(request.body())}`); if (SdaDialogDelegateTools.isWorkPackagesAddToBriefcaseMenuActionRequest(request)) { return this.performWorkPackagesAddWorkPackageToBriefcase(request); } else if (SdaDialogDelegateTools.isWorkPackagesRemoveFromBriefcaseMenuActionRequest(request)) { return this.performWorkPackagesRemoveWorkPackageFromBriefcase(request); } else if (request.isCreateSessionPath()) { return this.performCreateSessionRequest(request); } else if (SdaDialogDelegateTools.isBriefcaseWorkbenchActionRequest(request)) { return this.performBriefcaseWorkbenchActionRequest(request); } else if (SdaDialogDelegateTools.isOfflineBriefcaseWorkPackagesRequest(request)) { return this.performOfflineBriefcaseWorkPackagesRequest(request); } else if (SdaDialogDelegateTools.isOfflineBriefcaseCommentsRecordSetRequest(request)) { return this.performOfflineBriefcaseCommentsRequest(request); } else if (SdaDialogDelegateTools.isEnterOfflineModeMenuActionRequest(request)) { return this.performEnterOfflineModeMenuActionRequest(request); } else if (SdaDialogDelegateTools.isExitOfflineModeMenuActionRequest(request)) { return this.performExitOfflineModeMenuActionRequest(request); } if (!this.delegateOnline()) { if (request.isPostWorkbenchActionPath()) { return DialogProxyTools.readWorkbenchActionRedirectionAsOfflineResponse(this.delegateUserId(), request); } else if (request.isPostMenuActionPath()) { if (request.actionId() === 'alias_ShowDocs') { return this.performOfflineShowDocsMenuAction(request); } else if (request.actionId() === SdaDialogDelegate.ALIAS_CREATE_COMMENT_MENU_ACTION_ID) { return this.performOfflineCreateCommentMenuAction(request); } else if (request.actionId() === SdaDialogDelegate.ALIAS_SHOW_LATEST_MENU_ACTION_ID) { return this.performOfflineShowLatestMenuAction(request); } else if (request.actionId() === SdaDialogDelegate.ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID) { return DialogProxyTools.readMenuActionRedirectionAsVisitor(this.delegateUserId(), request).then(dialogRedirectionVisitor => { if (dialogRedirectionVisitor) { return new JsonClientResponse(dialogRedirectionVisitor.enclosedJsonObject(), 303); } else { // return new JsonClientResponse(DialogProxyTools.constructDialogMessageModel('Latest file not found'), 400); const pathFields = request.deconstructPostMenuActionPath(); const dialogRedirection = MobileComment_ImageNotAvailable_FORM_REDIRECTION.copyOfResponse(); DialogRedirectionVisitor.propagateDialogId(dialogRedirection, SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_ROOT_DIALOG_ID); DialogRedirectionVisitor.propagateTenantIdAndSessionId(dialogRedirection, pathFields.tenantId, pathFields.sessionId); return new JsonClientResponse(dialogRedirection, 303); } }); } return DialogProxyTools.readMenuActionRedirectionAsOfflineResponse(this.delegateUserId(), request); } else if (request.isPostRecordsPath()) { return DialogProxyTools.readRecordSetAsOfflineResponse(this.delegateUserId(), request); } else if (request.isPostSessionContentPath()) { return DialogProxyTools.readSessionContentAsOfflineResponse(this.delegateUserId(), request); } return Promise.resolve(DialogProxyTools.constructRequestNotValidDuringOfflineMode('postJson', request.resourcePath())); } return null; } public putJson(request: DialogRequest): Promise<JsonClientResponse> | null { // Log.info("SdaDialogDelegate::putJson -- path: " + request.resourcePath()); // Log.info("SdaDialogDelegate::putJson -- body: " + JSON.stringify(request.body())); if (request.isPutViewModePath()) { const pathFields = request.deconstructPutViewModePath(); if (SdaDialogDelegateTools.isBriefcaseEnterOfflineDetailsDialogId(pathFields.dialogId) && pathFields.viewMode === 'READ') { return Promise.resolve(new JsonClientResponse(SdaDialogDelegateTools.constructBriefcaseEnterOfflineDetailsNullRedirection(pathFields.tenantId, pathFields.sessionId, false), 303)); } } if (request.isPutRecordPath()) { const pathFields = request.deconstructPostRecordsPath(); if (SdaDialogDelegateTools.isBriefcaseEnterOfflineDetailsDialogId(pathFields.dialogId)) { const recordVisitor = new RecordVisitor(request.body()); const loginHash = SdaDialogDelegateTools.createOfflineLoginHash(pathFields.tenantId, pathFields.sessionId, this.delegateUserId(), recordVisitor.visitPropertyValueAt('P_PASSWORD')); // Log.info("SdaDialogDelegate::putJson -- loginHash: " + loginHash); this._dialogDelegateStateVisitor.visitAndSetLoginHash(loginHash); return this.performEnterOfflineModeContinueRequest(request.baseUrl(), pathFields.tenantId, pathFields.sessionId); } } if (!this.delegateOnline()) { if (request.isPutViewModePath()) { const pathFields = request.deconstructPutViewModePath(); if (pathFields.dialogId.startsWith('Documents_CreateComment$') && pathFields.viewMode === 'READ') { return Promise.resolve(this.constructCreateCommentNullRedirection(pathFields.tenantId, pathFields.sessionId, pathFields.dialogId)); } if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_ID) { const nullRedirection = DialogProxyTools.constructNullRedirection(pathFields.tenantId, pathFields.sessionId); const nullRedirectionVisitor = new RedirectionVisitor(nullRedirection); nullRedirectionVisitor.visitAndSetReferringDialogAlias(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_NAME); nullRedirectionVisitor.visitAndSetReferringDialogName(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_NAME); nullRedirectionVisitor.visitAndSetReferringDialogId(SdaDialogDelegateTools.MOBILE_COMMENT_IMAGE_NOT_AVAILABLE_DETAILS_DIALOG_ID); nullRedirectionVisitor.visitAndSetReferringDialogMode('DESTROYED'); return Promise.resolve(new JsonClientResponse(nullRedirectionVisitor.enclosedJsonObject(), 303)); } if (pathFields.dialogId === SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_ID) { const nullRedirection = DialogProxyTools.constructNullRedirection(pathFields.tenantId, pathFields.sessionId); const nullRedirectionVisitor = new RedirectionVisitor(nullRedirection); nullRedirectionVisitor.visitAndSetReferringDialogAlias(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_NAME); nullRedirectionVisitor.visitAndSetReferringDialogName(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_NAME); nullRedirectionVisitor.visitAndSetReferringDialogId(SdaDialogDelegateTools.MOBILE_COMMENT_COMMENT_NOT_AVAILABLE_DETAILS_DIALOG_ID); nullRedirectionVisitor.visitAndSetReferringDialogMode('DESTROYED'); return Promise.resolve(new JsonClientResponse(nullRedirectionVisitor.enclosedJsonObject(), 303)); } return null; } if (request.isPutRecordPath()) { const pathFields = request.deconstructPutRecordPath(); const recordVisitor = new RecordVisitor(request.body()); return DialogProxyTools.writeRecordCommit(this.delegateUserId(), pathFields.tenantId, pathFields.dialogId, recordVisitor).then(nullValue => { this._dialogDelegateStateVisitor.visitMobileCommentsRecordSet().acceptCreateComment(pathFields.dialogId, recordVisitor); return SdaDialogDelegateTools.writeDialogDelegateState(pathFields.tenantId, this._dialogDelegateStateVisitor).then(nullValue2 => { return this.constructCreateCommentNullRedirection(pathFields.tenantId, pathFields.sessionId, pathFields.dialogId); }); }); } if (request.isPutPropertyPath()) { const pathFields = request.deconstructPutPropertyPath(); const writeLargePropertyParameters = new WriteLargePropertyParametersVisitor(request.body()); return DialogProxyTools.writePropertyCommit(this.delegateUserId(), pathFields.tenantId, pathFields.dialogId, pathFields.propertyName, writeLargePropertyParameters).then(nullValue => { return this.constructCreateCommentNullRedirection(pathFields.tenantId, pathFields.sessionId, pathFields.dialogId); }); } return Promise.resolve(DialogProxyTools.constructRequestNotValidDuringOfflineMode('putJson', request.resourcePath())); } return null; } public deleteJson(request: DialogRequest): Promise<JsonClientResponse> | null { // Log.info("SdaDialogDelegate::deleteJson -- path: " + request.resourcePath()); if (request.isDeleteSessionPath()) { return this.performDeleteSessionRequest(request); } // Whether online or offline, we need to short-circuit the deletion of briefcase dialogs. The briefcase dialogs // are 100% client-side only and are synthesized for each use. if (request.isDeleteDialogPath() && SdaDialogDelegateTools.startsWithBriefcaseRootDialogId(request.dialogId())) { const response = { "dialogId": request.dialogId(), "type": "hxgn.api.dialog.DialogId" }; return Promise.resolve(new JsonClientResponse(response, 200)); } if (!this.delegateOnline()) { const pathFields = request.deconstructDeleteDialogPath(); if (request.isDeleteDialogPath()) { const response = { "dialogId": pathFields.dialogId, "type": "hxgn.api.dialog.DialogId" }; return Promise.resolve(new JsonClientResponse(response, 200)); } return Promise.resolve(DialogProxyTools.constructRequestNotValidDuringOfflineMode('deleteJson', request.resourcePath())); } return null; } // --- Response Handlers --- // public handleDeleteJsonResponse(request: DialogRequest, response: Promise<JsonClientResponse>): Promise<JsonClientResponse> | null { // Log.info("SdaDialogDelegate::handleDeleteJsonResponse -- path: " + request.resourcePath()); // response.then(jcr => Log.info("SdaDialogDelegate::handleDeleteJsonResponse -- json response: " + JSON.stringify(jcr.value))); return response; } public handleGetBlobResponse(request: DialogRequest, response: Promise<BlobClientResponse>): Promise<BlobClientResponse> | null { // Log.info("SdaDialogDelegate::handleGetBlobResponse -- path: " + request.resourcePath()); // response.then(bcr => Log.info("SdaDialogDelegate::handleGetBlobResponse -- blob response: " + JSON.stringify(bcr.value))); return response; } public handleGetJsonResponse(request: DialogRequest, response: Promise<JsonClientResponse>): Promise<JsonClientResponse> | null { // Log.info("SdaDialogDelegate::handleGetJsonResponse -- path: " + request.resourcePath()); // response.then(jcr => Log.info("SdaDialogDelegate::handleGetJsonResponse -- json response: " + JSON.stringify(jcr.value))); return response.then(jcr => { if (jcr.statusCode === 200) { const jsonObject = jcr.value as StringDictionary; if (SdaDialogDelegateTools.isWorkPackagesRootDialog(jsonObject)) { const workPackagesDialog = SdaDialogDelegateTools.insertBriefcaseMetaDataIntoWorkPackagesDialog(jsonObject); return new JsonClientResponse(workPackagesDialog, 200); } } return jcr; }); } public handleGetTextResponse(request: DialogRequest, response: Promise<TextClientResponse>): Promise<TextClientResponse> | null { // Log.info("SdaDialogDelegate::handleGetTextResponse -- path: " + request.resourcePath()); // response.then(tcr => Log.info("SdaDialogDelegate::handleGetTextResponse -- text response: " + JSON.stringify(tcr.value))); return response; } public handleOpenStreamResponse(request: DialogRequest, response: Promise<StreamProducer>): Promise<StreamProducer> | null { // Log.info("SdaDialogDelegate::handleOpenStreamResponse -- path: " + request.resourcePath()); // response.then(sp => Log.info("SdaDialogDelegate::handleOpenStreamResponse -- stream producer response: " + sp)); return response; } public handlePostJsonResponse(request: DialogRequest, response: Promise<JsonClientResponse>): Promise<JsonClientResponse> | null { const thisMethod = 'SdaDialogDelegate::handlePostJsonResponse'; // Log.info(`${thisMethod} -- path: ${request.resourcePath()}`); // response.then(jcr => Log.info(`${thisMethod} -- json response: ${JSON.stringify(jcr.value)}`)); return response.then(jsonClientResponse => { if (jsonClientResponse.statusCode === 200) { const jsonObject = jsonClientResponse.value as StringDictionary; if (DialogProxyTools.isSessionModel(jsonObject)) { return this.initializeAfterCreateSession(request, new SessionVisitor(jsonObject)).then(nullValue => jsonClientResponse); } else if (SdaDialogDelegateTools.isWorkPackagesListRecordSet(request, jsonObject)) { if (this.delegateOnline()) { const pathFields = request.deconstructPostRecordsPath(); const workPackagesRecordSetVisitor = new WorkPackagesRecordSetVisitor(jsonObject); workPackagesRecordSetVisitor.updateBriefcaseColumnUsingSelections(this.delegateSelectedWorkPackageIds()); this.delegateWorkPackagesRecordSetVisitor().addOrUpdateAllRecords(workPackagesRecordSetVisitor); return SdaDialogDelegateTools.writeDialogDelegateState(pathFields.tenantId, this._dialogDelegateStateVisitor).then(nullValue => { return jsonClientResponse; }); } } } return jsonClientResponse; }); } public handlePostMultipartResponse<T>(request: DialogRequest, response: Promise<VoidClientResponse>): Promise<VoidClientResponse> | null { // Log.info("SdaDialogDelegate::handlePostMultipartResponse -- path: " + request.resourcePath()); // response.then(vcr => Log.info("SdaDialogDelegate::handlePostMultipartResponse -- void response: " + JSON.stringify(vcr.value))); return response; } public handlePutJsonResponse(request: DialogRequest, response: Promise<JsonClientResponse>): Promise<JsonClientResponse> | null { const thisMethod = 'SdaDialogDelegate::handlePutJsonResponse'; // Log.info("SdaDialogDelegate::handlePutJsonResponse -- path: " + request.resourcePath()); // response.then(jcr => Log.info(`${thisMethod} -- json response: ${JSON.stringify(jcr.statusCode)} ${JSON.stringify(jcr.value)}`)); return response; } // --- Others --- // private async captureOfflineSession(baseUrl: string, tenantId: string, sessionId: string): Promise<JsonClientResponse> { const thisMethod = 'SdaDialogDelegate::captureOfflineSession'; this.notifyClientListener({message: 'Capturing session for offline', eventType: ClientEventType.MESSAGE}); const resourcePath = `tenants/${tenantId}/sessions/${sessionId}`; const sessionJcr = await DialogProxyTools.commonFetchClient().getJson(baseUrl, resourcePath); // Log.info(`${thisMethod} -- session value: ${JSON.stringify(sessionJcr.value)}`); const sessionVisitor = new SessionVisitor(sessionJcr.value); await SdaDialogDelegateTools.writeOfflineSession(tenantId, this.delegateUserId(), sessionVisitor); return sessionJcr; } private async captureNextOfflineWorkPackage(baseUrl: string, tenantId: string, sessionId: string, onlineWorkPackagesListDialogId: string, offlineWorkPackagesListDialogId: string, nextWorkPackageId: string): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureNextOfflineWorkPackage'; // Log.info(`${thisMethod} -- capturing work package for offline: ${nextWorkPackageId}`); this.notifyClientListener({ // message: `Capturing work package: ${nextWorkPackageId}`, message: `Capturing work package`, eventType: ClientEventType.MESSAGE }); const beforeAndAfterValues = await DialogProxyTools.captureMenuActionRedirectionAndDialog(this.delegateUserId(), baseUrl, tenantId, sessionId, onlineWorkPackagesListDialogId, offlineWorkPackagesListDialogId, SdaDialogDelegate.ALIAS_OPEN_MENU_ACTION_ID, nextWorkPackageId); await DialogProxyTools.captureRecord(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.DOCUMENTS_PROPERTIES_DIALOG_NAME); const documentsRecordSetVisitor = await DialogProxyTools.captureRecordSet(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.DOCUMENTS_LIST_DIALOG_NAME); const beforeDocumentsListDialog = (new DialogVisitor(beforeAndAfterValues.beforeDialog)).visitChildAtName(SdaDialogDelegateTools.DOCUMENTS_LIST_DIALOG_NAME); const afterDocumentsListDialog = (new DialogVisitor(beforeAndAfterValues.afterDialog)).visitChildAtName(SdaDialogDelegateTools.DOCUMENTS_LIST_DIALOG_NAME); for (const r of documentsRecordSetVisitor.visitRecords()) { await this.captureNextOfflineDocumentContent(baseUrl, tenantId, sessionId, beforeDocumentsListDialog, afterDocumentsListDialog, r); await this.captureNextOfflineLastComment(baseUrl, tenantId, sessionId, beforeDocumentsListDialog, afterDocumentsListDialog, r); } await this.captureNextOfflineTags(baseUrl, tenantId, sessionId, beforeDocumentsListDialog, afterDocumentsListDialog, nextWorkPackageId); return null; } private async captureNextOfflineTags(baseUrl: string, tenantId: string, sessionId: string, beforeDocumentsListDialog: DialogVisitor, afterDocumentsListDialog: DialogVisitor, nextWorkPackageId: string): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureNextOfflineTags'; // Log.info(`${thisMethod} -- capturing tags for offline: ${nextWorkPackageId}`); this.notifyClientListener({ // message: `Capturing tags: ${nextWorkPackageId}`, message: `Capturing tags`, eventType: ClientEventType.MESSAGE }); const beforeAndAfterValues = await DialogProxyTools.captureMenuActionRedirectionAndDialog(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeDocumentsListDialog.visitId(), afterDocumentsListDialog.visitId(), SdaDialogDelegate.ALIAS_SHOW_TAGS_MENU_ACTION_ID, null); await DialogProxyTools.captureRecord(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.TAGS_PROPERTIES_DIALOG_NAME); const tagsRecordSetVisitor = await DialogProxyTools.captureRecordSet(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.TAGS_LIST_DIALOG_NAME); const beforeTagsListDialog = (new DialogVisitor(beforeAndAfterValues.beforeDialog)).visitChildAtName(SdaDialogDelegateTools.TAGS_LIST_DIALOG_NAME); const afterTagsListDialog = (new DialogVisitor(beforeAndAfterValues.afterDialog)).visitChildAtName(SdaDialogDelegateTools.TAGS_LIST_DIALOG_NAME); for (const r of tagsRecordSetVisitor.visitRecords()) { await this.captureNextOfflineTag(baseUrl, tenantId, sessionId, beforeTagsListDialog, afterTagsListDialog, r); await this.captureNextOfflineLastComment(baseUrl, tenantId, sessionId, beforeTagsListDialog, afterTagsListDialog, r); } return null; } private async captureNextOfflineTag(baseUrl: string, tenantId: string, sessionId: string, beforeTagsListDialog: DialogVisitor, afterTagsListDialog: DialogVisitor, nextTagRecordVisitor: RecordVisitor): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureNextOfflineTag'; const nextTagRecordId = nextTagRecordVisitor.visitRecordId(); // Log.info(`${thisMethod} -- capturing tag for offline: ${nextTagRecordId}`); this.notifyClientListener({ // message: `Capturing tag: ${nextTagRecordId}`, message: `Capturing tag`, eventType: ClientEventType.MESSAGE }); const beforeAndAfterValues = await DialogProxyTools.captureMenuActionRedirectionAndDialog(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeTagsListDialog.visitId(), afterTagsListDialog.visitId(), SdaDialogDelegate.OPEN_MENU_ACTION_ID, nextTagRecordId); await DialogProxyTools.captureRecord(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.TAG_DETAILS_PROPERTIES_DIALOG_NAME); // const tagDetailsListRecordSetVisitor = await DialogProxyTools.captureRecordSet(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.TAG_DETAILS_LIST_DIALOG_NAME); // const beforeTagDetailsListDialog = (new DialogVisitor(beforeAndAfterValues.beforeDialog)).visitChildAtName(SdaDialogDelegateTools.TAG_DETAILS_LIST_DIALOG_NAME); // const afterTagDetailsListDialog = (new DialogVisitor(beforeAndAfterValues.afterDialog)).visitChildAtName(SdaDialogDelegateTools.TAG_DETAILS_LIST_DIALOG_NAME); // for (const r of tagDetailsListRecordSetVisitor.visitRecords()) { // await this.captureNextOfflineDocumentContent(baseUrl, tenantId, sessionId, beforeTagDetailsListDialog, afterTagDetailsListDialog, r); // await this.captureNextOfflineLastComment(baseUrl, tenantId, sessionId, beforeTagDetailsListDialog, afterTagDetailsListDialog, r); // } return null; } private async captureNextOfflineDocumentContent(baseUrl: string, tenantId: string, sessionId: string, beforeDocumentsListDialog: DialogVisitor, afterDocumentsListDialog: DialogVisitor, nextDocumentRecordVisitor: RecordVisitor): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureNextOfflineDocumentContent'; const onlineDocumentsListDialogId = beforeDocumentsListDialog.visitId(); const offlineDocumentsListDialogId = afterDocumentsListDialog.visitId(); // Log.info(`${thisMethod} -- online list dialog id: ${onlineDocumentsListDialogId}`); // Log.info(`${thisMethod} -- offline list dialog id: ${offlineDocumentsListDialogId}`); // GET REDIRECTION // const nextDocumentId = nextDocumentRecordVisitor.visitRecordId(); this.notifyClientListener({ // message: `Capturing document: ${nextDocumentId}`, message: `Capturing document`, eventType: ClientEventType.MESSAGE }); const nextDocumentIdEncoded = Base64.encodeUrlSafeString(nextDocumentId); // Log.info(`${thisMethod} -- next document id: ${nextDocumentId} encoded as: ${nextDocumentIdEncoded}`); const redirectionPath = `tenants/${tenantId}/sessions/${sessionId}/dialogs/${onlineDocumentsListDialogId}/actions/${SdaDialogDelegate.ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID}`; const redirectionParameters = { targets: [nextDocumentId], type: "hxgn.api.dialog.ActionParameters" }; const redirectionJcr = await DialogProxyTools.commonFetchClient().postJson(baseUrl, redirectionPath, redirectionParameters); if (redirectionJcr.statusCode !== 303) { throw new Error(`Unexpected result when opening Document: ${nextDocumentId}`); } // TODO: this is a hack for "document not found" scenario -- fix later if (redirectionJcr.value['type'] === 'hxgn.api.dialog.DialogRedirection') { // Log.info(`${thisMethod} -- skipping dialog redirection (document not found): ${JSON.stringify(redirectionJcr.value)}`); return null; } // Log.info(`${thisMethod} -- document content redirection: ${JSON.stringify(redirectionJcr.value)}`); // CLARIFICATION: We can navigate to the same document from multiple locations, therefore documents are shared // among entities by reference. Specifically a work package and tag can share the same document. We capitalize // on this fact by rewriting the content redirection identifier as derivative of the document id. The effect // allows us to determine if we have already downloaded the content, and if we have, to reference the same // content from multiple redirections. const contentRedirectionVisitor = new ContentRedirectionVisitor(redirectionJcr.value); const onlineContentId = contentRedirectionVisitor.visitId(); const offlineContentId = `content_redirection_${nextDocumentIdEncoded}`; contentRedirectionVisitor.visitAndSetId(offlineContentId); const actionIdAtRecordId = `${SdaDialogDelegate.ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID}@${nextDocumentIdEncoded}`; await DialogProxyTools.writeContentRedirection(this.delegateUserId(), tenantId, offlineDocumentsListDialogId, actionIdAtRecordId, contentRedirectionVisitor); const largePropertyExists = await DialogProxyTools.readSessionContentAsVisitor(this.delegateUserId(), tenantId, offlineContentId, 0); if (largePropertyExists) { // If the document has been previously captured from a shared reference, then we are done return null; } // GET AND WRITE CONTENT TO LOCAL STORAGE // let nextSequence = 0; while (true) { const contentPath = `tenants/${tenantId}/sessions/${sessionId}/content/${onlineContentId}`; const readLargePropertyParametersJson = { maxBytes: 131072, sequence: nextSequence, type: "hxgn.api.dialog.ReadLargePropertyParameters" }; const largePropertyJcr = await DialogProxyTools.commonFetchClient().postJson(this._dialogDelegateStateVisitor.visitBaseUrl(), contentPath, readLargePropertyParametersJson); if (largePropertyJcr.statusCode !== 200) { throw new Error(`Unexpected result when reading content: ${onlineContentId}`); } const largePropertyVisitor = new LargePropertyVisitor(largePropertyJcr.value); await DialogProxyTools.writeContentChunk(this.delegateUserId(), tenantId, offlineContentId, nextSequence, largePropertyVisitor); if (!largePropertyVisitor.visitHasMore()) { break; } nextSequence++; } return null; } private async captureNextOfflineLastComment(baseUrl: string, tenantId: string, sessionId: string, beforeDocumentsListDialog: DialogVisitor, afterDocumentsListDialog: DialogVisitor, nextDocumentRecordVisitor: RecordVisitor): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureNextOfflineLastComment'; const nextDocumentRecordId = nextDocumentRecordVisitor.visitRecordId(); // Log.info(`${thisMethod} -- capturing last comment: ${nextDocumentRecordId}`); this.notifyClientListener({ // message: `Capturing last comment at document id: ${nextDocumentRecordId}`, message: `Capturing last comment for document`, eventType: ClientEventType.MESSAGE }); const beforeAndAfterValues = await DialogProxyTools.captureMenuActionRedirectionAndDialog(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeDocumentsListDialog.visitId(), afterDocumentsListDialog.visitId(), SdaDialogDelegate.ALIAS_SHOW_LATEST_MENU_ACTION_ID, nextDocumentRecordId); const beforeDialogVisitor = new DialogVisitor(beforeAndAfterValues.beforeDialog); const beforePropertiesDialogVisitor = beforeDialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_DETAILS_PROPERTIES_DIALOG_NAME); if (beforeDialogVisitor.visitDialogName() !== SdaDialogDelegateTools.MOBILE_COMMENT_DETAILS_ROOT_DIALOG_NAME) { return; } const afterDialogVisitor = new DialogVisitor(beforeAndAfterValues.afterDialog); const afterPropertiesDialogVisitor = afterDialogVisitor.visitChildAtName(SdaDialogDelegateTools.MOBILE_COMMENT_DETAILS_PROPERTIES_DIALOG_NAME); // Log.info(`${thisMethod} -- last comment before dialog id: ${beforePropertiesDialogVisitor.visitId()}`); // Log.info(`${thisMethod} -- last comment after dialog id: ${afterPropertiesDialogVisitor.visitId()}`); await DialogProxyTools.captureRecord(this.delegateUserId(), baseUrl, tenantId, sessionId, beforeAndAfterValues, SdaDialogDelegateTools.MOBILE_COMMENT_DETAILS_PROPERTIES_DIALOG_NAME); const lastCommentRecordId = beforeDialogVisitor.visitRecordId(); const lastCommentRecordIdEncoded = Base64.encodeUrlSafeString(lastCommentRecordId); // Log.info(`${thisMethod} -- last comment record id: ${lastCommentRecordId} encoded as: ${lastCommentRecordIdEncoded}`); const redirectionPath = `tenants/${tenantId}/sessions/${sessionId}/dialogs/${beforePropertiesDialogVisitor.visitId()}/actions/${SdaDialogDelegate.ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID}`; const redirectionParameters = { targets: [], type: "hxgn.api.dialog.ActionParameters" }; const redirectionJcr = await DialogProxyTools.commonFetchClient().postJson(baseUrl, redirectionPath, redirectionParameters); if (redirectionJcr.statusCode !== 303) { throw new Error(`Unexpected result when opening Last Comment: ${nextDocumentRecordId}`); } // TODO: this is a hack for "document not found" scenario -- fix later if (redirectionJcr.value['type'] === 'hxgn.api.dialog.DialogRedirection') { // Log.info(`${thisMethod} -- skipping dialog redirection (latest document not found): ${JSON.stringify(redirectionJcr.value)}`); return null; } // Log.info(`${thisMethod} -- last comment content redirection: ${JSON.stringify(redirectionJcr.value)}`); const contentRedirectionVisitor = new ContentRedirectionVisitor(redirectionJcr.value); const onlineContentId = contentRedirectionVisitor.visitId(); const offlineContentId = `content_redirection_${lastCommentRecordIdEncoded}`; contentRedirectionVisitor.visitAndSetId(offlineContentId); await DialogProxyTools.writeContentRedirection(this.delegateUserId(), tenantId, afterPropertiesDialogVisitor.visitId(), SdaDialogDelegate.ALIAS_OPEN_LATEST_FILE_MENU_ACTION_ID, contentRedirectionVisitor); // GET AND WRITE CONTENT TO LOCAL STORAGE // let nextSequence = 0; while (true) { const contentPath = `tenants/${tenantId}/sessions/${sessionId}/content/${onlineContentId}`; const readLargePropertyParametersJson = { maxBytes: 131072, sequence: nextSequence, type: "hxgn.api.dialog.ReadLargePropertyParameters" }; const largePropertyJcr = await DialogProxyTools.commonFetchClient().postJson(this._dialogDelegateStateVisitor.visitBaseUrl(), contentPath, readLargePropertyParametersJson); if (largePropertyJcr.statusCode !== 200) { throw new Error(`Unexpected result when reading content: ${onlineContentId}`); } const largePropertyVisitor = new LargePropertyVisitor(largePropertyJcr.value); await DialogProxyTools.writeContentChunk(this.delegateUserId(), tenantId, offlineContentId, nextSequence, largePropertyVisitor); if (!largePropertyVisitor.visitHasMore()) { break; } nextSequence++; } return null; } private async captureOfflineWorkPackages(baseUrl: string, tenantId: string, sessionId: string): Promise<void> { const thisMethod = 'SdaDialogDelegate::captureOfflineWorkPackages'; // CAPTURE OFFLINE WORK PACKAGES REDIRECTION AND ROOT DIALOG // Log.info(`${thisMethod} -- capturing work packages list for offline`); const userId = this.delegateUserId(); const beforeAndAfterValues = await DialogProxyTools.captureWorkbenchActionRedirectionAndDialog(userId, baseUrl, tenantId, sessionId, 'SDAWorkbench', 'WorkPackages'); // CAPTURE OFFLINE WORK PACKAGES RECORD SET // Log.info(`${thisMethod} -- capturing selected work packages for offline`); const dialogVisitor = new DialogVisitor(beforeAndAfterValues.beforeDialog); const listDialogVisitor = dialogVisitor.visitChildAtName(SdaDialogDelegateTools.WORK_PACKAGES_LIST_DIALOG_NAME); const listDialogId = listDialogVisitor.visitId(); const sampleRecordSet = SdaPostWorkPackagesRecords1JsonSample.copyOfResponse(); const recordSetVisitor = new RecordSetVisitor(sampleRecordSet); recordSetVisitor.visitAndClearRecords(); recordSetVisitor.visitAndSetHasMore(false); for (const wpv of this.delegateWorkPackagesRecordSetVisitor().visitRecords()) { if (wpv.visitBriefcase()) { recordSetVisitor.addOrUpdateRecord(wpv); } } await DialogProxyTools.writeRecordSet(userId, tenantId, SdaDialogDelegateTools.WORK_PACKAGES_LIST_DIALOG_NAME, recordSetVisitor); const workPackageIdsIterator = new ValueIterator(this.delegateSelectedWorkPackageIds()); while (!workPackageIdsIterator.done()) { await this.captureNextOfflineWorkPackage(baseUrl, tenantId, sessionId, listDialogId, SdaDialogDelegateTools.WORK_PACKAGES_LIST_DIALOG_NAME, workPackageIdsIterator.next()); } } private constructCreateCommentNullRedirection(tenantId: string, sessionId: string, dialogId: string): JsonClientResponse { const nullRedirection = DialogProxyTools.constructNullRedirection(tenantId, sessionId); const nullRedirectionVisitor = new RedirectionVisitor(nullRedirection); nullRedirectionVisitor.visitAndSetReferringDialogAlias('Documents_CreateComment'); nullRedirectionVisitor.visitAndSetReferringDialogName('Documents_CreateComment'); nullRedirectionVisitor.visitAndSetReferringDialogId(dialogId); nullRedirectionVisitor.visitAndSetReferringDialogMode('DESTROYED');