diff --git a/package-lock.json b/package-lock.json
index 9c0a76b2..b02fa115 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"glob": "^7.1.7",
"gpt-tokenizer": "^2.1.1",
"https-browserify": "^1.0.0",
+ "js-yaml": "^4.1.0",
"liquidjs": "^10.2.0",
"n-readlines": "^1.0.1",
"puppeteer-core": "^14.4.1",
@@ -71,7 +72,7 @@
"eslint": "^8.11.0",
"eslint-plugin-header": "^3.1.1",
"fancy-log": "^1.3.3",
- "fs-extra": "^9.0.1",
+ "fs-extra": "^9.1.0",
"get-func-name": "^2.0.2",
"gulp": "^4.0.2",
"gulp-eslint": "^6.0.0",
@@ -8960,6 +8961,7 @@
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
@@ -12271,6 +12273,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
diff --git a/package.json b/package.json
index 27d4e510..74aff018 100644
--- a/package.json
+++ b/package.json
@@ -99,7 +99,9 @@
"onStartupFinished",
"workspaceContains:**/**.portalconfig",
"onDebug",
- "onFileSystem:powerplatform-vfs"
+ "onFileSystem:powerplatform-vfs",
+ "onCommand:extension.openWebpage",
+ "onCommand:extension.openFile"
],
"capabilities": {
"untrustedWorkspaces": {
@@ -167,6 +169,18 @@
"dark": "src/web/client/assets/microsoftTeamsIcon/dark/microsoftTeams.svg"
}
},
+ {
+ "command": "extension.openWebpage",
+ "title": "Open Webpage"
+ },
+ {
+ "command": "extension.openFile",
+ "title": "Open File"
+ },
+ {
+ "command": "extension.activateDirectory",
+ "title": "Activate Directory"
+ },
{
"command": "powerpages.collaboration.openMail",
"title": "Open Mail",
@@ -944,6 +958,10 @@
}
],
"explorer": [
+ {
+ "id": "exampleView",
+ "name": "Example View"
+ },
{
"id": "powerpages.powerPagesFileExplorer",
"name": "%microsoft-powerplatform-portals.navigation-loop.powerPagesFileExplorer.title%",
@@ -1053,7 +1071,7 @@
"eslint": "^8.11.0",
"eslint-plugin-header": "^3.1.1",
"fancy-log": "^1.3.3",
- "fs-extra": "^9.0.1",
+ "fs-extra": "^9.1.0",
"get-func-name": "^2.0.2",
"gulp": "^4.0.2",
"gulp-eslint": "^6.0.0",
@@ -1088,6 +1106,7 @@
"@fluidframework/azure-client": "^1.2.0",
"@microsoft/1ds-core-js": "4.0.5",
"@microsoft/1ds-post-js": "4.0.5",
+ "@maker-studio/powerportals-preview-engine": "^3.7.24",
"@microsoft/generator-powerpages": "1.21.19",
"@types/jwt-decode": "2.2.0",
"@types/node-fetch": "^2.6.2",
@@ -1100,6 +1119,7 @@
"glob": "^7.1.7",
"gpt-tokenizer": "^2.1.1",
"https-browserify": "^1.0.0",
+ "js-yaml": "^4.1.0",
"liquidjs": "^10.2.0",
"n-readlines": "^1.0.1",
"puppeteer-core": "^14.4.1",
diff --git a/src/client/PortalWebView.ts b/src/client/PortalWebView.ts
index cc0669c5..ca02d24d 100644
--- a/src/client/PortalWebView.ts
+++ b/src/client/PortalWebView.ts
@@ -170,7 +170,7 @@ export class PortalWebView {
return html;
}
- private static getPortalRootFolder(): vscode.Uri | null {
+ public static getPortalRootFolder(): vscode.Uri | null {
const fileBeingEdited = vscode.window.activeTextEditor as vscode.TextEditor;
if (fileBeingEdited) {
for (let i = 0; !!(vscode.workspace.workspaceFolders) && (i < vscode.workspace.workspaceFolders?.length); i++) {
diff --git a/src/client/extension.ts b/src/client/extension.ts
index 0a8e6871..43c95407 100644
--- a/src/client/extension.ts
+++ b/src/client/extension.ts
@@ -41,6 +41,7 @@ import { ActiveOrgOutput } from "./pac/PacTypes";
import { telemetryEventNames } from "./telemetry/TelemetryEventNames";
import { IArtemisAPIOrgResponse } from "../common/services/Interfaces";
import { ArtemisService } from "../common/services/ArtemisService";
+import { treeView } from "../common/TreeStructure/DataMapper";
let client: LanguageClient;
let _context: vscode.ExtensionContext;
@@ -69,6 +70,10 @@ export async function activate(
context.subscriptions.push(_telemetry);
// Logging telemetry in US cluster for unauthenticated scenario
oneDSLoggerWrapper.instantiate("us");
+ oneDSLoggerWrapper.getLogger().traceInfo("Instantiating tree view", {
+ "instantiate": performance.now()
+ });
+ await treeView();
_telemetry.sendTelemetryEvent("Start", {
"pac.userId": readUserSettings().uniqueId,
@@ -483,4 +488,4 @@ class CliAcquisitionContext implements ICliAcquisitionContext {
comment: ["Do not translate 'dotnet' or 'sdk'"]
});
}
-}
+}
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/book.svg b/src/client/portal_fileicons/icons/dark/book.svg
new file mode 100644
index 00000000..669db404
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/book.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/css.svg b/src/client/portal_fileicons/icons/dark/css.svg
new file mode 100644
index 00000000..ec75da91
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/css.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/file-submodule.svg b/src/client/portal_fileicons/icons/dark/file-submodule.svg
new file mode 100644
index 00000000..79018e08
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/file-submodule.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/file-symlink-file.svg b/src/client/portal_fileicons/icons/dark/file-symlink-file.svg
new file mode 100644
index 00000000..2aff0ee4
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/file-symlink-file.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/html.svg b/src/client/portal_fileicons/icons/dark/html.svg
new file mode 100644
index 00000000..af331070
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/html.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/js.svg b/src/client/portal_fileicons/icons/dark/js.svg
new file mode 100644
index 00000000..d6ced9e7
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/js.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/json.svg b/src/client/portal_fileicons/icons/dark/json.svg
new file mode 100644
index 00000000..af583f76
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/json.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/list-flat.svg b/src/client/portal_fileicons/icons/dark/list-flat.svg
new file mode 100644
index 00000000..042ad665
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/list-flat.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/mp4.svg b/src/client/portal_fileicons/icons/dark/mp4.svg
new file mode 100644
index 00000000..aceee8c4
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/mp4.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/note.svg b/src/client/portal_fileicons/icons/dark/note.svg
new file mode 100644
index 00000000..8e013c11
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/note.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/png.svg b/src/client/portal_fileicons/icons/dark/png.svg
new file mode 100644
index 00000000..e4f64df5
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/png.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/referrences.svg b/src/client/portal_fileicons/icons/dark/referrences.svg
new file mode 100644
index 00000000..280b3d83
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/referrences.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/dark/yml.svg b/src/client/portal_fileicons/icons/dark/yml.svg
new file mode 100644
index 00000000..551def40
--- /dev/null
+++ b/src/client/portal_fileicons/icons/dark/yml.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/book.svg b/src/client/portal_fileicons/icons/light/book.svg
new file mode 100644
index 00000000..82ccad3f
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/book.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/file-submodule.svg b/src/client/portal_fileicons/icons/light/file-submodule.svg
new file mode 100644
index 00000000..2161152f
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/file-submodule.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/file-symlink-file.svg b/src/client/portal_fileicons/icons/light/file-symlink-file.svg
new file mode 100644
index 00000000..f2de1bf1
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/file-symlink-file.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/json.svg b/src/client/portal_fileicons/icons/light/json.svg
new file mode 100644
index 00000000..d7a79a34
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/json.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/list-flat.svg b/src/client/portal_fileicons/icons/light/list-flat.svg
new file mode 100644
index 00000000..b1d9eca2
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/list-flat.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/client/portal_fileicons/icons/light/note.svg b/src/client/portal_fileicons/icons/light/note.svg
new file mode 100644
index 00000000..81a134ba
--- /dev/null
+++ b/src/client/portal_fileicons/icons/light/note.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/client/power-pages/commonUtility.ts b/src/client/power-pages/commonUtility.ts
index cdb8a8fd..de48a8b3 100644
--- a/src/client/power-pages/commonUtility.ts
+++ b/src/client/power-pages/commonUtility.ts
@@ -197,3 +197,16 @@ export function getRegExPattern(fileNameArray: string[]): RegExp[] {
return patterns;
}
+
+export const findObjectIndexByProperty = (array: any, key: string, value: any): number => {
+ for (let i=0; i {
+ return fileName.slice(0, -extn.length);
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/CovertIItemToJson.ts b/src/common/TreeStructure/CovertIItemToJson.ts
new file mode 100644
index 00000000..3ca0fb9b
--- /dev/null
+++ b/src/common/TreeStructure/CovertIItemToJson.ts
@@ -0,0 +1,34 @@
+import { IItem } from './TreeView/Types/Entity/IItem';
+
+const componentTypeMap: { [key: string]: string } = {
+ '08': 'web-temmplates',
+ '07': 'content-snippets',
+ '015': 'basic-forms',
+ '017': 'lists',
+ '019': 'advanced-forms'
+};
+
+export function generateJsonFromIItem(item: IItem): any {
+ const result: any = {
+ label: item.label
+ };
+
+ if (item.children && item.children.length > 0) {
+ result.children = item.children.map(child => {
+ const childResult = generateJsonFromIItem(child);
+ if (item.label === 'References') {
+ childResult['type'] = componentTypeMap[child.component];
+ }
+ return childResult;
+ });
+ }
+
+ if (item.parentList && item.parentList.length > 0) {
+ result.parentList = item.parentList.map(parent => ({
+ type: parent.title,
+ label: parent.label,
+ }));
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/DataMapper.ts b/src/common/TreeStructure/DataMapper.ts
new file mode 100644
index 00000000..2abf7d42
--- /dev/null
+++ b/src/common/TreeStructure/DataMapper.ts
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+import * as vscode from 'vscode';
+import { IPreviewEngineContext } from './TreeView/Utils/IDataResolver';
+import { Webpage } from './TreeView/Types/Entity/WebPage';
+import { Website } from './TreeView/Types/Entity/Website';
+import { WebTemplate } from './TreeView/Types/Entity/WebTemplate';
+import { PageTemplate } from './TreeView/Types/Entity/PageTemplate';
+import { WebFile } from "./TreeView/Types/Entity/WebFile";
+import { ContentSnippet } from "./TreeView/Types/Entity/ContentSnippet";
+import { EntityForm } from "./TreeView/Types/Entity/EntityForm";
+import { EntityList } from "./TreeView/Types/Entity/EntityList";
+import { WebForm } from "./TreeView/Types/Entity/WebForm";
+import { SiteMarker } from "./TreeView/Types/Entity/SiteMarker";
+import { SiteSetting } from "./TreeView/Types/Entity/SiteSettings";
+import { Weblink } from "./TreeView/Types/Entity/Weblink";
+import { WeblinkSet } from "./TreeView/Types/Entity/WeblinkSet";
+import { PortalWebView } from '../../client/PortalWebView';
+import { BootstrapSiteSetting, ContextProperty } from './TreeView/Utils/Constant';
+import { createTree } from './TreeViewProvider';
+import { IItem } from './TreeView/Types/Entity/IItem';
+import { getDependencies } from './DataParser';
+import { PortalComponentServiceFactory } from "./dataMapperServices/PortalComponentServiceFactory";
+import { oneDSLoggerWrapper } from "../../common/OneDSLoggerTelemetry/oneDSLoggerWrapper";
+import { MyReferenceProvider } from "./MyReferenceProvider";
+import { generateJsonFromIItem } from './CovertIItemToJson';
+import { contentPage } from './dataMapperServices/WebPageService';
+
+const fs = require('fs');
+const yaml = require("js-yaml");
+const load = yaml.load;
+const fallbackURI = vscode.Uri.file('');
+
+export let globalWebsiteIItem: IItem;
+export let globalwebPageIItem: IItem;
+
+export const treeView = async () => {
+ const previewHelper = new PreviewHelper();
+ try {
+ await previewHelper.createContext();
+ const getPath = await previewHelper.getPath();
+ const IPortalMetadataContext = await previewHelper.getPreviewHelper();
+ console.log(IPortalMetadataContext);
+ const web = await previewHelper.web();
+
+ oneDSLoggerWrapper.getLogger().traceInfo("End of IPortalMetadata creation", {
+ "timeNow": performance.now()
+ });
+
+ const { allwebTemplate, allwebPage, allwebFile, allcontentSnippet, alllist, allentityForm, allwebForm } = convertAllMetadataToItems(IPortalMetadataContext, getPath);
+ const websiteIItem = await createWebsiteItem(previewHelper);
+ const { webtemplateIItem, webPageIItem, webFileIItem, contentSnippetIItem, listIItem, entityFormtIItem, webFormIItem, unUsedFileIItem, webIItem } = createIndividualItems(allwebTemplate, allwebPage, allwebFile, allcontentSnippet, alllist, allentityForm, allwebForm);
+ addWebfileToWebPage(IPortalMetadataContext, allwebPage, allwebFile);
+ addPageTemplate(IPortalMetadataContext,contentPage, allwebPage, allwebTemplate);
+
+ const entityFileMap: Map> = new Map();
+
+ addDependencies(webtemplateIItem, webPageIItem, webFileIItem, contentSnippetIItem, listIItem, entityFormtIItem, webFormIItem, entityFileMap);
+ addUnUsedFiles(unUsedFileIItem, entityFileMap, webtemplateIItem, contentSnippetIItem, listIItem, entityFormtIItem, webFormIItem);
+ removeusedOne(unUsedFileIItem, IPortalMetadataContext);
+
+ globalwebPageIItem = webIItem;
+ webPageIItem.children = webPageIItem.children.filter(item => item.label === "Home");
+ (websiteIItem.children as IItem[]).push(webtemplateIItem, webPageIItem, webFileIItem, contentSnippetIItem, listIItem, entityFormtIItem, webFormIItem, unUsedFileIItem);
+
+ console.log(websiteIItem);
+ globalWebsiteIItem = websiteIItem;
+
+ const languages = ['html', 'css', 'javascript', 'json', 'yaml'];
+ languages.forEach(language => {
+ vscode.languages.registerReferenceProvider(
+ { scheme: 'file', language },
+ new MyReferenceProvider()
+ );
+ });
+
+ createTree(websiteIItem);
+ const jsonObject = generateJsonFromIItem(websiteIItem);
+ console.log(JSON.stringify(jsonObject, null, 2));
+
+ oneDSLoggerWrapper.getLogger().traceInfo("End of tree view creation", {
+ "timeNow": performance.now()
+ });
+
+ } catch (error) {
+ console.error('Error:', error);
+ }
+};
+vscode.workspace.onDidSaveTextDocument(async (document) => {
+ await treeView(); // Refresh treeView on document save
+});
+
+function convertAllMetadataToItems(IPortalMetadataContext: any, getPath: any) {
+ const allwebTemplate = PortalComponentServiceFactory.getPortalComponent("WebTemplate")?.create(IPortalMetadataContext, getPath) || [];
+ const allwebPage = PortalComponentServiceFactory.getPortalComponent("WebPage")?.create(IPortalMetadataContext, getPath) || [];
+ const allwebFile = PortalComponentServiceFactory.getPortalComponent("WebFile")?.create(IPortalMetadataContext, getPath) || [];
+ const allcontentSnippet = PortalComponentServiceFactory.getPortalComponent("Content Snippet")?.create(IPortalMetadataContext, getPath) || [];
+ const alllist = PortalComponentServiceFactory.getPortalComponent("List")?.create(IPortalMetadataContext, getPath) || [];
+ const allentityForm = PortalComponentServiceFactory.getPortalComponent("EntityForm")?.create(IPortalMetadataContext, getPath) || [];
+ const allwebForm = PortalComponentServiceFactory.getPortalComponent("WebForm")?.create(IPortalMetadataContext, getPath) || [];
+ return { allwebTemplate, allwebPage, allwebFile, allcontentSnippet, alllist, allentityForm, allwebForm };
+}
+
+async function createWebsiteItem(previewHelper: PreviewHelper) {
+ const web = await previewHelper.web();
+ return {
+ label: web.adx_name ?? 'Unnamed Website',
+ title: web.adx_name ?? 'Unnamed Website',
+ id: web.adx_websiteid,
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/${web.adx_name}`),
+ component: "1",
+ children: [],
+ error: "",
+ parentList: []
+ };
+}
+
+function createIndividualItems(allwebTemplate: IItem[], allwebPage: IItem[], allwebFile: IItem[], allcontentSnippet: IItem[], alllist: IItem[], allentityForm: IItem[], allwebForm: IItem[]) {
+ const webtemplateIItem = {
+ label: 'Web Templates',
+ title: 'Web Templates',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/WebTemplate`),
+ component: "8",
+ children: allwebTemplate,
+ error: "",
+ parentList: []
+ };
+
+ const webPageIItem = {
+ label: 'Web Pages',
+ title: 'Web Pages',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/WebPage`),
+ component: "2",
+ children: allwebPage,
+ error: "",
+ parentList: []
+ };
+
+ const webFileIItem = {
+ label: 'Web Files',
+ title: 'Web Files',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/webFile`),
+ component: "3",
+ children: allwebFile,
+ error: "",
+ parentList: []
+ };
+ const contentSnippetIItem = {
+ label: 'Content Snippets',
+ title: 'Content Snippets',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/contentSnippet`),
+ component: "7",
+ children: allcontentSnippet,
+ error: "",
+ parentList: []
+ };
+ const listIItem = {
+ label: 'Lists',
+ title: 'Lists',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/lists`),
+ component: "17",
+ children: alllist,
+ error: "",
+ parentList: []
+ };
+
+ const entityFormtIItem = {
+ label: 'Basic Forms',
+ title: 'Basic Forms',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/basic-forms`),
+ component: "15",
+ children: allentityForm,
+ error: "",
+ parentList: []
+ };
+
+ const webFormIItem = {
+ label: 'Advanced Forms',
+ title: 'Advanced Forms',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/advanced-forms`),
+ component: "19",
+ children: allwebForm,
+ error: "",
+ parentList: []
+ };
+ const unUsedFileIItem = {
+ label: 'Unused Components',
+ title: 'Unused Components',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/unused-files`),
+ component: "20",
+ children: [],
+ error: "",
+ parentList: []
+ };
+ const webIItem = {
+ label: 'Web Pages',
+ title: 'Web Pages',
+ id: '',
+ isFile: false,
+ content: "",
+ path: vscode.Uri.parse(`/WebPage`),
+ component: "2",
+ children: allwebPage,
+ error: "",
+ parentList: []
+ };
+
+ return { webtemplateIItem, webPageIItem, webFileIItem, contentSnippetIItem, listIItem, entityFormtIItem, webFormIItem, unUsedFileIItem, webIItem };
+}
+
+function addWebfileToWebPage(metadataContext: IPreviewEngineContext, webPageIItem: IItem[], webFileIItem: IItem[]) {
+ const items: IItem[] = [];
+ const webfile: WebFile[] | undefined = metadataContext.webFiles;
+
+ if (!webfile) {
+ return items;
+ }
+ webfile.forEach(file => {
+ webPageIItem.forEach(item => {
+ if (file.adx_parentpageid == item.id) {
+ webFileIItem.forEach(it => {
+ if (it.id == file.adx_webfileid) {
+ let webfileItem = item.children.find(child => child.label === "Web File");
+ if (!webfileItem) {
+ let webFile = createItem('Web File', 'Web File', '', false, vscode.Uri.parse(`/webFile`), "3", [it]);
+ item.children.push(webFile);
+ } else {
+ webfileItem.children.push(it);
+ }
+ }
+ })
+ }
+ });
+ });
+}
+
+function createItem(label: string, title: string, id: string, isFile: boolean, path: vscode.Uri, component: string, children: IItem[] = [], content: string = '', error: string = '', parentList: IItem[] = []): IItem {
+ return {
+ label,
+ title,
+ id,
+ isFile,
+ content,
+ path,
+ component,
+ children,
+ error,
+ parentList,
+ };
+}
+
+function addPageTemplate(IPortalMetadataContext: any, contentPage: Webpage[], webPageIItem: IItem[], webTemplateIITem: IItem[]) {
+ const pageTemplate: PageTemplate[] | undefined = IPortalMetadataContext.pageTemplates;
+ const webpages: Webpage[] | undefined = IPortalMetadataContext.webpages;
+ pageTemplate?.forEach(pg => {
+ const pgid = pg.adx_pagetemplateid;
+ webpages?.forEach(webpage => {
+ const wbpgid = webpage.adx_pagetemplateid;
+ const webPageId=webpage.adx_webpageid;
+ if (wbpgid == pgid) {
+ const webPage = webPageIItem.find(item => webPageId === item.id);
+ const tempid = pg.adx_webtemplateid;
+ if (tempid) {
+ const te = webTemplateIITem.find(it => tempid === it.id);
+ if (te) {
+ const item = createItem(`${te.label}`, `Source-Dependencies`, `${te.id}`, true, vscode.Uri.parse(`/inside treeItem`), '08', [], '', '');
+ const pageTemplateAlreadyExists = webPage?.children.find(it => it.label === 'Page Template');
+ if (!pageTemplateAlreadyExists) {
+ let pT = createItem('Page Template', 'Page Template', '', false, vscode.Uri.parse(`/pageTemplate`), "6", []);
+ pT.children.push(item);
+ webPage?.children.push(pT);
+ } else {
+ pageTemplateAlreadyExists.children.push(item);
+ webPage?.children.push(pageTemplateAlreadyExists);
+ }
+ }
+ }
+ }
+ })
+ contentPage?.forEach(webpage => {
+ const wbpgid = webpage.adx_pagetemplateid;
+ const webPageId=webpage.adx_webpageid;
+ if (wbpgid == pgid) {
+ const webPage = webPageIItem.find(item => webPageId === item.id);
+ const tempid = pg.adx_webtemplateid;
+ if (tempid) {
+ const te = webTemplateIITem.find(it => tempid === it.id);
+ if (te) {
+ const item = createItem(`${te.label}`, `Source-Dependencies`, `${te.id}`, true, vscode.Uri.parse(`/inside treeItem`), '08', [], '', '');
+ const pageTemplateAlreadyExists = webPage?.children.find(it => it.label === 'Page Template');
+ if (!pageTemplateAlreadyExists) {
+ let pT = createItem('Page Template', 'Page Template', '', false, vscode.Uri.parse(`/pageTemplate`), "6", []);
+ pT.children.push(item);
+ webPage?.children.push(pT);
+ } else {
+ pageTemplateAlreadyExists.children.push(item);
+ webPage?.children.push(pageTemplateAlreadyExists);
+ }
+ }
+ }
+ }
+ })
+ })
+
+}
+
+
+function addDependencies(webtemplateIItem: IItem, webPageIItem: IItem, webFileIItem: IItem, contentSnippetIItem: IItem, listIItem: IItem, entityFormtIItem: IItem, webFormIItem: IItem, entityFileMap: Map>): any {
+ addDependenciesToIItem(webtemplateIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ addDependenciesToWebPage(webPageIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ addDependenciesToIItem(contentSnippetIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ addDependenciesToIItem(listIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ addDependenciesToIItem(entityFormtIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ addDependenciesToIItem(webFileIItem, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+}
+
+function addDependenciesToIItem(entityIItem: IItem, contentSnippetIItem: IItem, webtemplateIItem: IItem, entityFormtIItem: IItem, listIItem: IItem, webFormIItem: IItem, entityFileMap: Map>): any {
+ entityIItem.children.forEach((item: IItem) => {
+ if (!item.isFile) {
+ let sourceDep = item.children.find((child: IItem) => child.isFile === false);
+ if (!sourceDep) {
+ sourceDep = createItem(`References`, `References`, '', false, vscode.Uri.parse(''), "21", [], "");
+ }
+ const htOrJsFile = item.children.find((child: IItem) => child.isFile === true);
+ const filePath = htOrJsFile?.path?.fsPath;
+ if (filePath && sourceDep) {
+ processDependencies(sourceDep, item, filePath, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap);
+ } else {
+ console.log('No valid file path found for:', item);
+ }
+ if (sourceDep.children.length != 0) {
+ item.children.push(sourceDep);
+ }
+ }
+ });
+}
+
+function addDependenciesToWebPage(webPageIItem: IItem, contentSnippetIItem: IItem, webtemplateIItem: IItem, entityFormtIItem: IItem, listIItem: IItem, webFormIItem: IItem, entityFileMap: Map>): any {
+ webPageIItem.children.forEach((item: IItem) => {
+ const pgcy = item.children.find(child => child.label === "Page Copy");
+ const pgsy = item.children.find(child => child.label === "Page Summary");
+ const cp = item.children.find(child => child.label === "Content Page")
+ const cppgcy = cp?.children.find(child => child.label === "Page Copy");
+ const cppgsy = cp?.children.find(child => child.label === "Page Summary");
+ const cpjsfile = cp?.children.find((child: IItem) => child.label.endsWith('.js'));
+ const jsfile = item.children.find((child: IItem) => child.label.endsWith('.js'));
+
+ handleChildItem(pgcy, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap, jsfile);
+ handleChildItem(pgsy, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap, jsfile);
+ handleChildItem(cppgcy, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap, cpjsfile);
+ handleChildItem(cppgsy, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap, cpjsfile);
+ });
+}
+
+function handleChildItem(child: IItem | undefined, contentSnippetIItem: IItem, webtemplateIItem: IItem, entityFormtIItem: IItem, listIItem: IItem, webFormIItem: IItem, entityFileMap: Map>, jsfile?: IItem) {
+ if (child) {
+ const ht = child.children.find((child: IItem) => child.isFile === true);
+ const filePath = ht?.path?.fsPath;
+ const jsFilePath = jsfile?.path?.fsPath;
+ let sourceDep = child.children.find((child: IItem) => child.isFile === false);
+
+ if (!sourceDep) {
+ sourceDep = createItem("References", "References", '', false, vscode.Uri.parse(''), "21", [], "");
+ }
+ if (filePath && sourceDep) {
+ processDependencies(sourceDep, child, filePath, contentSnippetIItem, webtemplateIItem, entityFormtIItem, listIItem, webFormIItem, entityFileMap, jsFilePath);
+ } else {
+ console.log('No valid file path or sourceDep found for:', child);
+ }
+ if (sourceDep.children.length != 0) {
+ child.children.push(sourceDep);
+ }
+ }
+}
+
+function processDependencies(sourceDep: IItem, parent: IItem, filePath: string, contentSnippetIItem: IItem, webtemplateIItem: IItem, entityFormtIItem: IItem, listIItem: IItem, webFormIItem: IItem, entityFileMap: Map>, jsFilePath?: string) {
+ const data = fs.readFileSync(filePath, 'utf8');
+ const dependencies = getDependencies(data);
+ if (jsFilePath) {
+ const jsdata = fs.readFileSync(jsFilePath, 'utf8');
+ const jsdependencies = getDependencies(jsdata)
+ dependencies.push(...jsdependencies);
+ }
+ dependencies.forEach((entity: any) => {
+ const tagName = entity.tagName.replace(/^['"](.*)['"]$/, '$1');
+ const property = entity.property.replace(/^['"](.*)['"]$/, '$1');
+ const fileNameOrID = entity.fileNameOrID.replace(/^['"](.*)['"]$/, '$1');
+
+ if (tagName === "snippets" || tagName === "snippet" || (tagName === 'editable' && (property === "snippets" || property === "snippet"))) {
+ processEntity(sourceDep, parent, contentSnippetIItem, entity, 'label', entityFileMap, '07');
+ } else if (tagName === "Web Template") {
+ processEntity(sourceDep, parent, webtemplateIItem, entity, 'label', entityFileMap, '08');
+ } else if (tagName === "entityform" || tagName === "entity_form") {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(sourceDep, parent, entityFormtIItem, entity, 'id', entityFileMap, '015');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(sourceDep, parent, entityFormtIItem, entity, 'label', entityFileMap, '015')
+ } else {
+ console.log("Not Valid EnitityForm");
+ }
+ } else if (tagName === "entitylist" || tagName === "entity_list") {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(sourceDep, parent, listIItem, entity, 'id', entityFileMap, '017');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(sourceDep, parent, listIItem, entity, 'label', entityFileMap, '017')
+ } else {
+ console.log("Not Valid EntityList");
+ }
+ } else if (tagName === "webform") {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(sourceDep, parent, webFormIItem, entity, 'id', entityFileMap, '019');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(sourceDep, parent, webFormIItem, entity, 'label', entityFileMap, '019')
+ } else {
+ console.log("Not Valid WebForm");
+ }
+ } else if ((tagName != "entityform" && tagName != "entity_form") && (tagName != "entitylist" && tagName != "entity_list") && tagName !== "editable") {
+ entity.fileNameOrID = tagName;
+ entity.tagName = 'Web Template'
+ processEntity(sourceDep, parent, webtemplateIItem, entity, 'label', entityFileMap, '08');
+ } else {
+ console.log("Another Dynamic entity");
+ }
+ });
+}
+
+function processEntity(sourceDep: IItem, parent: IItem, targetIItem: IItem, entity: any, compareBy: string, entityFileMap: Map>, comp: string) {
+ let exist = false;
+ const fileNameOrID = entity.fileNameOrID.replace(/^['"](.*)['"]$/, '$1');
+ targetIItem.children.forEach((targetItem: IItem) => {
+ const compareValue = compareBy === 'label' ? targetItem.label : targetItem.id;
+ if (compareValue === fileNameOrID) {
+ exist = true;
+ let fileNameAlready = sourceDep.children.find(child => (child.label === targetItem.label && child.component.slice(1) === targetItem.component.slice(1)));
+ let ht = targetItem.children.find((child: IItem) => child.isFile === true);
+ let htLabel = ht?.label ?? '';
+ let parentAlreadyPresent = targetItem.parentList.find(child => (child.label === parent.label && child.component === parent.component));
+ if (!parentAlreadyPresent) {
+ targetItem.parentList.push(parent);
+ }
+ const item = createItem(`${targetItem.label}`, `Source-Dependencies`, `${targetItem.id}`, true, vscode.Uri.parse(`/inside treeItem`), comp, [], '', '');
+ if (!entityFileMap.has(targetIItem.label)) {
+ entityFileMap.set(targetIItem.label, new Set());
+ }
+ entityFileMap.get(targetIItem.label)?.add(htLabel);
+ if (!fileNameAlready) {
+ sourceDep.children.push(item);
+ }
+ }
+ });
+ if (exist == false) {
+ const item = createItem(`${fileNameOrID} Not Used`, `${fileNameOrID}`, `${entity.tagName}`, true, vscode.Uri.parse(``), comp, [], '', '');
+ let fileNameAlready = sourceDep.children.find(child => child.label === `${fileNameOrID} Not Used`);
+ if (!fileNameAlready) {
+ sourceDep.children.push(item);
+ }
+ }
+}
+
+
+function addUnUsedFiles(unUsedFileIItem: IItem, entityFileMap: Map>, webtemplateIItem: IItem, contentSnippetIItem: IItem, listIItem: IItem, entityFormtIItem: IItem, webFormIItem: IItem) {
+ addUnusedFilesHelper('Web Templates', unUsedFileIItem, entityFileMap, webtemplateIItem, '/WebTemplates', "8");
+ addUnusedFilesHelper('Content Snippets', unUsedFileIItem, entityFileMap, contentSnippetIItem, '/contentSnippets', "7");
+ addUnusedFilesHelper('Lists', unUsedFileIItem, entityFileMap, listIItem, '/lists', "17");
+ addUnusedFilesHelper('Basic Forms', unUsedFileIItem, entityFileMap, entityFormtIItem, '/basic-forms', "15");
+ addUnusedFilesHelper('Advanced Forms', unUsedFileIItem, entityFileMap, webFormIItem, '/advanced-forms', "19");
+}
+
+function addUnusedFilesHelper(entityType: string, unusedFileIItem: IItem, entityFileMap: Map>, entityIItem: IItem, folderPath: string, order: string) {
+ const usedEntityFiles = entityFileMap.get(entityType);
+ entityIItem.children.forEach((item: IItem) => {
+ const file = item.children.find((child: IItem) => child.isFile === true);
+ if (file && !usedEntityFiles?.has(file.label)) {
+ let entityPresent = unusedFileIItem.children.find(child => child.label === entityType);
+ if (entityPresent) {
+ entityPresent.children.push(file);
+ } else {
+ entityPresent = createItem(entityType, entityType, '', false, vscode.Uri.parse(folderPath), order, []);
+ entityPresent.children.push(file);
+ unusedFileIItem.children.push(entityPresent);
+ }
+ }
+ });
+}
+
+function removeusedOne(unUsedFileIItem: IItem, metadataContext: IPreviewEngineContext) {
+ const pageTemplate = metadataContext.pageTemplates;
+ const webTemplateItem = unUsedFileIItem.children.find((item: IItem) => item.label === 'Web Template');
+ pageTemplate?.forEach(pageTemp => {
+ if (pageTemp.adx_webtemplateid && webTemplateItem) {
+ webTemplateItem.children = webTemplateItem.children.filter((item: IItem) => item.id !== pageTemp.adx_webtemplateid);
+ }
+ })
+ const website = metadataContext.website;
+ if (website?.adx_footerwebtemplateid && webTemplateItem) {
+ webTemplateItem.children = webTemplateItem.children.filter((item: IItem) => item.id !== website.adx_footerwebtemplateid);
+ }
+ if (website?.adx_headerwebtemplateid && webTemplateItem) {
+ webTemplateItem.children = webTemplateItem.children.filter((item: IItem) => item.id !== website.adx_headerwebtemplateid);
+ }
+}
+
+export class PreviewHelper {
+ private pathroot: vscode.Uri | null;
+ private previewHelper: IPreviewEngineContext;
+ private websiteData: Website;
+ private isBootstrapV5: boolean;
+
+
+ constructor() {
+ this.isBootstrapV5 = false;
+ this.previewHelper = {};
+ // this.pathroot = PortalWebView.getPortalRootFolder();
+ this.pathroot = vscode.Uri.file('C:/Users/t-mansisingh/OneDrive - Microsoft/Desktop/clone2/mansi-site-1---site-ajx90');
+ this.websiteData = {} as Website;
+ }
+
+ public createContext = async () => {
+ this.websiteData = await this.getWebsite();
+ this.previewHelper = await this.createEngineContext();
+ }
+ public getPath = async () => {
+ return this.pathroot;
+ }
+
+ public web = async () => {
+ return this.websiteData;
+ }
+
+ public getPreviewHelper = () => {
+ return this.previewHelper;
+ }
+
+ private getWebsite = async (): Promise => {
+ const website = await vscode.workspace.fs.readFile(this.pathroot?.with({ path: this.pathroot.path + '/website.yml' }) || fallbackURI);
+ const websiteYaml = load(new TextDecoder().decode(website));
+ return websiteYaml as Website;
+ }
+
+ private createEngineContext = async (): Promise => {
+ if (this.pathroot) {
+ return {
+ webpages: await this.getWebpages(),
+ pageTemplates: await this.getPageTemplates(),
+ webTemplates: await this.getWebTemplates(),
+ webFiles: await this.getWebFiles(),
+ contentSnippets: await this.getContentSnippets(),
+ entityLists: await this.getEntityLists(),
+ entityForms: await this.getEntityForms(),
+ webForms: await this.getWebForms(),
+ siteMarkers: await this.getSiteMarker(),
+ siteSettings: await this.getSiteSetting(),
+ weblinks: await this.getWeblinks(),
+ weblinkSets: await this.getWeblinkSets(),
+ website: this.websiteData,
+ isBootstrapV5: this.isBootstrapV5,
+ }
+ } else return {}
+ }
+
+ private getWebpages = async (): Promise => {
+ const webpagesDir = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/web-pages' }) || fallbackURI);
+ const webpageArray: Webpage[] = [];
+
+ for (const webpage of webpagesDir) {
+ webpageArray.push(await this.webPageHelper(this.pathroot?.with({ path: this.pathroot.path + '/web-pages/' + webpage[0] + '/' + webpage[0] }) || fallbackURI));
+
+ const contentPageDir = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/web-pages/' + webpage[0] + '/content-pages' }) || fallbackURI);
+ for (const page of contentPageDir) {
+ if (page[0].endsWith(ContextProperty.WEBPAGE_YAML)) {
+ const pageName = page[0].slice(0, -12);
+ webpageArray.push(await this.webPageHelper(this.pathroot?.with({ path: this.pathroot.path + '/web-pages/' + webpage[0] + '/content-pages/' + pageName }) || fallbackURI));
+ }
+ }
+ }
+ return webpageArray;
+ }
+
+ private webPageHelper = async (pageUri: vscode.Uri): Promise => {
+ const webpageYaml = await vscode.workspace.fs.readFile(pageUri?.with({ path: pageUri.path + '.webpage.yml' }));
+ const webpageJS = await vscode.workspace.fs.readFile(pageUri?.with({ path: pageUri.path + '.webpage.custom_javascript.js' }));
+ const webpageCSS = await vscode.workspace.fs.readFile(pageUri?.with({ path: pageUri.path + '.webpage.custom_css.css' }));
+ const webpageCopy = await vscode.workspace.fs.readFile(pageUri?.with({ path: pageUri.path + '.webpage.copy.html' }));
+ const webpageSummary = await vscode.workspace.fs.readFile(pageUri?.with({ path: pageUri.path + '.webpage.summary.html' }));
+ const webpageRecord = load(new TextDecoder().decode(webpageYaml)) as Webpage;
+ webpageRecord.adx_customcss = new TextDecoder().decode(webpageCSS);
+ webpageRecord.adx_customjavascript = new TextDecoder().decode(webpageJS);
+ webpageRecord.adx_copy = new TextDecoder().decode(webpageCopy);
+ webpageRecord.adx_summary = new TextDecoder().decode(webpageSummary);
+ webpageRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return webpageRecord;
+ }
+
+ private getPageTemplates = async (): Promise => {
+ const pageTemplatesDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/page-templates' }) || fallbackURI);
+ const pageTemplatesArray: PageTemplate[] = [];
+
+ for (const pageTemplate of pageTemplatesDirectory) {
+ pageTemplatesArray.push(await this.pageTemplateHelper(this.pathroot?.with({ path: this.pathroot.path + '/page-templates/' + pageTemplate[0] }) || fallbackURI));
+ }
+ return pageTemplatesArray;
+ }
+
+ private pageTemplateHelper = async (fileUri: vscode.Uri): Promise => {
+ const pageTemplateYaml = await vscode.workspace.fs.readFile(fileUri);
+ const pageTemplateRecord = load(new TextDecoder().decode(pageTemplateYaml)) as PageTemplate;
+ return pageTemplateRecord;
+ };
+
+
+ private webTemplateHelper = async (fileUri: vscode.Uri): Promise => {
+ const webTemplateYaml = await vscode.workspace.fs.readFile(fileUri?.with({ path: fileUri.path + '.webtemplate.yml' }));
+ const webTemplateSource = await vscode.workspace.fs.readFile(fileUri?.with({ path: fileUri.path + '.webtemplate.source.html' }));
+ const webTemplateSourceHTML = new TextDecoder().decode(webTemplateSource);
+ const webTemplateRecord = load(new TextDecoder().decode(webTemplateYaml)) as WebTemplate;
+ webTemplateRecord.adx_source = webTemplateSourceHTML;
+ webTemplateRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return webTemplateRecord;
+ };
+
+ private getWebTemplates = async (): Promise => {
+ const webTemplatesDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/web-templates' }) || fallbackURI);
+
+ const webTemplatesArray: WebTemplate[] = [];
+ for (const webTemplate of webTemplatesDirectory) {
+ webTemplatesArray.push(await this.webTemplateHelper(this.pathroot?.with({ path: this.pathroot.path + '/web-templates/' + webTemplate[0] + `/${webTemplate[0]}` }) || fallbackURI));
+ }
+ return webTemplatesArray;
+ }
+
+ private webFileHelper = async (fileUri: vscode.Uri): Promise => {
+ const webFileYaml = await vscode.workspace.fs.readFile(fileUri);
+ const webFileRecord = load(new TextDecoder().decode(webFileYaml)) as WebFile;
+ return webFileRecord;
+ };
+
+ private getWebFiles = async (): Promise => {
+ const webFilesDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/web-files' }) || fallbackURI);
+ const webFilesArray: WebFile[] = [];
+ for (const webFile of webFilesDirectory) {
+ if (webFile[0].endsWith("webfile.yml")) {
+ webFilesArray.push(await this.webFileHelper(this.pathroot?.with({ path: this.pathroot.path + '/web-files/' + `/${webFile[0]}` }) || fallbackURI));
+ }
+ }
+ return webFilesArray;
+ }
+
+ private contentSnippetHelper = async (fileUri: vscode.Uri): Promise => {
+ const snippetYaml = await vscode.workspace.fs.readFile(fileUri?.with({ path: fileUri.path + '.contentsnippet.yml' }));
+ const snippetValue = await vscode.workspace.fs.readFile(fileUri?.with({ path: fileUri.path + '.contentsnippet.value.html' }));
+ const snippetRecord = load(new TextDecoder().decode(snippetYaml)) as ContentSnippet
+ snippetRecord.adx_value = new TextDecoder().decode(snippetValue);
+ snippetRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ snippetRecord.stateCode = 0;
+ return snippetRecord;
+ };
+
+ private getContentSnippets = async (): Promise => {
+ const contentSnippetsDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/content-snippets' }) || fallbackURI);
+ const contentSnippetsArray: ContentSnippet[] = [];
+ for (const contentSnippet of contentSnippetsDirectory) {
+ const snippetSubDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/content-snippets/' + contentSnippet[0] }) || fallbackURI);
+ for (const snippet of snippetSubDirectory) {
+ if (snippet[0].endsWith(ContextProperty.CONTENT_SNIPPET_YAML)) {
+ contentSnippetsArray.push(await this.contentSnippetHelper(this.pathroot?.with({ path: this.pathroot.path + '/content-snippets/' + contentSnippet[0] + `/${snippet[0].slice(0, -19)}` }) || fallbackURI));
+ }
+ }
+ }
+ return contentSnippetsArray;
+ }
+
+ private entityFormHelper = async (fileUri: vscode.Uri): Promise => {
+ const entityFormYaml = await vscode.workspace.fs.readFile(fileUri);
+ const entityFormRecord = load(new TextDecoder().decode(entityFormYaml)) as EntityForm;
+ entityFormRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return entityFormRecord;
+ };
+
+ private getEntityForms = async (): Promise => {
+ const entityFormsDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/basic-forms' }) || fallbackURI);
+
+ const entityFormsArray: EntityForm[] = [];
+ for (const entityForm of entityFormsDirectory) {
+ entityFormsArray.push(await this.entityFormHelper(this.pathroot?.with({ path: this.pathroot.path + '/basic-forms/' + entityForm[0] + `/${entityForm[0]}.basicform.yml` }) || fallbackURI));
+ }
+ return entityFormsArray;
+ }
+
+ private entityListHelper = async (fileUri: vscode.Uri): Promise => {
+ const entityListYaml = await vscode.workspace.fs.readFile(fileUri);
+ const entityListRecord = load(new TextDecoder().decode(entityListYaml)) as EntityList;
+ entityListRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return entityListRecord;
+ };
+
+ private getEntityLists = async (): Promise => {
+ const entityListsDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/lists' }) || fallbackURI);
+
+ const entityListsArray: EntityList[] = [];
+ for (const entityList of entityListsDirectory) {
+ if (entityList[0].endsWith(ContextProperty.ENTITY_LIST)) {
+ entityListsArray.push(await this.entityListHelper(this.pathroot?.with({ path: this.pathroot.path + '/lists/' + entityList[0] }) || fallbackURI));
+ }
+ }
+ return entityListsArray;
+ }
+
+ private webFormHelper = async (fileUri: vscode.Uri): Promise => {
+ const webFormYaml = await vscode.workspace.fs.readFile(fileUri);
+ const webFormRecord = load(new TextDecoder().decode(webFormYaml)) as WebForm;
+ webFormRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return webFormRecord;
+ };
+
+
+ private getWebForms = async (): Promise => {
+ const webFormsDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/advanced-forms' }) || fallbackURI);
+
+ const webFormsArray: WebForm[] = [];
+ for (const webForm of webFormsDirectory) {
+ webFormsArray.push(await this.webFormHelper(this.pathroot?.with({ path: this.pathroot.path + '/advanced-forms/' + webForm[0] + `/${webForm[0]}.advancedform.yml` }) || fallbackURI));
+ }
+ return webFormsArray;
+ }
+
+ private getSiteSetting = async (): Promise => {
+ const siteSetting = await vscode.workspace.fs.readFile(this.pathroot?.with({ path: this.pathroot.path + '/sitesetting.yml' }) || fallbackURI);
+ const siteSettingYaml = load(new TextDecoder().decode(siteSetting)) as SiteSetting[];
+ const siteSettingRecords = siteSettingYaml.map((siteSettingRecord) => {
+ if (siteSettingRecord.adx_name === BootstrapSiteSetting) {
+ this.isBootstrapV5 = siteSettingRecord.adx_value ? String(siteSettingRecord.adx_value).toLowerCase() === 'true' : false;
+ }
+ return {
+ adx_websiteid: this.websiteData.adx_websiteid,
+ adx_name: siteSettingRecord.adx_name,
+ adx_value: siteSettingRecord.adx_value,
+ adx_sitesettingid: siteSettingRecord.adx_sitesettingid,
+ }
+ });
+ return siteSettingRecords;
+ }
+
+ private getSiteMarker = async (): Promise => {
+ const siteMarker = await vscode.workspace.fs.readFile(this.pathroot?.with({ path: this.pathroot.path + '/sitemarker.yml' }) || fallbackURI);
+ const siteMarkerYaml = load(new TextDecoder().decode(siteMarker)) as SiteMarker[];
+ const siteMarkerRecords = siteMarkerYaml.map((siteMarkerRecord) => {
+ return {
+ adx_name: siteMarkerRecord.adx_name as string,
+ adx_pageid: siteMarkerRecord.adx_pageid as string,
+ adx_sitemarkerid: siteMarkerRecord.adx_sitemarkerid,
+ adx_websiteid: this.websiteData.adx_websiteid,
+
+ }
+
+ });
+ return siteMarkerRecords;
+ }
+
+ private getWeblinks = async (): Promise => {
+ const weblinksDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets' }) || fallbackURI);
+
+ const weblinksArray: Weblink[] = [];
+ for (const link of weblinksDirectory) {
+ const linkSubDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets/' + link[0] }) || fallbackURI);
+ for (const sublink of linkSubDirectory) {
+ if (sublink[0].endsWith(ContextProperty.WEB_LINK)) {
+ const weblinkYaml = await vscode.workspace.fs.readFile(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets/' + link[0] + `/${sublink[0]}` }) || fallbackURI);
+ const weblinkRecord = load(new TextDecoder().decode(weblinkYaml)) as Weblink[]
+ weblinksArray.push(...weblinkRecord);
+ }
+ }
+ }
+ return weblinksArray;
+ }
+
+ private webLinkSetHelper = async (fileUri: vscode.Uri): Promise => {
+ const weblinkSetYaml = await vscode.workspace.fs.readFile(fileUri);
+ const weblinkSetRecord = load(new TextDecoder().decode(weblinkSetYaml)) as WeblinkSet;
+ weblinkSetRecord.adx_websiteid = this.websiteData.adx_websiteid;
+ return weblinkSetRecord;
+ };
+
+ private getWeblinkSets = async (): Promise => {
+ const weblinkSetsDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets' }) || fallbackURI);
+
+ const weblinkSetsArray: WeblinkSet[] = [];
+ for (const weblinkSet of weblinkSetsDirectory) {
+ const linkSubDirectory = await vscode.workspace.fs.readDirectory(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets/' + weblinkSet[0] }) || fallbackURI);
+ for (const sublink of linkSubDirectory) {
+ if (sublink[0].endsWith(ContextProperty.WEB_LINK_SET)) {
+ weblinkSetsArray.push(await this.webLinkSetHelper(this.pathroot?.with({ path: this.pathroot.path + '/weblink-sets/' + weblinkSet[0] + `/${sublink[0]}` }) || fallbackURI)); // adx_title not in pac data but is manadatory, studio sends as undefined.
+ }
+ }
+ }
+ return weblinkSetsArray;
+ }
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/DataParser.ts b/src/common/TreeStructure/DataParser.ts
new file mode 100644
index 00000000..3edb4c7e
--- /dev/null
+++ b/src/common/TreeStructure/DataParser.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+import { Tokenizer, TokenKind } from "liquidjs";
+import { OutputToken, TagToken } from "liquidjs/dist/tokens";
+import { DataParserRule, ruleDefinitions, DyanmicEntity } from "./DataParserRule";
+
+const rules: DataParserRule[] = [];
+ruleDefinitions.forEach(rule => rules.push(rule))
+
+export const getDependencies = (content: string): DyanmicEntity[] => {
+ const tokenizer = new Tokenizer(content);
+ const liquidTokens = tokenizer.readTopLevelTokens();
+ const allDependencey: DyanmicEntity[] = [];
+ liquidTokens.forEach(token => {
+ if (token.kind !== TokenKind.HTML) {
+ const info = checkRule(token as TagToken | OutputToken);
+ allDependencey.push(...info);
+ }
+ });
+ return allDependencey;
+};
+
+const checkRule = (liquidToken: TagToken | OutputToken): DyanmicEntity[] => {
+ return rules
+ .map(r => {
+ if (r.isValid(liquidToken)) {
+ const info = r.apply(liquidToken)
+ return info;
+ } else {
+ return []
+ }
+ })
+ .reduce(function (prev, next) {
+ return prev.concat(next);
+ }, []);
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/DataParserRule.ts b/src/common/TreeStructure/DataParserRule.ts
new file mode 100644
index 00000000..26c3c9eb
--- /dev/null
+++ b/src/common/TreeStructure/DataParserRule.ts
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+import { TagToken, Tokenizer, TokenKind, Value } from "liquidjs";
+import { OutputToken, PropertyAccessToken } from "liquidjs/dist/tokens";
+import { PortalObjects, PortalTags } from "../../server/constants/PortalEnums";
+
+export interface DyanmicEntity {
+ tagName: string,
+ property: string;
+ fileNameOrID?: string;
+}
+
+export interface DataParserRule {
+ name: string,
+ isValid: (liquidToken: TagToken | OutputToken) => boolean
+ apply: (liquidToken: TagToken | OutputToken) => DyanmicEntity[]
+}
+
+const snippetObjectRule: DataParserRule = {
+ name: 'snippetObject',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Output && liquidToken.content.includes(PortalObjects.SNIPPETS),
+ apply: (liquidToken) => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer(liquidToken.content)
+ const property = tokenizer.readIdentifier().getText();
+ const value = tokenizer.readValue() as PropertyAccessToken;
+ const fileNameOrID = value.propertyName;
+ const tagName = PortalObjects.SNIPPETS;
+ entities.push({ tagName, property, fileNameOrID });
+ return entities;
+ }
+}
+
+
+const entityFormTagRule: DataParserRule = {
+ name: 'entityFormTag',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Tag && (liquidToken as TagToken).name.toLowerCase() === PortalTags.ENTITYFORM,
+ apply: (liquidToken) => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer((liquidToken as TagToken).args)
+ const hashes = tokenizer.readHashes();
+ hashes.forEach(hash => {
+ const property = hash.name.getText()
+ const fileNameOrID = hash.value?.getText()
+ if (['id', 'name', 'key'].includes(property)) {
+ const tagName = PortalTags.ENTITYFORM;
+ entities.push({ tagName, property, fileNameOrID });
+ }
+ })
+ return entities
+ }
+}
+
+const entityListTagRule: DataParserRule = {
+ name: 'entityListTag',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Tag && (liquidToken as TagToken).name.toLowerCase() === PortalTags.ENTITYLIST,
+ apply: (liquidToken) => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer((liquidToken as TagToken).args)
+ const hashes = tokenizer.readHashes();
+ hashes.forEach(hash => {
+ const property = hash.name.getText()
+ const fileNameOrID = hash.value?.getText()
+ if (['id', 'name', 'key'].includes(property)) {
+ const tagName = PortalTags.ENTITYLIST;
+ entities.push({ tagName, property, fileNameOrID });
+ }
+ })
+ return entities;
+ }
+}
+
+const webFormTagRule: DataParserRule = {
+ name: 'webFormTag',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Tag && (liquidToken as TagToken).name.toLowerCase() === PortalTags.WEBFORM,
+ apply: (liquidToken) => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer((liquidToken as TagToken).args)
+ const hashes = tokenizer.readHashes();
+ hashes.forEach(hash => {
+ const property = hash.name.getText()
+ const fileNameOrID = hash.value?.getText()
+ if (['id', 'name', 'key'].includes(property)) {
+ const tagName = PortalTags.WEBFORM;
+ entities.push({ tagName, property, fileNameOrID });
+ }
+ })
+ return entities;
+ }
+}
+
+const includeTagRule: DataParserRule = {
+ name: 'includeTag',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Tag && (liquidToken as TagToken).name.toLowerCase() === PortalTags.INCLUDE,
+ apply: (tagToken: TagToken | OutputToken): DyanmicEntity[] => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer((tagToken as TagToken).args);
+ const value = tokenizer.readValue();
+ const hashes = tokenizer.readHashes();
+ //Handling case - {% include 'Search' %}
+ if (hashes.length == 0) {
+ const property = "name";
+ const fileNameOrID = value?.getText() || '';
+ const tagName = "Web Template";
+ entities.push({ tagName, property, fileNameOrID });
+ } else {
+ hashes.forEach(hash => {
+ const tagName = value?.getText() || '';
+ const property = hash.name.getText().toLowerCase();
+ const fileNameOrID = hash.value?.getText();
+ entities.push({ tagName, property, fileNameOrID });
+ });
+ }
+ return entities;
+ }
+};
+
+const editableTagRule: DataParserRule = {
+ name: 'editableTag',
+ isValid: (liquidToken) => liquidToken.kind === TokenKind.Tag && (liquidToken as TagToken).name.toLowerCase() === PortalTags.EDITABLE,
+ apply: (liquidToken) => {
+ const entities: DyanmicEntity[] = [];
+ const tokenizer = new Tokenizer((liquidToken as TagToken).args)
+ const property = tokenizer.readIdentifier().getText();
+ const value = tokenizer.readValue()
+ const fileNameOrID = value?.getText() || '';
+ const tagName = PortalTags.EDITABLE;
+ entities.push({ tagName, property, fileNameOrID });
+ return entities;
+ }
+}
+
+
+
+export const ruleDefinitions = [
+ includeTagRule,
+ editableTagRule,
+ entityFormTagRule,
+ webFormTagRule,
+ entityListTagRule,
+ snippetObjectRule,
+]
+
diff --git a/src/common/TreeStructure/MyReferenceProvider.ts b/src/common/TreeStructure/MyReferenceProvider.ts
new file mode 100644
index 00000000..e0056754
--- /dev/null
+++ b/src/common/TreeStructure/MyReferenceProvider.ts
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+import * as vscode from 'vscode';
+import * as fs from 'fs';
+import { getDependencies } from "./DataParser";
+import { DyanmicEntity } from './DataParserRule';
+import { IItem } from './TreeView/Types/Entity/IItem';
+import { globalWebsiteIItem, globalwebPageIItem } from './DataMapper';
+
+export class MyReferenceProvider implements vscode.ReferenceProvider {
+ async provideReferences(
+ document: vscode.TextDocument,
+ position: vscode.Position,
+ context: vscode.ReferenceContext,
+ token: vscode.CancellationToken
+ ): Promise {
+ const selection = vscode.window.activeTextEditor?.selection;
+ if (!selection) {
+ return [];
+ }
+ const startLine = selection.start.line;
+ const endLine = selection.end.line;
+
+ const selectedLines: string[] = [];
+ for (let line = startLine; line <= endLine; line++) {
+ const lineText = document.lineAt(line).text;
+ selectedLines.push(lineText);
+ }
+ const selectedText = document.getText(selection);
+ const selectedTextLine = selectedLines.join('\n');
+ const dependencies = getDependencies(selectedTextLine);
+ const locations: vscode.Location[] = [];
+ if (dependencies.length === 0) {
+ findText(selectedText, globalWebsiteIItem, locations);
+ } else {
+ processDependencies(dependencies, locations);
+ }
+ return locations;
+ }
+}
+
+function findText(selectedText: string, globalWebsiteIItem: IItem, locations: vscode.Location[]) {
+ for (const entityIItem of globalWebsiteIItem.children) {
+ if (entityIItem.label == 'Web Page') {
+ globalwebPageIItem.children.forEach((item: IItem) => {
+ const pgcy = item.children.find(child => child.label === "Page Copy");
+ const pgsy = item.children.find(child => child.label === "Page Summary");
+ const cp = item.children.find(child => child.label === "Content Page")
+ const cppgcy = cp?.children.find(child => child.label === "Page Copy");
+ const cppgsy = cp?.children.find(child => child.label === "Page Summary");
+
+ findTextInFile(pgcy, selectedText, locations);
+ findTextInFile(pgsy, selectedText, locations);
+ findTextInFile(cppgcy, selectedText, locations);
+ findTextInFile(cppgsy, selectedText, locations);
+ })
+ } else {
+ for (const iitem of entityIItem.children) {
+ findTextInFile(iitem, selectedText, locations);
+ }
+ }
+ }
+}
+
+function findTextInFile(entityIItem: any, selectedText: any, locations: vscode.Location[]) {
+ let file = entityIItem.children.find((child: IItem) => child.isFile === true);
+ const filePath = file?.path?.fsPath;
+ if (!filePath) {
+ return;
+ }
+
+ try {
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
+ const lines = fileContent.split(/\r?\n/);
+
+ for (let i = 0; i < lines.length; i++) {
+ let startIndex = 0;
+ while ((startIndex = lines[i].indexOf(selectedText, startIndex)) !== -1) {
+ const entityPosition = new vscode.Position(i, startIndex);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ startIndex += selectedText.length;
+ }
+ }
+ } catch (error) {
+ console.error('Error reading file:', error);
+ }
+}
+
+function processDependencies(dependencies: DyanmicEntity[], locations: vscode.Location[]) {
+ dependencies.forEach((entity: any) => {
+ const tagName = entity.tagName.replace(/^['"](.*)['"]$/, '$1');
+ const property = entity.property.replace(/^['"](.*)['"]$/, '$1');
+ const fileNameOrID = entity.fileNameOrID.replace(/^['"](.*)['"]$/, '$1');
+ if (tagName === "snippets" || tagName === "snippet" || (tagName === 'editable' && (property === "snippets" || property === "snippet"))) {
+ const contentSnippetIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Content Snippets');
+ if (contentSnippetIItem) {
+ processEntity(contentSnippetIItem, entity, locations, 'label', '07');
+ }
+ } else if (tagName === "Web Template") {
+ const webtemplateIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Web Templates');
+ if (webtemplateIItem) {
+ processEntity(webtemplateIItem, entity, locations, 'label', '08');
+ }
+ } else if (tagName === "entityform" || tagName === "entity_form") {
+ const entityFormtIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Basic Forms');
+ if (entityFormtIItem) {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(entityFormtIItem, entity, locations, 'id', '015');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(entityFormtIItem, entity, locations, 'label', '015')
+ } else {
+ console.log("Not Valid EnitityForm");
+ }
+ }
+ } else if (tagName === "entitylist" || tagName === "entity_list") {
+ const listIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Lists');
+ if (listIItem) {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(listIItem, entity, locations, 'id', '017');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(listIItem, entity, locations, 'label', '017')
+ } else {
+ console.log("Not Valid EntityList");
+ }
+ }
+ } else if (tagName === "webform") {
+ const webFormIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Advanced Forms');
+ if (webFormIItem) {
+ if (property == 'id' && isNaN(fileNameOrID)) {
+ processEntity(webFormIItem, entity, locations, 'id', '019');
+ } else if (property == 'name' || property == 'key') {
+ processEntity(webFormIItem, entity, locations, 'label', '019')
+ } else {
+ console.log("Not Valid WebForm");
+ }
+ }
+ } else if ((tagName != "entityform" && tagName != "entity_form") && (tagName != "entitylist" && tagName != "entity_list") && tagName !== "editable") {
+ entity.fileNameOrID = tagName;
+ entity.tagName = 'Web Template';
+ const webtemplateIItem = globalWebsiteIItem.children.find((child: IItem) => child.label === 'Web Templates');
+ if (webtemplateIItem) {
+ processEntity(webtemplateIItem, entity, locations, 'label', '08');
+ }
+ } else {
+ console.log("Another Dynamic entity");
+ }
+ })
+}
+
+
+function processEntity(targetIItem: IItem, entity: any, locations: vscode.Location[], compareBy: string, comp: string) {
+ const fileNameOrID = entity.fileNameOrID.replace(/^['"](.*)['"]$/, '$1');
+ const tagName = entity.tagName.replace(/^['"](.*)['"]$/, '$1');
+ targetIItem.children.forEach((targetItem: IItem) => {
+ const compareValue = compareBy === 'label' ? targetItem.label : targetItem.id;
+ if (compareValue === fileNameOrID) {
+ const IITem = targetItem.parentList;
+ if (IITem) {
+ for (const iitem of IITem) {
+ const file = iitem.children.find((child: IItem) => child.isFile === true);
+ if (file) {
+ addFileLocations(file, locations, entity);
+ }
+ }
+ }
+ }
+ });
+}
+
+function addFileLocations(file: IItem, locations: vscode.Location[], entity: DyanmicEntity) {
+ const filePath = file?.path?.fsPath;
+ if (!filePath) {
+ return;
+ }
+ try {
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
+ const lines = fileContent.split(/\r?\n/);
+ let file = entity.fileNameOrID?.replace(/^['"](.*)['"]$/, '$1');
+ let tagName = entity.tagName.replace(/^['"](.*)['"]$/, '$1');
+ const property = entity.property.replace(/^['"](.*)['"]$/, '$1');
+
+ if (!file) {
+ return;
+ }
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].includes(file)) {
+ const dep = getDependencies(lines[i]);
+ dep.forEach((de: any) => {
+ let tag = de.tagName.replace(/^['"](.*)['"]$/, '$1');
+ const pro = de.property.replace(/^['"](.*)['"]$/, '$1');
+ let fn = de.fileNameOrID?.replace(/^['"](.*)['"]$/, '$1');
+ if (tag !== 'snippets' && tag !== 'snippet' && tag !== 'editable' && tag !== 'Web Template' && tag !== "webform" && tag !== "entityform" && tag !== "entity_form" && tag !== "entitylist" && tag !== "entity_list") {
+ fn = tag;
+ tag = 'Web Template';
+ }
+ if (tag == tagName && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ } else if ((tag == 'snippets' && (tagName === 'snippets' || tagName === 'snippet')) || (tagName == 'snippets' && (tag === 'snippets' || tag === 'snippet')) && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ } else if (tagName === 'editable' && (property === "snippets" || property === "snippet")) {
+ if ((tag === 'snippets' || tag === 'snippet') && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ }
+ } else if (tag === 'editable' && (pro === "snippets" || pro === "snippet")) {
+ if ((tagName === 'snippets' || tagName === 'snippet') && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ }
+ } else if (((tag === 'entity_form' && tagName === 'entityform') || (tagName === 'entity_form' && tag === 'entityform')) && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ } else if (((tag === 'entity_list' && tagName === 'entitylist') || (tagName === 'entity_list' && tag === 'entitylist')) && fn == file) {
+ const entityPosition = new vscode.Position(i, 0);
+ const entityLocation = new vscode.Location(vscode.Uri.file(filePath), entityPosition);
+ locations.push(entityLocation);
+ }
+ })
+ }
+ }
+ } catch (error) {
+ console.error('Error reading file:', error);
+ }
+}
diff --git a/src/common/TreeStructure/TreeView/PortalDrops/PortalDrops.ts b/src/common/TreeStructure/TreeView/PortalDrops/PortalDrops.ts
new file mode 100644
index 00000000..cb62037d
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/PortalDrops/PortalDrops.ts
@@ -0,0 +1,11 @@
+import { Drop } from 'liquidjs';
+import { IDataResolver } from '../Utils/IDataResolver';
+
+export class PortalDrop extends Drop {
+ protected dataResolver: IDataResolver;
+
+ constructor(dataResolver: IDataResolver) {
+ super();
+ this.dataResolver = dataResolver;
+ }
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/AbstractEntity.ts b/src/common/TreeStructure/TreeView/Types/Entity/AbstractEntity.ts
new file mode 100644
index 00000000..a8c15e6c
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/AbstractEntity.ts
@@ -0,0 +1,5 @@
+export interface AbstractEntity {
+ ownerId?: string;
+ stateCode?: number;
+ statusCode?: number;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/ContentSnippet.ts b/src/common/TreeStructure/TreeView/Types/Entity/ContentSnippet.ts
new file mode 100644
index 00000000..e36749db
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/ContentSnippet.ts
@@ -0,0 +1,18 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface ContentSnippet extends AbstractEntity {
+ adx_display_name?: string;
+ adx_value: string;
+ adx_createdbyipaddress?: string;
+ adx_createdbyusername?: string;
+ adx_name: string;
+ adx_modifiedbyipaddress?: string;
+ adx_modifiedbyusername?: string;
+ adx_websiteid: string;
+ adx_websiteidname?: string;
+ adx_contentsnippetlanguageidname?: string;
+ adx_type?: number;
+ adx_contentsnippetlanguageid?: string;
+ adx_typename?: string;
+ adx_contentsnippetid: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/EntityAttributeMetadata.ts b/src/common/TreeStructure/TreeView/Types/Entity/EntityAttributeMetadata.ts
new file mode 100644
index 00000000..b4dda8c8
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/EntityAttributeMetadata.ts
@@ -0,0 +1,7 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface IEntityAttributeMetadata extends AbstractEntity {
+ attributeType: string;
+ localizedDisplayName: string;
+ logicalName: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/EntityForm.ts b/src/common/TreeStructure/TreeView/Types/Entity/EntityForm.ts
new file mode 100644
index 00000000..e787514d
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/EntityForm.ts
@@ -0,0 +1,117 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface EntityForm extends AbstractEntity {
+ adx_appendquerystring?: boolean;
+ adx_appendquerystringname?: string;
+ adx_associatecurrentportaluser?: boolean;
+ adx_associatecurrentportalusername?: string;
+ adx_attachfile?: boolean;
+ adx_attachfileaccept?: string;
+ adx_attachfileacceptextensions?: string;
+ adx_attachfileallowmultiple?: boolean;
+ adx_attachfilelabel?: string;
+ adx_attachfilemaxsize?: number;
+ adx_attachfilename?: string;
+ adx_attachfilerequired?: boolean;
+ adx_attachfilerequirederrormessage?: string;
+ adx_attachfilerequiredname?: string;
+ adx_attachfilerestrictaccept?: boolean;
+ adx_attachfilesaveoption?: number;
+ adx_attachfilesizeerrormessage?: string;
+ adx_attachfilestoragelocation?: number;
+ adx_attachfiletypeerrormessage?: string;
+ adx_autogeneratesteps?: boolean;
+ adx_autogeneratestepsname?: string;
+ adx_captcharequired?: boolean;
+ adx_captcharequiredname?: string;
+ adx_entityformid: string;
+ adx_entityname: string;
+ adx_entitypermissionsenabled?: boolean;
+ adx_entitysourcetype?: number;
+ adx_forceallfieldsrequired?: boolean;
+ adx_formname: string;
+ adx_geolocation_addresslinefieldname?: string;
+ adx_geolocation_cityfieldname?: string;
+ adx_geolocation_countryfieldname?: string;
+ adx_geolocation_countyfieldname?: string;
+ adx_geolocation_displaymap?: boolean;
+ adx_geolocation_enabled?: boolean;
+ adx_geolocation_formattedaddressfieldname?: string;
+ adx_geolocation_latitudefieldname?: string;
+ adx_geolocation_longitudefieldname?: string;
+ adx_geolocation_maptype?: number;
+ adx_geolocation_neighborhoodfieldname?: string;
+ adx_geolocation_postalcodefieldname?: string;
+ adx_geolocation_statefieldname?: string;
+ adx_hideformonsuccess?: boolean;
+ adx_instructions?: string;
+ adx_mode?: number;
+ adx_modename?: string;
+ adx_name: string;
+ adx_nextbuttoncssclass?: string;
+ adx_nextbuttontext?: string;
+ adx_onsuccess?: number;
+ adx_populatereferenceentitylookupfield?: boolean;
+ adx_populatereferenceentitylookupfieldname?: string;
+ adx_portaluserlookupattributeisactivityparty?: boolean;
+ adx_portaluserlookupattributeisactivitypartyname?: string;
+ adx_previousbuttoncssclass?: string;
+ adx_previousbuttontext?: string;
+ adx_primarykeyname?: string;
+ adx_provisionedlanguages?: number;
+ adx_recommendedfieldsrequired?: boolean;
+ adx_recommendedfieldsrequiredname?: string;
+ adx_recordidquerystringparametername?: string;
+ adx_recordnotfoundmessage?: string;
+ adx_recordsourceallowcreateonnull?: boolean;
+ adx_recordsourceentitylogicalname?: string;
+ adx_recordsourcerelationshipname?: string;
+ adx_redirecturl?: string;
+ adx_redirecturlappendentityidquerystring?: boolean;
+ adx_redirecturlappendentityidquerystringname?: string;
+ adx_redirecturlcustomquerystring?: string;
+ adx_redirecturlquerystringattribute?: string;
+ adx_redirecturlquerystringattributeparamname?: string;
+ adx_redirecturlquerystringname?: string;
+ adx_redirectwebpage?: string;
+ adx_redirectwebpagename?: string;
+ adx_referenceentitylogicalname?: string;
+ adx_referenceentityprimarykeylogicalname?: string;
+ adx_referenceentityreadonlyformname?: string;
+ adx_referenceentityrelationshipname?: string;
+ adx_referenceentityshowreadonlyform?: boolean;
+ adx_referenceentityshowreadonlyformname?: string;
+ adx_referenceentitysourcetype?: number;
+ adx_referenceentitysourcetypename?: string;
+ adx_referencequeryattributelogicalname?: string;
+ adx_referencequerystringisprimarykey?: boolean;
+ adx_referencequerystringisprimarykeyname?: string;
+ adx_referencequerystringname?: string;
+ adx_referencerecordsourcerelationshipname?: string;
+ adx_referencetargetlookupattributelogicalname?: string;
+ adx_registerstartupscript?: string;
+ adx_renderwebresourcesinline?: boolean;
+ adx_setentityreference?: boolean;
+ adx_setentityreferencename?: string;
+ adx_settings?: string;
+ adx_showcaptchaforauthenticatedusers?: boolean;
+ adx_showcaptchaforauthenticatedusersname?: string;
+ adx_showownerfields?: boolean;
+ adx_showownerfieldsname?: string;
+ adx_showunsupportedfields?: boolean;
+ adx_showunsupportedfieldsname?: string;
+ adx_submitbuttonbusytext?: string;
+ adx_submitbuttoncssclass?: string;
+ adx_submitbuttontext?: string;
+ adx_successmessage: string;
+ adx_tabname?: string;
+ adx_targetentityportaluserlookupattribute?: string;
+ adx_tooltipenabled?: boolean;
+ adx_validationgroup?: string;
+ adx_validationsummarycssclass?: string;
+ adx_validationsummaryheadertext?: string;
+ adx_validationsummarylinksenabled?: boolean;
+ adx_validationsummarylinktext?: string;
+ adx_websiteid: string;
+ adx_websiteidname?: string;
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/EntityFormMetadata.ts b/src/common/TreeStructure/TreeView/Types/Entity/EntityFormMetadata.ts
new file mode 100644
index 00000000..21d93467
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/EntityFormMetadata.ts
@@ -0,0 +1,57 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface EntityFormMetadata extends AbstractEntity {
+ adx_adddescription?: boolean;
+ adx_adddescriptionname?: string;
+ adx_attributelogicalname?: string;
+ adx_constantsummaximumtotal?: number;
+ adx_constantsumminimumtotal?: number;
+ adx_constantsumvalidationerrormessage?: string;
+ adx_controlstyle?: number;
+ adx_cssclass?: string;
+ adx_description?: string;
+ adx_descriptionposition?: number;
+ adx_entityform: string;
+ adx_entityformforcreate?: string;
+ adx_entityformforcreatename?: string;
+ adx_entityformmetadataid: string;
+ adx_entityformname?: string;
+ adx_fieldisrequired?: boolean;
+ adx_geolocationvalidatorerrormessage?: string;
+ adx_groupname?: string;
+ adx_ignoredefaultvalue?: boolean;
+ adx_label?: string;
+ adx_maxmultiplechoiceselectedcount?: number;
+ adx_minmultiplechoiceselectedcount?: number;
+ adx_multiplechoicevalidationerrormessage?: string;
+ adx_name?: string;
+ adx_notes_settings?: string;
+ adx_onsavefromattribute?: string;
+ adx_onsavetype?: number;
+ adx_onsavetypename?: string;
+ adx_onsavevalue?: string;
+ adx_prepopulatefromattribute?: string;
+ adx_prepopulatetype?: number;
+ adx_prepopulatetypename?: string;
+ adx_prepopulatevalue?: string;
+ adx_provisionedlanguages?: number;
+ adx_randomizeoptionsetvalues?: boolean;
+ adx_randomizeoptionsetvaluesname?: string;
+ adx_rangevalidationerrormessage?: string;
+ adx_rankordernotiesvalidationerrormessage?: string;
+ adx_requiredfieldvalidationerrormessage?: string;
+ adx_sectionname?: string;
+ adx_setvalueonsave?: boolean;
+ adx_setvalueonsavename?: string;
+ adx_subgrid_name?: string;
+ adx_subgrid_settings?: string;
+ adx_tabname?: string;
+ adx_timeline_settings?: string;
+ adx_type: number;
+ adx_typename?: string;
+ adx_useattributedescriptionproperty?: boolean;
+ adx_useattributedescriptionpropertyname?: string;
+ adx_validationerrormessage?: string;
+ adx_validationregularexpression?: string;
+ adx_validationregularexpressionerrormessage?: string;
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/EntityList.ts b/src/common/TreeStructure/TreeView/Types/Entity/EntityList.ts
new file mode 100644
index 00000000..c8893ad0
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/EntityList.ts
@@ -0,0 +1,84 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface EntityList extends AbstractEntity {
+ adx_provisionedlanguages?: number;
+ adx_calendar_stylename?: string;
+ adx_calendar_initialviewname?: string;
+ adx_calendar_initialdate?: Date;
+ adx_map_longitude?: string;
+ adx_filter_applybuttonlabel?: string;
+ adx_map_infoboxdescriptionfieldname?: string;
+ adx_map_distanceunitsname?: string;
+ adx_map_infoboxtitlefieldname?: string;
+ adx_odata_enabled?: boolean;
+ adx_calendar_alldayfieldname?: string;
+ adx_calendar_enddatefieldname?: string;
+ adx_entitypermissionsenabledname?: string;
+ adx_map_type?: number;
+ adx_pagesize: number;
+ adx_filteraccount?: string;
+ adx_entitylistid: string;
+ adx_websiteidname?: string;
+ adx_idquerystringparametername?: string;
+ adx_filterwebsite?: string;
+ adx_map_distanceunits?: number;
+ adx_map_credentials?: string;
+ adx_map_latitudefieldname?: string;
+ adx_calendar_organizerfieldname?: string;
+ adx_map_pushpinwidth?: number;
+ adx_calendar_enabledname?: string;
+ adx_odata_entitysetname?: string;
+ adx_odata_entitytypename?: string;
+ adx_map_pushpinurl?: string;
+ adx_filter_enabled?: boolean;
+ adx_filter_definition?: string;
+ adx_views: string;
+ adx_webpagefordetailsviewname?: string;
+ adx_filter_enabledname?: string;
+ adx_websiteid: string;
+ adx_map_pushpinheight?: number;
+ adx_filter_orientation?: number;
+ adx_registerstartupscript?: string;
+ adx_createbuttonlabel?: string;
+ adx_map_resturl?: string;
+ adx_entitypermissionsenabled?: boolean;
+ adx_map_typename?: string;
+ adx_calendar_timezone?: number;
+ adx_map_infoboxoffsetx?: number;
+ adx_map_zoom?: number;
+ adx_key?: string;
+ adx_view?: string;
+ adx_calendar_timezonemodename?: string;
+ adx_filterportaluser?: string;
+ adx_calendar_descriptionfieldname?: string;
+ adx_map_distancevalues?: string;
+ adx_detailsbuttonlabel?: string;
+ adx_searchenabledname?: string;
+ adx_calendar_locationfieldname?: string;
+ adx_searchplaceholdertext?: string;
+ adx_webpageforcreatename?: string;
+ adx_primarykeyname?: string;
+ adx_settings?: string;
+ adx_calendar_initialview?: number;
+ adx_searchenabled?: boolean;
+ adx_calendar_enabled?: boolean;
+ adx_name: string;
+ adx_calendar_startdatefieldname?: string;
+ adx_calendar_style?: number;
+ adx_entityname: string;
+ adx_map_enabledname?: string;
+ adx_map_enabled?: boolean;
+ adx_map_latitude?: string;
+ adx_webpageforcreate?: string;
+ adx_webpagefordetailsview?: string;
+ adx_filter_orientationname?: string;
+ adx_emptylisttext?: string;
+ adx_calendar_timezonemode?: number;
+ adx_odata_enabledname?: string;
+ adx_searchtooltiptext?: string;
+ adx_calendar_summaryfieldname?: string;
+ adx_odata_view?: string;
+ adx_map_infoboxoffsety?: number;
+ adx_map_longitudefieldname?: string;
+ adx_iscodecomponent?: boolean;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/IItem.ts b/src/common/TreeStructure/TreeView/Types/Entity/IItem.ts
new file mode 100644
index 00000000..f781b77e
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/IItem.ts
@@ -0,0 +1,14 @@
+import * as vscode from 'vscode';
+
+export interface IItem {
+ label: string;
+ title: string;
+ id: string;
+ isFile: boolean;
+ content: string;
+ path?: vscode.Uri;
+ component: string;
+ children: IItem[];
+ error: string;
+ parentList: IItem[];
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/PageTemplate.ts b/src/common/TreeStructure/TreeView/Types/Entity/PageTemplate.ts
new file mode 100644
index 00000000..6495f5cb
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/PageTemplate.ts
@@ -0,0 +1,19 @@
+export interface PageTemplate {
+ adx_description?: string;
+ adx_webtemplateid?: string;
+ adx_isdefaultname?: string;
+ adx_name: string;
+ adx_typename?: string;
+ adx_usewebsiteheaderandfootername?: string;
+ adx_entityname?: string;
+ adx_usewebsiteheaderandfooter?: boolean;
+ adx_websiteid?: string;
+ adx_isdefault?: boolean;
+ adx_websiteidname?: string;
+ adx_webtemplateidname?: string;
+ adx_type?: number;
+ adx_pagetemplateid: string;
+ adx_botconsumerid?: string;
+ adx_rewriteurl?: string;
+ adx_botconsumeridname?: string;
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/SiteMarker.ts b/src/common/TreeStructure/TreeView/Types/Entity/SiteMarker.ts
new file mode 100644
index 00000000..e09690e8
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/SiteMarker.ts
@@ -0,0 +1,10 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface SiteMarker extends AbstractEntity {
+ adx_websiteid: string;
+ adx_name: string;
+ adx_pageidname?: string;
+ adx_websiteidname?: string;
+ adx_pageid: string;
+ adx_sitemarkerid: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/SiteSettings.ts b/src/common/TreeStructure/TreeView/Types/Entity/SiteSettings.ts
new file mode 100644
index 00000000..9a4f5353
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/SiteSettings.ts
@@ -0,0 +1,10 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface SiteSetting extends AbstractEntity {
+ adx_websiteid: string;
+ adx_description?: string;
+ adx_value?: string;
+ adx_name: string;
+ adx_websiteidname?: string;
+ adx_sitesettingid: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebFile.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebFile.ts
new file mode 100644
index 00000000..108f13c0
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebFile.ts
@@ -0,0 +1,19 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WebFile extends AbstractEntity {
+ adx_contentdisposition: number;
+ adx_enabletracking: boolean;
+ adx_excludefromsearch: boolean;
+ adx_hiddenfromsitemap: boolean;
+ adx_name: string;
+ adx_parentpageid: string;
+ adx_partialurl: string;
+ adx_publishingstateid: string;
+ adx_webfileid: string;
+ annotationid: string;
+ filename: string;
+ isdocument: boolean;
+ mimetype: string;
+ objectid: string;
+ objecttypecode: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebForm.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebForm.ts
new file mode 100644
index 00000000..798b1b5b
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebForm.ts
@@ -0,0 +1,36 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WebForm extends AbstractEntity {
+ adx_progressindicatorpositionname?: string;
+ adx_savechangeswarningmessage?: string;
+ adx_progressindicatorposition?: number;
+ adx_name: string;
+ adx_editexpiredstatuscode?: number;
+ adx_startstep?: string;
+ adx_editexpiredstatecode?: number;
+ adx_editnotpermittedmessage?: string;
+ adx_websiteid: string;
+ adx_editexistingrecordpermittedname?: string;
+ adx_progressindicatortypename?: string;
+ adx_progressindicatorprependstepnum?: boolean;
+ adx_progressindicatorignorelaststep?: boolean;
+ adx_progressindicatorenabled?: boolean;
+ adx_multiplerecordsperuserpermitted?: boolean;
+ adx_authenticationrequired?: boolean;
+ adx_provisionedlanguages?: number;
+ adx_authenticationrequiredname?: string;
+ adx_startnewsessiononloadname?: string;
+ adx_startstepname?: string;
+ adx_startnewsessiononload?: boolean;
+ adx_progressindicatorprependstepnumname?: string;
+ adx_editexpiredmessage?: string;
+ adx_savechangeswarningonclose?: boolean;
+ adx_webformid: string;
+ adx_progressindicatorignorelaststepname?: string;
+ adx_editexistingrecordpermitted?: boolean;
+ adx_savechangeswarningonclosename?: string;
+ adx_progressindicatortype?: number;
+ adx_progressindicatorenabledname?: string;
+ adx_multiplerecordsperuserpermittedname?: string;
+ adx_websiteidname?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebFormMetadata.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebFormMetadata.ts
new file mode 100644
index 00000000..41938fb7
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebFormMetadata.ts
@@ -0,0 +1,75 @@
+
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WebFormMetadata extends AbstractEntity {
+ adx_adddescription?: boolean;
+ adx_adddescriptionname?: string;
+ adx_attributelogicalname: string;
+ adx_constantsummaximumtotal?: number;
+ adx_constantsumminimumtotal?: number;
+ adx_constantsumvalidationerrormessage?: string;
+ adx_controlstyle?: number;
+ adx_cssclass?: string;
+ adx_description?: string;
+ adx_descriptionposition?: number;
+ adx_entityformforcreate?: string;
+ adx_entityformforcreateinwebformmetadata?: string;
+ adx_entityformforcreatename?: string;
+ adx_fieldisrequired?: boolean;
+ adx_geolocationvalidatorerrormessage?: string;
+ adx_groupname?: string;
+ adx_ignoredefaultvalue?: boolean;
+ adx_label?: string;
+ adx_maxmultiplechoiceselectedcount?: number;
+ adx_minmultiplechoiceselectedcount?: number;
+ adx_multiplechoicevalidationerrormessage?: string;
+ adx_notes_settings?: string;
+ adx_onsavefromattribute?: string;
+ adx_onsavetype?: number;
+ adx_onsavetypename?: string;
+ adx_onsavevalue?: string;
+ adx_prepopulatefromattribute?: string;
+ adx_prepopulatetype?: number;
+ adx_prepopulatetypename?: string;
+ adx_prepopulatevalue?: string;
+ adx_provisionedlanguages?: number;
+ adx_purchasecreateinvoiceonpayment?: boolean;
+ adx_purchasefulfillorderonpayment?: boolean;
+ adx_purchaselineitemdescriptionattribute?: string;
+ adx_purchaselineiteminstructionsattribute?: string;
+ adx_purchaselineitemorderattribute?: string;
+ adx_purchaselineitemproductattribute?: string;
+ adx_purchaselineitemquantityattribute?: string;
+ adx_purchaselineitemrelationship?: string;
+ adx_purchaselineitemrequiredattribute?: string;
+ adx_purchaselineitemuomattribute?: string;
+ adx_purchaseoptionalproductsrelationship?: string;
+ adx_purchasequotename?: string;
+ adx_purchaserequiredproductsrelationship?: string;
+ adx_purchaserequiresshipping?: boolean;
+ adx_purchasetargetentityinvoicerelationship?: string;
+ adx_purchasetargetentityorderrelationship?: string;
+ adx_purchasetargetentityrelationship?: string;
+ adx_randomizeoptionsetvalues?: boolean;
+ adx_randomizeoptionsetvaluesname?: string;
+ adx_rangevalidationerrormessage?: string;
+ adx_rankordernotiesvalidationerrormessage?: string;
+ adx_requiredfieldvalidationerrormessage?: string;
+ adx_sectionname?: string;
+ adx_setvalueonsave?: boolean;
+ adx_setvalueonsavename?: string;
+ adx_subgrid_name?: string;
+ adx_subgrid_settings?: string;
+ adx_tabname?: string;
+ adx_timeline_settings?: string;
+ adx_type: number;
+ adx_typename?: string;
+ adx_useattributedescriptionproperty?: boolean;
+ adx_useattributedescriptionpropertyname?: string;
+ adx_validationerrormessage?: string;
+ adx_validationregularexpression?: string;
+ adx_validationregularexpressionerrormessage?: string;
+ adx_webformstep: string;
+ adx_entityformmetadataid?: string;
+ adx_webformstepid?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebFormStep.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebFormStep.ts
new file mode 100644
index 00000000..fae6f0b2
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebFormStep.ts
@@ -0,0 +1,146 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WebFormStep extends AbstractEntity {
+ adx_accept?: string;
+ adx_allowmultiplefiles?: boolean;
+ adx_appendquerystring?: boolean;
+ adx_appendquerystringname?: string;
+ adx_associatecurrentportaluser?: boolean;
+ adx_associatecurrentportalusername?: string;
+ adx_attachfile?: boolean;
+ adx_attachfilelabel?: string;
+ adx_attachfilemaxsize?: number;
+ adx_attachfilename?: string;
+ adx_attachfilerequired?: boolean;
+ adx_attachfilerequirederrormessage?: string;
+ adx_attachfilerequiredname?: string;
+ adx_attachfilerestrictaccept?: boolean;
+ adx_attachfilesizeerrormessage?: string;
+ adx_attachfilestoragelocation?: number;
+ adx_attachfiletypeerrormessage?: string;
+ adx_autogeneratesteps?: boolean;
+ adx_autogeneratestepsname?: string;
+ adx_autonumberattributelogicalname?: string;
+ adx_autonumberdefinitionname?: string;
+ adx_captcharequired?: boolean;
+ adx_captcharequiredname?: string;
+ adx_condition?: string;
+ adx_conditiondefaultnextstep?: string;
+ adx_conditiondefaultnextstepname?: string;
+ adx_createautonumber?: boolean;
+ adx_editexistingrecordpermitted?: boolean;
+ adx_editexpiredmessage?: string;
+ adx_editexpiredstatecode?: number;
+ adx_editexpiredstatusreason?: number;
+ adx_editnotpermittedmessage?: string;
+ adx_entitypermissionsenabled?: boolean;
+ adx_entitysourcestep?: string;
+ adx_entitysourcestepname?: string;
+ adx_entitysourcetype?: number;
+ adx_forceallfieldsrequired?: boolean;
+ adx_formname?: string;
+ adx_geolocation_addresslinefieldname?: string;
+ adx_geolocation_cityfieldname?: string;
+ adx_geolocation_countryfieldname?: string;
+ adx_geolocation_countyfieldname?: string;
+ adx_geolocation_displaymap?: boolean;
+ adx_geolocation_enabled?: boolean;
+ adx_geolocation_formattedaddressfieldname?: string;
+ adx_geolocation_latitudefieldname?: string;
+ adx_geolocation_longitudefieldname?: string;
+ adx_geolocation_maptype?: number;
+ adx_geolocation_neighborhoodfieldname?: string;
+ adx_geolocation_postalcodefieldname?: string;
+ adx_geolocation_statefieldname?: string;
+ adx_hideformonsuccess?: boolean;
+ adx_instructions?: string;
+ adx_loadeventkeyname?: string;
+ adx_loguser?: boolean;
+ adx_mode?: number;
+ adx_modename?: string;
+ adx_movepreviouspermitted?: boolean;
+ adx_multiplerecordsperuserpermitted?: boolean;
+ adx_name: string;
+ adx_nextbuttoncssclass?: string;
+ adx_nextbuttontext?: string;
+ adx_nextstep: string;
+ adx_nextstepname?: string;
+ adx_populatereferenceentitylookupfield?: boolean;
+ adx_populatereferenceentitylookupfieldname?: string;
+ adx_portaluserlookupattributeisactivityparty?: boolean;
+ adx_portaluserlookupattributeisactivitypartyname?: string;
+ adx_postbackurl?: string;
+ adx_previousbuttoncssclass?: string;
+ adx_previousbuttontext?: string;
+ adx_previousstep: string;
+ adx_previousstepname?: string;
+ adx_primarykeyattributelogicalname?: string;
+ adx_primarykeyquerystringparametername?: string;
+ adx_provisionedlanguages?: number;
+ adx_recommendedfieldsrequired?: boolean;
+ adx_recommendedfieldsrequiredname?: string;
+ adx_recordnotfoundmessage?: string;
+ adx_recordsourcerelationshipname?: string;
+ adx_redirecturl?: string;
+ adx_redirecturlappendentityidquerystring?: boolean;
+ adx_redirecturlappendentityidquerystringname?: string;
+ adx_redirecturlcustomquerystring?: string;
+ adx_redirecturlquerystringattribute?: string;
+ adx_redirecturlquerystringattributeparamname?: string;
+ adx_redirecturlquerystringname?: string;
+ adx_redirectwebpage?: string;
+ adx_referenceentitylogicalname?: string;
+ adx_referenceentityprimarykeylogicalname?: string;
+ adx_referenceentityreadonlyformname?: string;
+ adx_referenceentityrelationshipname?: string;
+ adx_referenceentityshowreadonlyform?: boolean;
+ adx_referenceentityshowreadonlyformname?: string;
+ adx_referenceentitysourcetype?: number;
+ adx_referenceentitysourcetypename?: string;
+ adx_referenceentitystep?: string;
+ adx_referenceentitystepname?: string;
+ adx_referencequeryattributelogicalname?: string;
+ adx_referencequerystringisprimarykey?: boolean;
+ adx_referencequerystringisprimarykeyname?: string;
+ adx_referencequerystringname?: string;
+ adx_referencerecordsourcerelationshipname?: string;
+ adx_referencesourceentitylogicalname?: string;
+ adx_referencetargetlookupattributelogicalname?: string;
+ adx_registerstartupscript?: string;
+ adx_renderwebresourcesinline?: boolean;
+ adx_savedeventkeyname?: string;
+ adx_savingeventkeyname?: string;
+ adx_setentityreference?: boolean;
+ adx_setentityreferencename?: string;
+ adx_settings?: string;
+ adx_showcaptchaforauthenticatedusers?: boolean;
+ adx_showcaptchaforauthenticatedusersname?: string;
+ adx_showownerfields?: boolean;
+ adx_showownerfieldsname?: string;
+ adx_showunsupportedfields?: boolean;
+ adx_showunsupportedfieldsname?: string;
+ adx_submitbuttonbusytext?: string;
+ adx_submitbuttoncssclass?: string;
+ adx_submitbuttontext?: string;
+ adx_submiteventkeyname?: string;
+ adx_successmessage: string;
+ adx_tabname?: string;
+ adx_targetentitylogicalname: string;
+ adx_targetentityportaluserlookupattribute?: string;
+ adx_targetentityprimarykeylogicalname?: string;
+ adx_title: string;
+ adx_tooltipenabled?: boolean;
+ adx_type: number;
+ adx_usercontrolpath?: string;
+ adx_usercontroltitle?: string;
+ adx_userhostaddressattributelogicalname?: string;
+ adx_useridentitynameattributelogicalname?: string;
+ adx_validationgroup?: string;
+ adx_validationsummarycssclass?: string;
+ adx_validationsummaryheadertext?: string;
+ adx_validationsummarylinksenabled?: boolean;
+ adx_validationsummarylinktext?: string;
+ adx_webform: string;
+ adx_webformname?: string;
+ adx_webformstepid: string;
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebPage.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebPage.ts
new file mode 100644
index 00000000..431ef6da
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebPage.ts
@@ -0,0 +1,76 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface Webpage extends AbstractEntity {
+ adx_customcss?: string;
+ adx_authoridname?: string;
+ adx_entityform?: string;
+ adx_alloworigin?: string;
+ adx_modifiedbyipaddress?: string;
+ adx_entityformname?: string;
+ adx_meta_description?: string;
+ adx_botconsumeridname?: string;
+ adx_hiddenfromsitemapname?: string;
+ adx_modifiedbyusername?: string;
+ adx_webpagelanguageid?: string;
+ adx_title?: string;
+ adx_createdbyipaddress?: string;
+ adx_websiteidname?: string;
+ adx_editorialcomments?: string;
+ adx_categoryname?: string;
+ adx_authoridyominame?: string;
+ adx_parentpageidname?: string;
+ adx_navigationname?: string;
+ adx_authorid?: string;
+ adx_isrootname?: string;
+ adx_hiddenfromsitemap?: boolean;
+ adx_excludefromsearchname?: string;
+ adx_image?: string;
+ adx_imageurl?: string;
+ adx_publishingstateidname?: string;
+ adx_webform?: string;
+ adx_partialurl: string;
+ adx_displaydate?: Date;
+ adx_websiteid: string;
+ adx_customjavascript?: string;
+ adx_isofflinecachedname?: string;
+ adx_imagename?: string;
+ adx_enabletracking?: boolean;
+ adx_subjectid?: string;
+ adx_rootwebpageidname?: string;
+ adx_webformname?: string;
+ adx_displayorder?: number;
+ adx_isroot: boolean;
+ adx_category?: number;
+ adx_webpagelanguageidname?: string;
+ adx_summary?: string;
+ adx_subjectidname?: string;
+ adx_parentpageid?: string;
+ adx_expirationdate?: Date;
+ adx_entitylist?: string;
+ adx_releasedate?: Date;
+ adx_enabletrackingname?: string;
+ adx_createdbyusername?: string;
+ adx_sharedpageconfigurationname?: string;
+ adx_pagetemplateidname?: string;
+ adx_name: string;
+ adx_excludefromsearch?: boolean;
+ adx_navigation?: string;
+ adx_pagetemplateid: string;
+ adx_feedbackpolicy?: number;
+ adx_botconsumerid?: string;
+ adx_enableratingname?: string;
+ adx_masterwebpageid?: string;
+ adx_entitylistname?: string;
+ adx_feedbackpolicyname?: string;
+ adx_copy?: string;
+ adx_masterwebpageidname?: string;
+ adx_enablerating?: boolean;
+ adx_rootwebpageid?: string;
+ adx_webpageid: string;
+ adx_sharedpageconfiguration?: boolean;
+ adx_publishingstateid?: string;
+ adx_isofflinecached?: boolean;
+ _adx_webform_value?: string;
+ _adx_entitylist_value?: string;
+ _adx_entityform_value?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WebTemplate.ts b/src/common/TreeStructure/TreeView/Types/Entity/WebTemplate.ts
new file mode 100644
index 00000000..40508371
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WebTemplate.ts
@@ -0,0 +1,13 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WebTemplate extends AbstractEntity {
+ adx_mimetype?: string;
+ adx_websiteid: string;
+ adx_source: string;
+ adx_websiteidname?: string;
+ adx_webtemplateid: string;
+ adx_name: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/Weblink.ts b/src/common/TreeStructure/TreeView/Types/Entity/Weblink.ts
new file mode 100644
index 00000000..2ef1feeb
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/Weblink.ts
@@ -0,0 +1,35 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface Weblink extends AbstractEntity {
+ adx_disablepagevalidation?: boolean;
+ adx_imageurl?: string;
+ adx_imagewidth?: number;
+ adx_displaypagechildlinks?: boolean;
+ adx_modifiedbyusername?: string;
+ adx_weblinksetidname?: string;
+ adx_displayorder: number;
+ adx_openinnewwindowname?: string;
+ adx_name: string;
+ adx_displayimageonly?: boolean;
+ adx_weblinksetid: string;
+ adx_imagealttext?: string;
+ adx_createdbyusername?: string;
+ adx_parentweblinkid?: string;
+ adx_modifiedbyipaddress?: string;
+ adx_robotsfollowlink: boolean;
+ adx_description?: string;
+ adx_publishingstateid?: string;
+ adx_disablepagevalidationname?: string;
+ adx_createdbyipaddress?: string;
+ adx_pageidname?: string;
+ adx_weblinkid: string;
+ adx_displaypagechildlinksname?: string;
+ adx_parentweblinkidname?: string;
+ adx_openinnewwindow: boolean;
+ adx_externalurl?: string;
+ adx_displayimageonlyname?: string;
+ adx_robotsfollowlinkname?: string;
+ adx_imageheight?: number;
+ adx_pageid?: string;
+ adx_publishingstateidname?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/WeblinkSet.ts b/src/common/TreeStructure/TreeView/Types/Entity/WeblinkSet.ts
new file mode 100644
index 00000000..df9d2271
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/WeblinkSet.ts
@@ -0,0 +1,15 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface WeblinkSet extends AbstractEntity {
+ adx_publishingstateidname?: string;
+ adx_name: string;
+ adx_weblinksetid: string;
+ adx_copy?: string;
+ adx_websitelanguageidname?: string;
+ adx_websiteidname?: string;
+ adx_websitelanguageid: string;
+ adx_websiteid: string;
+ adx_display_name?: string;
+ adx_publishingstateid?: string;
+ adx_title: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/Entity/Website.ts b/src/common/TreeStructure/TreeView/Types/Entity/Website.ts
new file mode 100644
index 00000000..5102d4f7
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/Entity/Website.ts
@@ -0,0 +1,19 @@
+import { AbstractEntity } from './AbstractEntity';
+
+export interface Website extends AbstractEntity {
+ adx_defaultlanguagename?: string;
+ adx_name?: string;
+ adx_defaultbotconsumerid?: string;
+ adx_defaultlanguage: string;
+ adx_partialurl?: string;
+ adx_headerwebtemplateid?: string;
+ adx_parentwebsiteidname?: string;
+ adx_headerwebtemplateidname?: string;
+ adx_websiteid: string;
+ adx_defaultbotconsumeridname?: string;
+ adx_website_language: number;
+ adx_primarydomainname?: string;
+ adx_footerwebtemplateid?: string;
+ adx_footerwebtemplateidname?: string;
+ adx_parentwebsiteid?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Types/View/WebPage.ts b/src/common/TreeStructure/TreeView/Types/View/WebPage.ts
new file mode 100644
index 00000000..14017124
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Types/View/WebPage.ts
@@ -0,0 +1,22 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+import { WebTemplate } from '../Entity/WebTemplate';
+
+export interface WebpageView {
+ baseURL: string;
+ runtimeCdnRootPath: string;
+ cssWebFiles: string[];
+ runtimeJsAssets: string[];
+ runtimeCssAssets: string[];
+ fontStyles: string[];
+}
+
+export interface WebPageContent {
+ webTemplateContent: string;
+ header: WebTemplate;
+ footer: WebTemplate;
+ customJs?: string;
+ customCss?: string;
+}
diff --git a/src/common/TreeStructure/TreeView/Utils/Constant.ts b/src/common/TreeStructure/TreeView/Utils/Constant.ts
new file mode 100644
index 00000000..409c5e1a
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Utils/Constant.ts
@@ -0,0 +1,37 @@
+export enum ContextProperty {
+ WEBPAGE_YAML = '.webpage.yml',
+ WEBPAGE_COPY = '.webpage.copy.html',
+ WEBPAGE_CSS = '.webpage.custom_css.css',
+ WEBPAGE_JS = '.webpage.custom_javascript.js',
+ WEBPAGE_SUMMARY = '.webpage.summary.html',
+ CONTENT_SNIPPET_YAML = '.contentsnippet.yml',
+ CONTENT_SNIPPET_VALUE = '.contentsnippet.value.html',
+ WEB_TEMPLATE_YAML = '.webtemplate.yml',
+ WEB_TEMPLATE_SOURCE = '.webtemplate.source.html',
+ SITE_MARKER = 'sitemarker.yml',
+ SITE_SETTING = 'sitesetting.yml',
+ ENTITY_LIST = '.list.yml',
+ ENTITY_FORM = '.basicform.yml',
+ WEB_FORM = '.advancedform.yml',
+ WEB_LINK = '.weblink.yml',
+ WEB_LINK_SET = '.weblinkset.yml',
+ WEBSITE = 'website.yml',
+ PAGE_TEMPLATE = '.pagetemplate.yml',
+ UNKNOWN_PROPERTY = ''
+}
+export enum ContextPropertyKey {
+ WEBPAGE = 'adx_webpageid',
+ CONTENT_SNIPPET = 'adx_contentsnippetid',
+ WEB_TEMPLATE = 'adx_webtemplateid',
+ SITE_MARKER = 'adx_sitemarkerid',
+ SITE_SETTING = 'adx_sitesettingid',
+ ENTITY_LIST = 'adx_entitylistid',
+ ENTITY_FORM = 'adx_entityformid',
+ WEB_FORM = 'adx_webformid',
+ WEB_LINK = 'adx_weblinkid',
+ WEB_LINK_SET = 'adx_weblinksetid',
+ WEBSITE = 'adx_websiteid',
+ PAGE_TEMPLATE = 'adx_pagetemplateid',
+}
+
+export const BootstrapSiteSetting = 'Site/BootstrapV5Enabled';
\ No newline at end of file
diff --git a/src/common/TreeStructure/TreeView/Utils/IDataResolver.ts b/src/common/TreeStructure/TreeView/Utils/IDataResolver.ts
new file mode 100644
index 00000000..d45256bd
--- /dev/null
+++ b/src/common/TreeStructure/TreeView/Utils/IDataResolver.ts
@@ -0,0 +1,126 @@
+
+import { ContentSnippet } from '../Types/Entity/ContentSnippet';
+import { EntityForm } from '../Types/Entity/EntityForm';
+import { EntityList } from '../Types/Entity/EntityList';
+import { PageTemplate } from '../Types/Entity/PageTemplate';
+import { SiteMarker } from '../Types/Entity/SiteMarker';
+import { SiteSetting } from '../Types/Entity/SiteSettings';
+import { WebForm } from '../Types/Entity/WebForm';
+import { Weblink } from '../Types/Entity/Weblink';
+import { WeblinkSet } from '../Types/Entity/WeblinkSet';
+import { PortalDrop } from '../PortalDrops/PortalDrops';
+import { WebpageView } from '../Types/View/WebPage';
+import { Webpage } from '../Types/Entity/WebPage';
+import { Website } from '../Types/Entity/Website';
+import { WebFile } from '../Types/Entity/WebFile';
+import { WebTemplate } from '../Types/Entity/WebTemplate';
+import { IEntityAttributeMetadata } from '../Types/Entity/EntityAttributeMetadata';
+
+export type PortalEntity =
+ | Webpage
+ | ContentSnippet
+ | WebTemplate
+ | SiteSetting
+ | SiteMarker
+ | Website
+ | WeblinkSet
+ | WebFile
+ | Weblink;
+
+export interface IPreviewEngineContext {
+ webpages?: Webpage[];
+ contentSnippets?: ContentSnippet[];
+ webTemplates?: WebTemplate[];
+ webFiles?: WebFile[];
+ siteMarkers?: SiteMarker[];
+ siteSettings?: SiteSetting[];
+ entityLists?: EntityList[];
+ entityForms?: EntityForm[];
+ webForms?: WebForm[];
+ weblinks?: Weblink[];
+ weblinkSets?: WeblinkSet[];
+ website?: Website;
+ pageTemplates?: PageTemplate[];
+ dataResolverExtras?: { [key: string]: {} };
+ resx?: { [key: string]: string };
+ featureConfig?: Map;
+ entityAttributeMetadata?: IEntityAttributeMetadata[];
+ lcid?: string;
+ isBootstrapV5?: boolean;
+}
+
+
+export enum RenderingMode {
+ VIEW = 'viewer',
+ EDIT = 'editor',
+}
+
+export enum DebugMode {
+ OFF = 'OFF',
+ INFO = 'INFO',
+ ERROR = 'ERROR',
+ TRACE = 'TRACE',
+}
+
+interface IEngineConfig {
+ strictFilters: boolean;
+ strictVariables: boolean;
+ isDynamicComponentCheck?: boolean;
+ addDynamicEntity?: (entityName: string, id: string, attributeName?: string) => void;
+ addFetchXMLExpression?: (varName: string, fetchXML: string) => void;
+ addPcfControl?: (controlName: string) => void;
+ addDynamicDrops?: (dropName: string) => void;
+}
+
+export interface IPreviewEngineConfig {
+ renderingMode?: RenderingMode;
+ debugMode?: DebugMode;
+ engineConfig?: IEngineConfig;
+ websiteLanguageId?: string;
+ breadcrumb?: IBreadcrumbParams;
+}
+
+export interface IBreadcrumbParams {
+ separator: string;
+ home_as: string;
+ tag: string;
+ textClass: string;
+}
+
+export interface IDataResolver {
+ context?: IPreviewEngineContext;
+ config?: IPreviewEngineConfig;
+}
+
+export interface IPortalDrops {
+ [key: string]: PortalDrop;
+}
+
+export interface IPortalPreviewEngine {
+ renderWebpageById: (
+ webpageId: string,
+ htmlMeta?: WebpageView,
+ beforeTagRender?: (tagName: string, entityName: string, entityId: string) => void,
+ dynamicContext?: {}
+ ) => string;
+ evaluateExpression: (
+ expression: string,
+ webpageId?: string,
+ beforeTagRender?: (tagName: string, entityName: string, entityId: string) => void,
+ dynamicContext?: {}
+ ) => string;
+ renderWebpageByURL: (
+ pageUrl: string,
+ htmlMeta?: WebpageView,
+ beforeTagRender?: (tagName: string, entityName: string, entityId: string) => void,
+ dynamicContext?: {}
+ ) => string;
+ updateContext: (context?: IPreviewEngineContext) => void;
+ updateConfig: (config?: IPreviewEngineConfig) => void;
+ getConfig: () => IPreviewEngineConfig;
+ renderPartialWebpageById: (
+ webpageId?: string,
+ htmlMeta?: WebpageView,
+ beforeTagRender?: (tagName: string, entityName: string, entityId: string) => void
+ ) => { header: string; mainContent: string; footer: string };
+}
diff --git a/src/common/TreeStructure/TreeViewProvider.ts b/src/common/TreeStructure/TreeViewProvider.ts
new file mode 100644
index 00000000..9a5ca0ae
--- /dev/null
+++ b/src/common/TreeStructure/TreeViewProvider.ts
@@ -0,0 +1,299 @@
+import * as vscode from 'vscode';
+
+import * as path from "path";
+import { IItem } from './TreeView/Types/Entity/IItem';
+
+class MyTreeItem extends vscode.TreeItem {
+ constructor(public readonly item: IItem, public readonly collapsibleState: vscode.TreeItemCollapsibleState) {
+ super(item.label, collapsibleState);
+ this.tooltip = `${this.item.title}`;
+ this.description = this.item.content;
+ this.iconPath = this.getIconPath(item);
+ this.contextValue = this.item.isFile ? 'file' : 'folder';
+ this.command = this.getCommand(item);
+ }
+
+ private getCommand(item: IItem): vscode.Command | undefined {
+ if (item.isFile && item.title === 'Source-Dependencies') {
+ return {
+ title: 'Item Clicked',
+ command: 'extension.itemClicked',
+ arguments: [item]
+ };
+ } else if (item.isFile) {
+ return {
+ title: 'Open File',
+ command: 'extension.openFile',
+ arguments: [item]
+ };
+ }
+ return undefined;
+ }
+
+ private getIconPath(item: IItem): { light: string, dark: string } | vscode.ThemeIcon {
+ const basePath = path.join(__dirname, '..', 'src', 'client', 'portal_fileicons', 'icons');
+
+ if (item.isFile) {
+ switch (item.component) {
+ case "01": // HTML
+ return {
+ light: path.join(basePath, 'dark', 'html.svg'),
+ dark: path.join(basePath, 'dark', 'html.svg')
+ };
+ case "02": // CSS
+ return {
+ light: path.join(basePath, 'dark', 'css.svg'),
+ dark: path.join(basePath, 'dark', 'css.svg')
+ };
+ case "03": // JSON
+ return {
+ light: path.join(basePath, 'dark', 'js.svg'),
+ dark: path.join(basePath, 'dark', 'js.svg')
+ };
+ case "04": // YML
+ return {
+ light: path.join(basePath, 'dark', 'yml.svg'),
+ dark: path.join(basePath, 'dark', 'yml.svg')
+ };
+ case "05": // PNG
+ return {
+ light: path.join(basePath, 'dark', 'png.svg'),
+ dark: path.join(basePath, 'dark', 'png.svg')
+ };
+ case "06": // Json
+ return {
+ light: path.join(basePath, 'light', 'json.svg'),
+ dark: path.join(basePath, 'dark', 'json.svg')
+ };
+ case "09": // MP4
+ return {
+ light: path.join(basePath, 'dark', 'mp4.svg'),
+ dark: path.join(basePath, 'dark', 'mp4.svg')
+ };
+ case "10": // Text File
+ return new vscode.ThemeIcon('file');
+ case "07":
+ case "08":
+ case "015":
+ case "017":
+ case "019":
+ return {
+ light: path.join(basePath, 'light', 'file-symlink-file.svg'),
+ dark: path.join(basePath, 'dark', 'file-symlink-file.svg')
+ };
+ default:
+ return new vscode.ThemeIcon('file');
+ }
+ } else {
+ switch (item.component) {
+ case "1": // Website
+ return {
+ light: path.join(basePath, 'light', 'website.svg'),
+ dark: path.join(basePath, 'dark', 'website.svg')
+ };
+ case "2": // Webpage
+ return {
+ light: path.join(basePath, 'light', 'web_pages.svg'),
+ dark: path.join(basePath, 'dark', 'web_pages.svg')
+ };
+ case "3": // Webfile
+ return {
+ light: path.join(basePath, 'light', 'web_files.svg'),
+ dark: path.join(basePath, 'dark', 'web_files.svg')
+ };
+ case "4": // Weblink set
+ return {
+ light: path.join(basePath, 'light', 'weblink_sets.svg'),
+ dark: path.join(basePath, 'dark', 'weblink_sets.svg')
+ };
+ case "5": // Weblink
+ return {
+ light: path.join(basePath, 'light', 'weblinks.svg'),
+ dark: path.join(basePath, 'dark', 'weblinks.svg')
+ };
+ case "6": // Page template
+ return {
+ light: path.join(basePath, 'light', 'page_templates.svg'),
+ dark: path.join(basePath, 'dark', 'page_templates.svg')
+ };
+ case "7": // Content snippet
+ return {
+ light: path.join(basePath, 'light', 'content_snippets.svg'),
+ dark: path.join(basePath, 'dark', 'content_snippets.svg')
+ };
+ case "8": // Webtemplate
+ return {
+ light: path.join(basePath, 'light', 'web_templates.svg'),
+ dark: path.join(basePath, 'dark', 'web_templates.svg')
+ };
+ case "9": // Site setting
+ return {
+ light: path.join(basePath, 'light', 'site_settings.svg'),
+ dark: path.join(basePath, 'dark', 'site_settings.svg')
+ };
+ case "13": // Site marker
+ return {
+ light: path.join(basePath, 'light', 'site_markers.svg'),
+ dark: path.join(basePath, 'dark', 'site_markers.svg')
+ };
+ case "15": // Basic Forms
+ return {
+ light: path.join(basePath, 'light', 'basic_forms.svg'),
+ dark: path.join(basePath, 'dark', 'basic_forms.svg')
+ };
+ case "17": // Lists
+ return {
+ light: path.join(basePath, 'light', 'lists.svg'),
+ dark: path.join(basePath, 'dark', 'lists.svg')
+ };
+ case "19": // Advanced Forms
+ return {
+ light: path.join(basePath, 'light', 'advanced_forms.svg'),
+ dark: path.join(basePath, 'dark', 'advanced_forms.svg')
+ };
+ case "22": // Content Page
+ return {
+ light: path.join(basePath, 'light', 'book.svg'),
+ dark: path.join(basePath, 'dark', 'book.svg')
+ };
+ case "23": // Page Copy
+ return {
+ light: path.join(basePath, 'light', 'list-flat.svg'),
+ dark: path.join(basePath, 'dark', 'list-flat.svg')
+ };
+ case "24": // Page Summary
+ return {
+ light: path.join(basePath, 'light', 'note.svg'),
+ dark: path.join(basePath, 'dark', 'note.svg')
+ };
+ case "25": // Subpage
+ return {
+ light: path.join(basePath, 'light', 'file-submodule.svg'),
+ dark: path.join(basePath, 'dark', 'file-submodule.svg')
+ };
+ default: // Default folder icon
+ return {
+ light: path.join(basePath, 'light', 'folder.svg'),
+ dark: path.join(basePath, 'dark', 'folder.svg')
+ };
+ }
+ }
+ }
+}
+
+class MyTreeDataProvider implements vscode.TreeDataProvider {
+ private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
+ readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;
+
+ constructor(private readonly data: IItem[]) { }
+
+ getTreeItem(element: MyTreeItem): vscode.TreeItem {
+ return element;
+ }
+
+ getChildren(element?: MyTreeItem): Thenable {
+ if (element) {
+ return Promise.resolve(this.getItemChildren(element.item));
+ } else {
+ return Promise.resolve(this.data.map(item => new MyTreeItem(item, vscode.TreeItemCollapsibleState.Collapsed)));
+ }
+ }
+
+ private getItemChildren(item: IItem): MyTreeItem[] {
+ return item.children.map(child => new MyTreeItem(child, child.children.length > 0 ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None));
+ }
+
+ getParent(element: MyTreeItem): MyTreeItem | undefined {
+ const parentItem = this.findParentItem(this.data[0], element.item);
+ if (parentItem) {
+ return new MyTreeItem(parentItem, vscode.TreeItemCollapsibleState.Collapsed);
+ }
+ return undefined;
+ }
+
+ private findParentItem(currentItem: IItem, targetItem: IItem): IItem | undefined {
+ if (!currentItem || !currentItem.children) {
+ return undefined;
+ }
+ const foundChild = currentItem.children.find(child => child.id === targetItem.id && child.title === targetItem.title);
+ if (foundChild) {
+ return currentItem;
+ }
+ for (const child of currentItem.children) {
+ const parentItem = this.findParentItem(child, targetItem);
+ if (parentItem) {
+ return parentItem;
+ }
+ }
+
+ return undefined;
+ }
+
+ findItemById(item: IItem, websiteIItem: IItem): IItem | undefined {
+ const comp = item.component.slice(1);
+ if (comp == '7') {
+ const contentSnipppetIItem = websiteIItem.children.find((child: IItem) => child.label === 'Content Snippets');
+ return helper(item, contentSnipppetIItem);
+ } else if (comp == '8') {
+ const webTemplateIItem = websiteIItem.children.find((child: IItem) => child.label === 'Web Templates');
+ return helper(item, webTemplateIItem);
+ } else if (comp == '15') {
+ const entityFormIItem = websiteIItem.children.find((child: IItem) => child.label === 'Basic Forms');
+ return helper(item, entityFormIItem);
+ } else if (comp == '17') {
+ const listsIItem = websiteIItem.children.find((child: IItem) => child.label === 'Lists');
+ return helper(item, listsIItem);
+ } else if (comp == '19') {
+ const webformIItem = websiteIItem.children.find((child: IItem) => child.label === 'Advanced Forms');
+ return helper(item, webformIItem);
+ } else {
+ return undefined;
+ }
+ }
+}
+function helper(item: IItem, entityIItem: any) {
+ for (const child of entityIItem.children) {
+ if (child.id == item.id) {
+ return child;
+ }
+ }
+ return undefined;
+}
+export function createTree(websiteIItem: IItem) {
+ const treeDataProvider = new MyTreeDataProvider([websiteIItem]);
+ const treeView = vscode.window.createTreeView('exampleView', { treeDataProvider });
+
+ vscode.commands.registerCommand('extension.openWebpage', (webpageName: string) => {
+ vscode.window.showInformationMessage(`Opening Webpage: ${webpageName}`);
+ });
+
+ vscode.commands.registerCommand('extension.openFile', async (item: IItem) => {
+ try {
+ if (item.path) {
+ const pathString = item.path.fsPath.toLowerCase();
+
+ if (pathString.endsWith('.html') || pathString.endsWith('.css') || pathString.endsWith('.js') || pathString.endsWith('.json') || pathString.endsWith('.yml')) {
+ const document = await vscode.workspace.openTextDocument(item.path);
+ await vscode.window.showTextDocument(document);
+ } else if (pathString.endsWith('.png') || pathString.endsWith('.jpg') || pathString.endsWith('.jpeg') || pathString.endsWith('.gif') || pathString.endsWith('.mp4')) {
+ await vscode.commands.executeCommand('vscode.open', item.path);
+ } else {
+ const document = await vscode.workspace.openTextDocument(item.path);
+ await vscode.window.showTextDocument(document);
+ }
+ } else {
+ const document = await vscode.workspace.openTextDocument({ content: item.content, language: 'plaintext' });
+ await vscode.window.showTextDocument(document);
+ }
+ } catch (error) {
+ vscode.window.showErrorMessage(`${item.title} ${item.id} does not exist`);
+ }
+ });
+ vscode.commands.registerCommand('extension.itemClicked', (item: IItem) => {
+ const foundItem = treeDataProvider.findItemById(item, websiteIItem);
+ if (foundItem && !foundItem.isFile) {
+ const treeItem = new MyTreeItem(foundItem, foundItem.children.length > 0 ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
+ treeView.reveal(treeItem, { focus: true, expand: true });
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/DefaultPortalComponentService.ts b/src/common/TreeStructure/dataMapperServices/DefaultPortalComponentService.ts
new file mode 100644
index 00000000..19bbb654
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/DefaultPortalComponentService.ts
@@ -0,0 +1,87 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { IItem } from "../TreeView/Types/Entity/IItem";
+import { IPortalComponentService } from "./IPortalComponentService";
+import * as vscode from 'vscode';
+
+interface PortalComponentConfig {
+ type: string;
+ idField: string;
+ nameField: string;
+ url: string;
+ fileType: string,
+ comp: string,
+ getItems: (metadataContext: any) => any[];
+}
+
+export class DefaultPortalComponentService implements IPortalComponentService {
+ private config: PortalComponentConfig;
+
+ constructor(config: PortalComponentConfig) {
+ this.config = config;
+ }
+
+ create(metadataContext: any, getPath?: any): IItem[] {
+ const items: IItem[] = [];
+ const components = this.config.getItems(metadataContext);
+
+ if (!components) {
+ return items;
+ }
+
+ for (const component of components) {
+ const name = component[this.config.nameField];
+ const id = component[this.config.idField];
+ const type = this.config.type;
+ const url = this.config.url;
+ const filetype = this.config.fileType;
+ const comp = this.config.comp;
+ let x = name.replace(/[/\s]+/g, '-');
+ let y = x.toLowerCase();
+ let c = '01';
+ if (type == 'lists') {
+ y = '';
+ }
+ if (type == 'basic-forms') {
+ x = y;
+ }
+ if (filetype == 'js') {
+ c = '03';
+ }
+ if (filetype == 'yml') {
+ c = '04'
+ }
+ const children: IItem[] = [
+ {
+ label: `${x}${url}`,
+ title: `${name}.${filetype}`,
+ id: `${id}`,
+ isFile: true,
+ content: '',
+ path: vscode.Uri.file(`${getPath.path}/${type}/${y}/${x}${url}`),
+ component: c,
+ children: [],
+ error: "",
+ parentList:[]
+ }
+ ];
+
+ const item: IItem = {
+ label: name,
+ title: type,
+ id: id,
+ isFile: false,
+ content: '',
+ path: vscode.Uri.parse(`${getPath.path}/${type}/${y}`),
+ component: comp,
+ children: children,
+ error: "",
+ parentList:[]
+ };
+
+ items.push(item);
+ }
+ return items;
+ }
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/IPortalComponentService.ts b/src/common/TreeStructure/dataMapperServices/IPortalComponentService.ts
new file mode 100644
index 00000000..7d005dc5
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/IPortalComponentService.ts
@@ -0,0 +1,16 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { IItem } from "../TreeView/Types/Entity/IItem";
+
+export interface IPortalComponentService {
+ /**
+ * Save source value of the component and refresh component if save successful.
+ * @param id: Id of component
+ * @param value: source code value
+ * @param element Outer HTML element for portal component
+ * @param subComponent one of many dependent on its parent component service for saving
+ */
+ create(metadataContext: any, getPath?: any): IItem[];
+
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/PortalComponentServiceFactory.ts b/src/common/TreeStructure/dataMapperServices/PortalComponentServiceFactory.ts
new file mode 100644
index 00000000..b608ce0e
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/PortalComponentServiceFactory.ts
@@ -0,0 +1,39 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { IPortalComponentService } from "./IPortalComponentService";
+import { WebPageService } from "./WebPageService";
+import { DefaultPortalComponentService } from "./DefaultPortalComponentService";
+import { WebFileService } from './WebFileService'
+import { contentSnippetConfig, webTemplateConfig, listConfig, entityFormConfig, webFormConfig } from "./portalComponentConfigs";
+
+export class PortalComponentServiceFactory {
+ static getPortalComponent(componentType: string): IPortalComponentService | null {
+ switch (componentType) {
+ case "WebPage": {
+ return new WebPageService();
+ }
+ case "WebFile": {
+ return new WebFileService();
+ }
+ case "WebTemplate": {
+ return new DefaultPortalComponentService(webTemplateConfig);
+ }
+ case "Content Snippet": {
+ return new DefaultPortalComponentService(contentSnippetConfig);
+ }
+ case "List": {
+ return new DefaultPortalComponentService(listConfig);
+ }
+ case "EntityForm": {
+ return new DefaultPortalComponentService(entityFormConfig);
+ }
+ case "WebForm": {
+ return new DefaultPortalComponentService(webFormConfig);
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/WebFileService.ts b/src/common/TreeStructure/dataMapperServices/WebFileService.ts
new file mode 100644
index 00000000..c211d9e8
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/WebFileService.ts
@@ -0,0 +1,68 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { IPortalComponentService } from "./IPortalComponentService";
+import { IItem } from "../TreeView/Types/Entity/IItem";
+import { WebFile } from "../TreeView/Types/Entity/WebFile";
+import * as vscode from 'vscode';
+
+export class WebFileService implements IPortalComponentService {
+ create(metadataContext: any, getPath?: any): IItem[] {
+ const items: IItem[] = [];
+ const webFile: WebFile[] | undefined = metadataContext.webFiles;
+
+ if (!webFile) {
+ return items;
+ }
+ for (const file of webFile) {
+ let c = '';
+ if (file.adx_name.endsWith(".css")) {
+ c = '02';
+ } else if (file.adx_name.endsWith(".json")) {
+ c = '06';
+ } else if (file.adx_name.endsWith(".mp4")) {
+ c = '09';
+ file.adx_name=file.adx_name.replace(/\s+/g, '-');
+ } else if (file.adx_name.endsWith(".html")) {
+ c = '01';
+ } else if (file.adx_name.endsWith(".png")) {
+ c = '05';
+ } else if (file.adx_name.endsWith(".js")) {
+ c = '03';
+ }else{
+ c='10';
+ file.adx_name=file.adx_name.replace(/\s+/g, '-');
+ }
+ const item: IItem = {
+ label: file.adx_name,
+ title: file.adx_name,
+ id: file.adx_webfileid,
+ isFile: true,
+ content: '',
+ path: vscode.Uri.file(`${getPath.path}/web-files/${file.adx_name}`),
+ component: c,
+ children: [],
+ error: "",
+ parentList:[]
+ };
+ if(file.adx_name.endsWith(".html") || file.adx_name.endsWith(".js")){
+ const fileItem: IItem = {
+ label: file.filename,
+ title: 'webFile',
+ id: file.adx_webfileid,
+ isFile: false,
+ content: '',
+ path: vscode.Uri.file(`/web-files`),
+ component: c,
+ children: [item],
+ error: "",
+ parentList:[]
+ };
+ items.push(fileItem);
+ }else{
+ items.push(item);
+ }
+ }
+ return items;
+ }
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/WebPageService.ts b/src/common/TreeStructure/dataMapperServices/WebPageService.ts
new file mode 100644
index 00000000..ea33d5ea
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/WebPageService.ts
@@ -0,0 +1,95 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+import { IPortalComponentService } from "./IPortalComponentService";
+import { IItem } from "../TreeView/Types/Entity/IItem";
+import { Webpage } from '../TreeView/Types/Entity/WebPage';
+import * as vscode from 'vscode';
+
+export const contentPage: Webpage[] = [];
+export class WebPageService implements IPortalComponentService {
+ create(metadataContext: any, getPath?: any): IItem[] {
+ const items: IItem[] = [];
+ const webpages: Webpage[] | undefined = metadataContext.webpages;
+
+ if (!webpages) {
+ return items;
+ }
+
+ for (const webpage of webpages) {
+ if (!webpage.adx_webpagelanguageid) {
+ const str = webpage.adx_name;
+ let x = str.replace(/\s+/g, '-');
+ let y = x.toLowerCase();
+ const [pageCopy, cssItem, jsItem, pageSummary] = createCopyItems(webpage, getPath, y, x);
+ const webpageItem = createItem(webpage.adx_name, webpage.adx_name, webpage.adx_webpageid, false, vscode.Uri.parse(`/${webpage.adx_name}`), "/2", [pageCopy, cssItem, jsItem, pageSummary]);
+ items.push(webpageItem);
+ } else {
+ contentPage.push(webpage);
+ }
+ }
+
+ items.forEach(item => {
+ webpages.forEach(webpage => {
+ if (item.id === webpage.adx_parentpageid) {
+ const subItem = items.find(it => webpage.adx_webpageid === it.id);
+ if (subItem) {
+ let subpageItem = item.children.find(child => child.label === "Subpage");
+ if (!subpageItem) {
+ subpageItem = createItem('Subpage', 'Subpage', '', false, vscode.Uri.parse(`/Subpage`), "25", [subItem]);
+ item.children.push(subpageItem);
+ } else {
+ subpageItem.children.push(subItem);
+ }
+ }
+ }
+ });
+ });
+
+ for (const contentpg of contentPage) {
+ const str = contentpg.adx_name;
+ let x = str.replace(/\s+/g, '-');
+ let y = x.toLowerCase();
+ const [pageCopy, cssItem, jsItem, pageSummary] = createCopyItems(contentpg, getPath, y, x, '.en-US', '/content-pages');
+ const contentPageItem = createItem(`Content Page`, `Content Page`, `${contentpg.adx_webpageid}_content`, false, vscode.Uri.file(`${contentpg.adx_name}/Content`), "22", [pageCopy, cssItem, jsItem, pageSummary]);
+
+ items.forEach(item => {
+ if (item.title === contentpg.adx_name) {
+ const x = item.children.find(child => child.label === "Content Page");
+ if (!x) {
+ item.children.push(contentPageItem);
+ }
+ }
+ });
+ }
+ return items;
+ }
+
+}
+
+function createItem(label: string, title: string, id: string, isFile: boolean, path: vscode.Uri, component: string, children: IItem[] = [], content: string = '', error: string = '', parentList: IItem[] = []): IItem {
+ return {
+ label,
+ title,
+ id,
+ isFile,
+ content,
+ path,
+ component,
+ children,
+ error,
+ parentList,
+ };
+}
+
+function createCopyItems(webpage: Webpage, getPath: any, y: string, x: string, langSuffix: string = '', content: string = ''): IItem[] {
+ const basePath = `${getPath.path}/web-pages/${y}${content}/${x}${langSuffix}`;
+ const copyItem = createItem(`${x}${langSuffix}.webpage.copy.html`, `${x}${langSuffix}.webpage.copy.html`, `${x}${langSuffix}.webpage.copy.html`, true, vscode.Uri.file(`${basePath}.webpage.copy.html`), "01");
+ const cssItem = createItem(`${x}${langSuffix}.webpage.custom_css.css`, `${x}${langSuffix}.webpage.custom_css.css`, `${webpage.adx_webpageid}_css`, true, vscode.Uri.file(`${basePath}.webpage.custom_css.css`), "02");
+ const jsItem = createItem(`${x}${langSuffix}.webpage.custom_javascript.js`, `${x}${langSuffix}.webpage.custom_javascript.js`, `${webpage.adx_webpageid}_js`, true, vscode.Uri.file(`${basePath}.webpage.custom_javascript.js`), "03");
+ const summaryItem = createItem(`${x}${langSuffix}.webpage.summary.html`, `${x}${langSuffix}.webpage.summary.html`, `${x}${langSuffix}.webpage.summary.html`, true, vscode.Uri.file(`${basePath}.webpage.summary.html`), "01");
+ const pageCopy = createItem(`Page Copy`, `Page Copy`, `Page_copy`, false, vscode.Uri.file(`/pagecopy`), "23", [copyItem]);
+ const pageSummary = createItem(`Page Summary`, `Page Summary`, `Page_Summary`, false, vscode.Uri.file(`/pageSummary`), "24", [summaryItem]);
+
+ return [pageCopy, cssItem, jsItem, pageSummary];
+}
\ No newline at end of file
diff --git a/src/common/TreeStructure/dataMapperServices/portalComponentConfigs.ts b/src/common/TreeStructure/dataMapperServices/portalComponentConfigs.ts
new file mode 100644
index 00000000..694ac7f4
--- /dev/null
+++ b/src/common/TreeStructure/dataMapperServices/portalComponentConfigs.ts
@@ -0,0 +1,52 @@
+/*!
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+export const contentSnippetConfig = {
+ type: "content-snippets",
+ idField: "adx_contentsnippetid",
+ nameField: "adx_name",
+ url: ".en-US.contentsnippet.value.html",
+ fileType: "html",
+ comp: "/7",
+ getItems: (metadataContext: any) => metadataContext.contentSnippets
+};
+
+export const webTemplateConfig = {
+ type: "web-templates",
+ idField: "adx_webtemplateid",
+ nameField: "adx_name",
+ url: ".webtemplate.source.html",
+ fileType: "html",
+ comp: "/8",
+ getItems: (metadataContext: any) => metadataContext.webTemplates,
+};
+
+export const listConfig = {
+ type: "lists",
+ idField: "adx_entitylistid",
+ nameField: "adx_name",
+ url: ".list.custom_javascript.js",
+ fileType: "js",
+ comp: "/17",
+ getItems: (metadataContext: any) => metadataContext.entityLists,
+};
+
+export const entityFormConfig = {
+ type: "basic-forms",
+ idField: "adx_entityformid",
+ nameField: "adx_name",
+ url: ".basicform.custom_javascript.js",
+ fileType: "js",
+ comp: "/15",
+ getItems: (metadataContext: any) => metadataContext.entityForms,
+};
+
+export const webFormConfig = {
+ type: "advanced-forms",
+ idField: "adx_webformid",
+ nameField: "adx_name",
+ url: ".advancedform.yml",
+ fileType: "yml",
+ comp: "/9",
+ getItems: (metadataContext: any) => metadataContext.webForms,
+};
\ No newline at end of file