Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webfiles in old data model - load optimization and support webfiles browser refresh load #662

Merged
merged 4 commits into from Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/web/client/WebExtensionContext.ts
Expand Up @@ -356,15 +356,16 @@ class WebExtensionContext implements IWebExtensionContext {
entityName: string,
odataEtag: string,
attributePath: IAttributePath,
attributeContent: string
attributeContent: string,
mappingEntityId?: string
) {
this.entityDataMap.setEntity(
entityId,
entityName,
odataEtag,
attributePath,
attributeContent
);
attributeContent,
mappingEntityId);
}

public async updateSingleFileUrisInContext(uri: vscode.Uri) {
Expand Down
9 changes: 8 additions & 1 deletion src/web/client/context/entityData.ts
Expand Up @@ -8,13 +8,15 @@ import { IEntityInfo } from "../common/interfaces";
export interface IEntityData extends IEntityInfo {
entityEtag: string;
entityColumn: Map<string, string>;
mappingEntityId?: string;
}

export class EntityData implements IEntityData {
private _entityName!: string;
private _entityId!: string;
private _entityEtag!: string;
private _entityColumn!: Map<string, string>;
private _mappingEntityId?: string;

public get entityName(): string {
return this._entityName;
Expand All @@ -28,6 +30,9 @@ export class EntityData implements IEntityData {
public get entityColumn(): Map<string, string> {
return this._entityColumn;
}
public get mappingEntityId(): string | undefined {
return this._mappingEntityId;
}

// Setters
public set setEntityEtag(value: string) {
Expand All @@ -38,11 +43,13 @@ export class EntityData implements IEntityData {
entityId: string,
entityName: string,
entityEtag: string,
entityColumn: Map<string, string>
entityColumn: Map<string, string>,
mappingEntityId?: string
) {
this._entityId = entityId;
this._entityName = entityName;
this._entityEtag = entityEtag;
this._entityColumn = entityColumn;
this._mappingEntityId = mappingEntityId;
}
}
6 changes: 4 additions & 2 deletions src/web/client/context/entityDataMap.ts
Expand Up @@ -33,7 +33,8 @@ export class EntityDataMap {
entityName: string,
odataEtag: string,
attributePath: IAttributePath,
attributeContent: string
attributeContent: string,
mappingEntityId?: string
) {
let entityColumnMap = new Map<string, string>();
const existingEntity = this.entityMap.get(entityId);
Expand All @@ -47,7 +48,8 @@ export class EntityDataMap {
entityId,
entityName,
odataEtag,
entityColumnMap
entityColumnMap,
mappingEntityId
);
this.entityMap.set(entityId, entityData);
}
Expand Down
61 changes: 37 additions & 24 deletions src/web/client/dal/remoteFetchProvider.ts
Expand Up @@ -11,7 +11,7 @@ import {
isWebfileContentLoadNeeded,
setFileContent,
} from "../utilities/commonUtil";
import { getCustomRequestURL, getRequestURL, updateEntityId } from "../utilities/urlBuilderUtil";
import { getCustomRequestURL, getMappingEntityContent, getMappingEntityId, getRequestURL } from "../utilities/urlBuilderUtil";
import { getCommonHeaders } from "../common/authenticationProvider";
import * as Constants from "../common/constants";
import { ERRORS, showErrorDialog } from "../common/errorHandler";
Expand Down Expand Up @@ -197,7 +197,7 @@ async function createContentFiles(
schemaEntityKey.ATTRIBUTES_EXTENSION
);
const mappingEntityFetchQuery = entityDetails?.get(
schemaEntityKey.MAPPING_ATTRIBUTE_FETCH_QUERY
schemaEntityKey.MAPPING_ENTITY_FETCH_QUERY
);
const exportType = entityDetails?.get(schemaEntityKey.EXPORT_TYPE);
const portalFolderName = WebExtensionContext.urlParametersMap.get(
Expand Down Expand Up @@ -282,16 +282,15 @@ async function createContentFiles(

} catch (error) {
const errorMsg = (error as Error)?.message;
console.error(errorMsg);
vscode.window.showErrorMessage(
vscode.l10n.t("Failed to get file ready for edit.")
);
// WebExtensionContext.telemetry.sendErrorTelemetry(
// telemetryEventNames.WEB_EXTENSION_CONTENT_FILE_CREATION_FAILED,
// createContentFiles.name,
// errorMsg,
// error as Error
// );
WebExtensionContext.telemetry.sendErrorTelemetry(
telemetryEventNames.WEB_EXTENSION_CONTENT_FILE_CREATION_FAILED,
createContentFiles.name,
errorMsg,
error as Error
);
}
}

Expand Down Expand Up @@ -412,7 +411,8 @@ async function createFile(
entityName,
attribute
);

let fileContent = Constants.NO_CONTENT;
let mappingEntityId = null
// By default content is preloaded for all the files except for non-text webfiles for V2
const isPreloadedContent = mappingEntityFetchQuery ? isWebfileContentLoadNeeded(fileNameWithExtension, fileUri) : true;

Expand All @@ -421,22 +421,26 @@ async function createFile(
attribute
);

const fileContent = mappingEntityFetchQuery && isPreloadedContent ?
await getMappingEntityContent(
if (mappingEntityFetchQuery && isPreloadedContent) {
const mappingContent = await fetchMappingEntityContent(
mappingEntityFetchQuery,
attribute,
entityName,
entityId,
WebExtensionContext.dataverseAccessToken,
dataverseOrgUrl
) : GetFileContent(result, attributePath, entityName, entityId);

);
mappingEntityId = getMappingEntityId(entityName, mappingContent);
fileContent = getMappingEntityContent(entityName, mappingContent, attribute);
} else {
fileContent = GetFileContent(result, attributePath, entityName, entityId);
}

await createVirtualFile(
portalsFS,
fileUri,
convertContentToUint8Array(fileContent, base64Encoded),
updateEntityId(entityName, entityId, result),
entityId,
attributePath,
encodeAsBase64(entityName, attribute),
entityName,
Expand All @@ -445,11 +449,12 @@ async function createFile(
fileExtension,
result[Constants.ODATA_ETAG],
result[Constants.MIMETYPE],
isPreloadedContent
isPreloadedContent,
mappingEntityId
);
}

async function getMappingEntityContent(
async function fetchMappingEntityContent(
mappingEntityFetchQuery: string,
attributeKey: string,
entity: string,
Expand All @@ -467,14 +472,15 @@ async function getMappingEntityContent(
Constants.httpMethod.GET,
false,
true,
mappingEntityFetchQueryMap?.get(attributeKey) as string
mappingEntityFetchQueryMap?.get(attributeKey) as string,
getEntity(entity)?.get(schemaEntityKey.MAPPING_ENTITY)
);

WebExtensionContext.telemetry.sendAPITelemetry(
requestUrl,
entity,
Constants.httpMethod.GET,
getMappingEntityContent.name
fetchMappingEntityContent.name
);
requestSentAtTime = new Date().getTime();

Expand All @@ -488,7 +494,7 @@ async function getMappingEntityContent(
entity,
Constants.httpMethod.GET,
new Date().getTime() - requestSentAtTime,
getMappingEntityContent.name,
fetchMappingEntityContent.name,
JSON.stringify(response),
'',
response?.status.toString()
Expand All @@ -501,11 +507,16 @@ async function getMappingEntityContent(
entity,
Constants.httpMethod.GET,
new Date().getTime() - requestSentAtTime,
getMappingEntityContent.name
fetchMappingEntityContent.name
);

const result = await response.json();
return result.value ?? Constants.NO_CONTENT;
const data = result.value ?? result;
if (result[Constants.ODATA_COUNT] !== 0 && data.length === 1) {
return data[0];
}

return data ?? Constants.NO_CONTENT;
}

export async function preprocessData(
Expand Down Expand Up @@ -587,7 +598,8 @@ async function createVirtualFile(
fileExtension: string,
odataEtag: string,
mimeType?: string,
isPreloadedContent?: boolean
isPreloadedContent?: boolean,
mappingEntityId?: string
) {
// Maintain file information in context
await WebExtensionContext.updateFileDetailsInContext(
Expand Down Expand Up @@ -616,6 +628,7 @@ async function createVirtualFile(
entityName,
odataEtag,
attributePath,
originalAttributeContent
originalAttributeContent,
mappingEntityId
);
}
16 changes: 13 additions & 3 deletions src/web/client/dal/remoteSaveProvider.ts
Expand Up @@ -11,13 +11,16 @@ import { showErrorDialog } from "../common/errorHandler";
import { FileData } from "../context/fileData";
import { httpMethod } from "../common/constants";
import {
getEntity,
isWebFileV2,
useOctetStreamContentType,
} from "../utilities/schemaHelperUtil";
import { getPatchRequestUrl, getRequestURL } from "../utilities/urlBuilderUtil";
import WebExtensionContext from "../WebExtensionContext";
import { IAttributePath } from "../common/interfaces";
import { telemetryEventNames } from "../telemetry/constants";
import { schemaEntityKey } from "../schema/constants";
import { getEntityMappingEntityId } from "../utilities/fileAndEntityUtil";

interface ISaveCallParameters {
requestInit: RequestInit;
Expand All @@ -30,14 +33,21 @@ export async function saveData(fileUri: vscode.Uri) {
const dataverseOrgUrl = WebExtensionContext.urlParametersMap.get(
queryParameters.ORG_URL
) as string;
const entityName = dataMap.get(fileUri.fsPath)?.entityName as string;
const mappedEntity = getEntity(entityName)?.get(
schemaEntityKey.MAPPING_ENTITY
);
const entityId = dataMap.get(fileUri.fsPath)?.entityId as string;

const requestUrl = getRequestURL(
dataverseOrgUrl,
dataMap.get(fileUri.fsPath)?.entityName as string,
dataMap.get(fileUri.fsPath)?.entityId as string,
mappedEntity ?? entityName,
getEntityMappingEntityId(entityId) ?? entityId,
httpMethod.PATCH,
true,
false
false,
undefined,
mappedEntity
);

const fileDataMap = WebExtensionContext.fileDataMap.getFileMap;
Expand Down
3 changes: 2 additions & 1 deletion src/web/client/schema/constants.ts
Expand Up @@ -25,7 +25,8 @@ export enum schemaEntityKey {
FETCH_QUERY_PARAMETERS = "_fetchQueryParameters",
MULTI_FILE_FETCH_QUERY_PARAMETERS = "_multiFileFetchQueryParameters",
MAPPING_ENTITY_ID = "_mappingEntityId",
MAPPING_ATTRIBUTE_FETCH_QUERY = "_mappingAttributeFetchQuery",
MAPPING_ENTITY = "_mappingEntity",
MAPPING_ENTITY_FETCH_QUERY = "_mappingEntityFetchQuery",
EXPORT_TYPE = "_exporttype",
ATTRIBUTES = "_attributes",
}
Expand Down
24 changes: 14 additions & 10 deletions src/web/client/schema/portalSchema.ts
Expand Up @@ -91,21 +91,25 @@ export const portal_schema_V1 = {
{
relationships: "",
_vscodeentityname: "webfiles",
_dataverseenityname: "annotations",
_dataverseenityname: "adx_webfiles",
_displayname: "Web File",
_etc: "10020",
_primaryidfield: "_objectid_value",
_primarynamefield: "filename",
_primaryidfield: "adx_webfileid",
_primarynamefield: "adx_name",
_disableplugins: "true",
_foldername: "web-files",
_propextension: "webfile",
_exporttype: "SingleFolder",
_fetchQueryParameters:
"?$filter=_objectid_value eq {entityId} &$select=mimetype,documentbody,filename,annotationid,_objectid_value",
_multiFileFetchQueryParameters: "?$select=mimetype,documentbody,filename,annotationid,_objectid_value&$count=true",
"?$filter=adx_webfileid eq {entityId} &$select=adx_name",
_multiFileFetchQueryParameters: "?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_webfileid,adx_name&$count=true",
_attributes: "documentbody",
_attributesExtension: new Map([["documentbody", "css"]]),
_mappingEntityId: "annotationid", // Webfile in old schema are maintained with two dataverse entity adx_webfile and annotations. This Id acts as foreign key for that mapping
_mappingEntity: "annotations",
_mappingEntityFetchQuery: new Map([
["documentbody", "?$filter=_objectid_value eq {entityId} &$select=mimetype,documentbody,filename,annotationid,_objectid_value&$count=true"],
]),
},
{
relationships: "",
Expand Down Expand Up @@ -179,7 +183,7 @@ export const portal_schema_V1 = {
_fetchQueryParameters: "?$filter=adx_entityformid eq {entityId} &$select=adx_name,adx_registerstartupscript",
_multiFileFetchQueryParameters: "?$filter=_adx_websiteid_value eq {websiteId}&$select=adx_name,adx_registerstartupscript,adx_entityformid&$count=true",
_attributes: "adx_registerstartupscript",
_attributesExtension:new Map([["adx_registerstartupscript", "basicform.customjs.js"]]),
_attributesExtension: new Map([["adx_registerstartupscript", "basicform.customjs.js"]]),
},
{
relationships: "",
Expand Down Expand Up @@ -213,7 +217,7 @@ export const portal_schema_V1 = {
_fetchQueryParameters: "?$filter=_adx_webform_value eq {entityId} &$select=adx_name,adx_registerstartupscript,adx_webformstepid",
_multiFileFetchQueryParameters: "?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_registerstartupscript,adx_webformstepid&$count=true",
_attributes: "adx_registerstartupscript",
_attributesExtension:new Map([["adx_registerstartupscript", "advancedformstep.customjs.js"]]),
_attributesExtension: new Map([["adx_registerstartupscript", "advancedformstep.customjs.js"]]),
},
],
"_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
Expand Down Expand Up @@ -275,7 +279,7 @@ export const portal_schema_V2 = {
_fetchQueryParameters:
"?$select=powerpagesitelanguageid,languagecode,lcid",
_multiFileFetchQueryParameters:
"?$select=powerpagesitelanguageid,languagecode,lcid",
"?$select=powerpagesitelanguageid,languagecode,lcid",
},
{
relationships: "",
Expand Down Expand Up @@ -318,7 +322,7 @@ export const portal_schema_V2 = {
"?$filter=_powerpagesiteid_value eq {websiteId} and powerpagecomponenttype eq 3 &$select=name,content,_powerpagesitelanguageid_value&$count=true",
_attributes: "filecontent",
_attributesExtension: new Map([["filecontent", "css"]]),
_mappingAttributeFetchQuery: new Map([
_mappingEntityFetchQuery: new Map([
["filecontent", "({entityId})/filecontent"],
]),
},
Expand Down Expand Up @@ -427,7 +431,7 @@ export const portal_schema_V2 = {
_fetchQueryParameters: "?$filter=powerpagecomponentid eq {entityId}&$select=name,content",
_multiFileFetchQueryParameters: "?$filter=_powerpagesiteid_value eq {websiteId} and powerpagecomponenttype eq 20 &$select=name,content &$count=true",
_attributes: "content.registerstartupscript",
_attributesExtension:new Map([["content.registerstartupscript", "advancedformstep.customjs.js"]]),
_attributesExtension: new Map([["content.registerstartupscript", "advancedformstep.customjs.js"]]),
},
],
},
Expand Down