diff --git a/src/web/client/WebExtensionContext.ts b/src/web/client/WebExtensionContext.ts index ec8f8ae6..e355ca5b 100644 --- a/src/web/client/WebExtensionContext.ts +++ b/src/web/client/WebExtensionContext.ts @@ -367,7 +367,8 @@ class WebExtensionContext implements IWebExtensionContext { attributePath: IAttributePath, attributeContent: string, mappingEntityId?: string, - fileUri?: string + fileUri?: string, + rootWebPageId?: string, ) { this.entityDataMap.setEntity( entityId, @@ -376,7 +377,8 @@ class WebExtensionContext implements IWebExtensionContext { attributePath, attributeContent, mappingEntityId, - fileUri); + fileUri, + rootWebPageId); } public async updateSingleFileUrisInContext(uri: vscode.Uri) { diff --git a/src/web/client/context/entityData.ts b/src/web/client/context/entityData.ts index de1894d5..e32be9d5 100644 --- a/src/web/client/context/entityData.ts +++ b/src/web/client/context/entityData.ts @@ -19,6 +19,7 @@ export class EntityData implements IEntityData { private _entityColumn!: Map; private _mappingEntityId?: string; private _filePath?: Set; + private _rootWebPageId?: string; public get entityName(): string { return this._entityName; @@ -38,6 +39,9 @@ export class EntityData implements IEntityData { public get filePath(): Set | undefined { return this._filePath; } + public get rootWebPageId(): string | undefined { + return this._rootWebPageId; + } // Setters public set setEntityEtag(value: string) { @@ -50,7 +54,8 @@ export class EntityData implements IEntityData { entityEtag: string, entityColumn: Map, mappingEntityId?: string, - filePath?: Set + filePath?: Set, + rootWebPageId?: string ) { this._entityId = entityId; this._entityName = entityName; @@ -58,5 +63,6 @@ export class EntityData implements IEntityData { this._entityColumn = entityColumn; this._mappingEntityId = mappingEntityId; this._filePath = filePath; + this._rootWebPageId = rootWebPageId; } } diff --git a/src/web/client/context/entityDataMap.ts b/src/web/client/context/entityDataMap.ts index ea570b4b..b856e8fc 100644 --- a/src/web/client/context/entityDataMap.ts +++ b/src/web/client/context/entityDataMap.ts @@ -35,7 +35,8 @@ export class EntityDataMap { attributePath: IAttributePath, attributeContent: string, mappingEntityId?: string, - fileUri?: string + fileUri?: string, + rootWebPageId?: string ) { let entityColumnMap = new Map(); const existingEntity = this.entityMap.get(entityId); @@ -56,7 +57,8 @@ export class EntityDataMap { odataEtag, entityColumnMap, mappingEntityId, - filePath + filePath, + rootWebPageId ); this.entityMap.set(entityId, entityData); } diff --git a/src/web/client/dal/remoteFetchProvider.ts b/src/web/client/dal/remoteFetchProvider.ts index e4e2948a..6c6b9727 100644 --- a/src/web/client/dal/remoteFetchProvider.ts +++ b/src/web/client/dal/remoteFetchProvider.ts @@ -6,8 +6,8 @@ import * as vscode from "vscode"; import { convertContentToUint8Array, - GetFileContent, GetFileNameWithExtension, + getAttributeContent, getSanitizedFileName, isPortalVersionV1, isPortalVersionV2, @@ -271,6 +271,10 @@ async function createContentFiles( } const attributeArray = attributes.split(","); + + // Get rootpage id Attribute + const rootWebPageIdAttribute = entityDetails?.get(schemaEntityKey.ROOT_WEB_PAGE_ID); + await processDataAndCreateFile(attributeArray, attributeExtension, entityName, @@ -282,7 +286,8 @@ async function createContentFiles( languageCode, filePathInPortalFS, portalsFS, - defaultFileInfo) + defaultFileInfo, + rootWebPageIdAttribute) } catch (error) { const errorMsg = (error as Error)?.message; @@ -312,6 +317,7 @@ async function processDataAndCreateFile( filePathInPortalFS: string, portalsFS: PortalsFS, defaultFileInfo?: IFileInfo, + rootWebPageIdAttribute?: string ) { const attributeExtensionMap = attributeExtension as unknown as Map< string, @@ -330,7 +336,7 @@ async function processDataAndCreateFile( ); if (fileExtension === undefined) { - const expandedContent = GetFileContent(result, attributePath, entityName, entityId); + const expandedContent = getAttributeContent(result, attributePath, entityName, entityId); if (expandedContent !== Constants.NO_CONTENT) { await processExpandedData( @@ -351,6 +357,14 @@ async function processDataAndCreateFile( fileNameWithExtension = defaultFileInfo?.fileName; } + // Get rootpage id + let rootWebPageId = undefined; + + if (rootWebPageIdAttribute) { + const rootWebPageIdPath : IAttributePath = getAttributePath(rootWebPageIdAttribute); + rootWebPageId = getAttributeContent(result, rootWebPageIdPath, entityName, entityId); + } + if (fileCreationValid) { fileUri = filePathInPortalFS + fileNameWithExtension; await createFile( @@ -363,7 +377,8 @@ async function processDataAndCreateFile( mappingEntityFetchQuery, entityId, dataverseOrgUrl, - portalsFS + portalsFS, + rootWebPageId, ); } } @@ -409,7 +424,8 @@ async function createFile( mappingEntityFetchQuery: string | undefined, entityId: string, dataverseOrgUrl: string, - portalsFS: PortalsFS + portalsFS: PortalsFS, + rootWebPageId?: string ) { const base64Encoded: boolean = isBase64Encoded( entityName, @@ -440,7 +456,7 @@ async function createFile( mimeType = getMimeType(mappingContent); fileContent = getMappingEntityContent(entityName, mappingContent, attribute); } else { - fileContent = GetFileContent(result, attributePath, entityName, entityId); + fileContent = getAttributeContent(result, attributePath, entityName, entityId); } await createVirtualFile( @@ -458,7 +474,8 @@ async function createFile( mimeType ?? result[Constants.MIMETYPE], isPreloadedContent, mappingEntityId, - getLogicalEntityName(result, logicalEntityName) + getLogicalEntityName(result, logicalEntityName), + rootWebPageId, ); } @@ -562,7 +579,7 @@ export async function preprocessData( // eslint-disable-next-line @typescript-eslint/no-explicit-any data?.forEach((dataItem: any) => { - const webFormSteps = GetFileContent(dataItem, attributePath, entityType, fetchedFileId as string) as []; + const webFormSteps = getAttributeContent(dataItem, attributePath, entityType, fetchedFileId as string) as []; // eslint-disable-next-line @typescript-eslint/no-explicit-any const steps: any[] = []; @@ -608,7 +625,8 @@ async function createVirtualFile( mimeType?: string, isPreloadedContent?: boolean, mappingEntityId?: string, - logicalEntityName?: string + logicalEntityName?: string, + rootWebPageId?: string, ) { // Maintain file information in context await WebExtensionContext.updateFileDetailsInContext( @@ -642,5 +660,6 @@ async function createVirtualFile( originalAttributeContent, mappingEntityId, fileUri, + rootWebPageId, ); } diff --git a/src/web/client/schema/constants.ts b/src/web/client/schema/constants.ts index 8bcdfb58..d32a17f5 100644 --- a/src/web/client/schema/constants.ts +++ b/src/web/client/schema/constants.ts @@ -30,6 +30,7 @@ export enum schemaEntityKey { MAPPING_ENTITY_FETCH_QUERY = "_mappingEntityFetchQuery", EXPORT_TYPE = "_exporttype", ATTRIBUTES = "_attributes", + ROOT_WEB_PAGE_ID = "_rootwebpageid", } export enum schemaEntityName { diff --git a/src/web/client/schema/portalSchema.ts b/src/web/client/schema/portalSchema.ts index 0eadce30..55249016 100644 --- a/src/web/client/schema/portalSchema.ts +++ b/src/web/client/schema/portalSchema.ts @@ -78,15 +78,16 @@ export const portal_schema_V1 = { _languagefield: "_adx_webpagelanguageid_value", _languagegroupby: "adx_rootwebpageid", _fetchQueryParameters: - "?$filter=adx_webpageid eq {entityId} &$select=adx_name,adx_copy,adx_customcss,adx_customjavascript,adx_partialurl,_adx_webpagelanguageid_value&$count=true", + "?$filter=adx_webpageid eq {entityId} &$select=adx_name,adx_copy,adx_customcss,adx_customjavascript,adx_partialurl,_adx_webpagelanguageid_value,_adx_rootwebpageid_value&$count=true", _multiFileFetchQueryParameters: - "?$filter=_adx_websiteid_value eq {websiteId} and _adx_webpagelanguageid_value ne null &$select=adx_webpageid,_adx_webpagelanguageid_value,adx_name,adx_copy,adx_customcss,adx_customjavascript,adx_partialurl&$count=true", + "?$filter=_adx_websiteid_value eq {websiteId} and _adx_webpagelanguageid_value ne null &$select=adx_webpageid,_adx_webpagelanguageid_value,adx_name,adx_copy,adx_customcss,adx_customjavascript,adx_partialurl,_adx_rootwebpageid_value&$count=true", _attributes: "adx_customcss,adx_customjavascript,adx_copy", _attributesExtension: new Map([ ["adx_customcss", "customcss.css"], ["adx_customjavascript", "customjs.js"], ["adx_copy", "webpage.copy.html"], ]), + _rootwebpageid: "_adx_rootwebpageid_value", }, { relationships: "", @@ -307,6 +308,7 @@ export const portal_schema_V2 = { ["content.customjavascript", "customjs.js"], ["content.copy", "webpage.copy.html"], ]), + _rootwebpageid: "content.rootwebpageid" }, { relationships: "", diff --git a/src/web/client/services/etagHandlerService.ts b/src/web/client/services/etagHandlerService.ts index 976b827a..e43ff182 100644 --- a/src/web/client/services/etagHandlerService.ts +++ b/src/web/client/services/etagHandlerService.ts @@ -10,7 +10,7 @@ import { httpMethod, ODATA_ETAG, queryParameters } from "../common/constants"; import { IAttributePath } from "../common/interfaces"; import { PortalsFS } from "../dal/fileSystemProvider"; import { telemetryEventNames } from "../telemetry/constants"; -import { GetFileContent } from "../utilities/commonUtil"; +import { getAttributeContent } from "../utilities/commonUtil"; import { getFileEntityEtag, getFileEntityId, @@ -85,7 +85,7 @@ export class EtagHandlerService { const currentContent = new TextDecoder().decode( await portalFs.readFile(vscode.Uri.parse(fileFsPath)) ); - const latestContent = GetFileContent(result, attributePath, entityName, entityId); + const latestContent = getAttributeContent(result, attributePath, entityName, entityId); updateEntityEtag(entityId, result[ODATA_ETAG]); if (currentContent !== latestContent) { diff --git a/src/web/client/telemetry/constants.ts b/src/web/client/telemetry/constants.ts index 34dcfe78..538adfe4 100644 --- a/src/web/client/telemetry/constants.ts +++ b/src/web/client/telemetry/constants.ts @@ -49,7 +49,7 @@ export enum telemetryEventNames { WEB_EXTENSION_CREATE_ENTITY_FOLDER_FAILED = "webExtensionCreateEntityFolderFailed", WEB_EXTENSION_PREPROCESS_DATA_FAILED = "webExtensionPreprocessDataFailed", WEB_EXTENSION_PREPROCESS_DATA_SUCCESS = "webExtensionPreprocessDataSuccess", - WEB_EXTENSION_GET_FILE_CONTENT_ERROR = "webExtensionGetFileContentError", + WEB_EXTENSION_ATTRIBUTE_CONTENT_ERROR = "webExtensionAttributeContentError", WEB_EXTENSION_SET_FILE_CONTENT_ERROR = "webExtensionSetFileContentError", WEB_EXTENSION_FAILED_TO_PREPARE_WORKSPACE = "webExtensionFailedToPrepareWorkspace", WEB_EXTENSION_BULKHEAD_QUEUE_FULL = "webExtensionBulkheadQueueFull", @@ -98,5 +98,5 @@ export enum telemetryEventNames { WEB_EXTENSION_BACK_TO_STUDIO_TRIGGERED = 'webExtensionBackToStudioTriggered', WEB_EXTENSION_PREVIEW_SITE_TRIGGERED = 'webExtensionPreviewSiteTriggered', WEB_EXTENSION_IMAGE_EDIT_SUPPORTED_FILE_EXTENSION = 'webExtensionImageEditSupportedFileExtension', - WEB_EXTENSION_SAVE_IMAGE_FILE_TRIGGERED = 'webExtensionSaveImageFileTriggered' + WEB_EXTENSION_SAVE_IMAGE_FILE_TRIGGERED = 'webExtensionSaveImageFileTriggered', } diff --git a/src/web/client/utilities/commonUtil.ts b/src/web/client/utilities/commonUtil.ts index a6aff10f..4296bf5a 100644 --- a/src/web/client/utilities/commonUtil.ts +++ b/src/web/client/utilities/commonUtil.ts @@ -62,23 +62,23 @@ export function isExtensionNeededInFileName(entity: string) { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -export function GetFileContent(result: any, attributePath: IAttributePath, entityName: string, entityId: string) { - let fileContent = result[attributePath.source] ?? NO_CONTENT; +export function getAttributeContent(result: any, attributePath: IAttributePath, entityName: string, entityId: string) { + let value = result[attributePath.source] ?? NO_CONTENT; try { if (result[attributePath.source] && attributePath.relativePath.length) { - fileContent = + value = JSON.parse(result[attributePath.source])[attributePath.relativePath] ?? NO_CONTENT; } } catch (error) { const errorMsg = (error as Error)?.message; - WebExtensionContext.telemetry.sendErrorTelemetry(telemetryEventNames.WEB_EXTENSION_GET_FILE_CONTENT_ERROR, - GetFileContent.name, + WebExtensionContext.telemetry.sendErrorTelemetry(telemetryEventNames.WEB_EXTENSION_ATTRIBUTE_CONTENT_ERROR, + getAttributeContent.name, `For ${entityName} with entityId ${entityId} and attributePath ${JSON.stringify(attributePath)} error: ${errorMsg}`); } - return fileContent; + return value; } // eslint-disable-next-line @typescript-eslint/no-explicit-any