Skip to content

Commit 85b0a07

Browse files
amitjoshi438Amit Joshi
andauthored
[Powerpages] Add support for blogs, ideas & forums entity in web ext schema (#1342)
* Add support for blogs entity in web schema and utilities - Add BLOGS to schemaEntityName and MultiFileSupportedEntityName enums - Add portal schema entries for blogs in V1 and V2 - Include BLOGS in isExtensionNeededInFileName so blog files get extensions handled * Gate blog entity support behind ECS feature flag - Add EnableBlogSupport feature flag in ECS feature gates - Conditionally include 'blogs' entity in portal schema V1 and V2 based on the flag - Add null checks in folderHelperUtility to skip entities not present in schema (e.g., blogs when feature is off) * Add support for ideas entity in schema and utilities * Add support for Idea Forums entity in schema and utilities * Add support for lazy(conditional) folder creation for blogs, ideas, and ideaforums * Add support for Forum Announcements entity in schema and utilities * Add support for Forum Posts entity and enhance lazy folder creation logic * Add support for blog posts and forum entities in schema and utilities * Add support for Forum Announcements and Forum Posts entities in portal schema * Refine multi-file fetch query parameters for blog and idea entities to include website ID filter * Enhance multi-file fetch query parameters for forum announcements to include website ID filter * Add tests for GetFileNameWithExtension and folderHelperUtility functions * Add unit tests for GetFileNameWithExtension with various entity types * Remove tests for folderHelperUtility and clean up remoteFetchProvider tests --------- Co-authored-by: Amit Joshi <amitjoshi@microsoft.com>
1 parent 2508d33 commit 85b0a07

File tree

7 files changed

+424
-16
lines changed

7 files changed

+424
-16
lines changed

src/common/ecs-features/ecsFeatureGates.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,13 @@ export const {
120120
disallowedDuplicateFileHandlingOrgs: "",
121121
}
122122
});
123+
124+
export const {
125+
feature: EnableBlogSupport
126+
} = getFeatureConfigs({
127+
teamName: PowerPagesClientName,
128+
description: 'Enable blog file support in VSCode (web & desktop)',
129+
fallback: {
130+
enableBlogSupport: false,
131+
}
132+
});

src/web/client/dal/remoteFetchProvider.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ import {
2929
} from "../utilities/schemaHelperUtil";
3030
import WebExtensionContext from "../WebExtensionContext";
3131
import { webExtensionTelemetryEventNames } from "../../../common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents";
32-
import { EntityMetadataKeyCore, SchemaEntityMetadata, folderExportType, schemaEntityKey, schemaEntityName, schemaKey, WEBPAGE_FOLDER_CONSTANTS } from "../schema/constants";
32+
import { conditionalFolderEntities, EntityMetadataKeyCore, SchemaEntityMetadata, folderExportType, schemaEntityKey, schemaEntityName, schemaKey, WEBPAGE_FOLDER_CONSTANTS } from "../schema/constants";
3333
import { getEntityNameForExpandedEntityContent, getRequestUrlForEntities } from "../utilities/folderHelperUtility";
3434
import { IAttributePath, IFileInfo } from "../common/interfaces";
3535
import { portal_schema_V2 } from "../schema/portalSchema";
3636
import { ERROR_CONSTANTS } from "../../../common/ErrorConstants";
3737
import { showErrorDialog } from "../../../common/utilities/errorHandlerUtil";
38-
import { EnableServerLogicChanges, EnableDuplicateFileHandling } from "../../../common/ecs-features/ecsFeatureGates";
38+
import { EnableServerLogicChanges, EnableDuplicateFileHandling, EnableBlogSupport } from "../../../common/ecs-features/ecsFeatureGates";
3939
import { ECSFeaturesClient } from "../../../common/ecs-features/ecsFeatureClient";
4040

4141
export async function fetchDataFromDataverseAndUpdateVFS(
@@ -760,9 +760,27 @@ async function createVirtualFile(
760760
entityMetadata
761761
);
762762

763+
const fileUriParsed = vscode.Uri.parse(fileUri);
764+
765+
const { enableBlogSupport } = ECSFeaturesClient.getConfig(EnableBlogSupport);
766+
// Ensure parent directory exists before writing file for conditional entities
767+
// This enables lazy folder creation for blogs, ideas, ideaforums, forum announcements, and forum posts
768+
if (enableBlogSupport && conditionalFolderEntities.includes(entityName as schemaEntityName)) {
769+
const parentDirPath = fileUriParsed.path.substring(0, fileUriParsed.path.lastIndexOf('/'));
770+
const parentDirUri = fileUriParsed.with({ path: parentDirPath });
771+
772+
try {
773+
// createDirectory is idempotent - it checks if directory exists before creating
774+
await portalsFS.createDirectory(parentDirUri);
775+
} catch (error) {
776+
//Directory might already exist or parent lookup might succeed anyway
777+
778+
}
779+
}
780+
763781
// Call file system provider write call for buffering file data in VFS
764782
await portalsFS.writeFile(
765-
vscode.Uri.parse(fileUri),
783+
fileUriParsed,
766784
fileContent,
767785
{ create: true, overwrite: true },
768786
true

src/web/client/schema/constants.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ export enum schemaEntityName {
5353
BASICFORMS = "basicforms",
5454
ADVANCEDFORMS = "advancedforms",
5555
ADVANCEDFORMSTEPS = "advancedformsteps",
56+
BLOGS = "blogs",
57+
BLOGPOSTS = "blogposts",
58+
IDEAS = "ideas",
59+
IDEAFORUMS = "ideaforums",
60+
FORUMANNOUNCEMENTS = "forumannouncements",
61+
FORUMPOSTS = "forumposts",
5662
}
5763

5864
export enum MultiFileSupportedEntityName {
@@ -64,6 +70,12 @@ export enum MultiFileSupportedEntityName {
6470
LISTS = "lists",
6571
BASICFORMS = "basicforms",
6672
ADVANCEDFORMS = "advancedforms",
73+
BLOGS = "blogs",
74+
BLOGPOSTS = "blogposts",
75+
IDEAS = "ideas",
76+
IDEAFORUMS = "ideaforums",
77+
FORUMANNOUNCEMENTS = "forumannouncements",
78+
FORUMPOSTS = "forumposts",
6779
}
6880

6981
// This decides the folder hierarchy a file being displayed in File explorer will follow.
@@ -100,3 +112,14 @@ export const WEBPAGE_FOLDER_CONSTANTS = {
100112
export function getRootWebPageIdForTelemetry(rootWebPageId: string | undefined | null): string {
101113
return rootWebPageId || WEBPAGE_FOLDER_CONSTANTS.NULL_PLACEHOLDER;
102114
}
115+
116+
// Entities that should only have folders created when they contain data
117+
// These folders will be created lazily when files are fetched
118+
export const conditionalFolderEntities = [
119+
schemaEntityName.BLOGS,
120+
schemaEntityName.BLOGPOSTS,
121+
schemaEntityName.IDEAS,
122+
schemaEntityName.IDEAFORUMS,
123+
schemaEntityName.FORUMANNOUNCEMENTS,
124+
schemaEntityName.FORUMPOSTS,
125+
];

src/web/client/schema/portalSchema.ts

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*/
55

6+
import { ECSFeaturesClient } from "../../../common/ecs-features/ecsFeatureClient";
7+
import { EnableBlogSupport } from "../../../common/ecs-features/ecsFeatureGates";
8+
69
export const portal_schema_V1 = {
710
entities: {
811
dataSourceProperties: {
@@ -232,6 +235,114 @@ export const portal_schema_V1 = {
232235
_attributes: "adx_registerstartupscript",
233236
_attributesExtension: new Map([["adx_registerstartupscript", "advancedformstep.customjs.js"]]),
234237
},
238+
...(ECSFeaturesClient.getConfig(EnableBlogSupport).enableBlogSupport ? [
239+
{
240+
relationships: "",
241+
_vscodeentityname: "blogs",
242+
_dataverseenityname: "adx_blogs",
243+
_displayname: "Blog",
244+
_etc: "10061",
245+
_primaryidfield: "adx_blogid",
246+
_primarynamefield: "adx_name",
247+
_disableplugins: "true",
248+
_foldername: "blogs",
249+
_exporttype: "SingleFolder",
250+
_fetchQueryParameters:
251+
"?$filter=adx_blogid eq {entityId}&$select=adx_name,adx_summary",
252+
_multiFileFetchQueryParameters:
253+
"?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_summary,adx_blogid&$count=true",
254+
_attributes: "adx_summary",
255+
_attributesExtension: new Map([["adx_summary", "html"]]),
256+
},
257+
{
258+
relationships: "",
259+
_vscodeentityname: "ideas",
260+
_dataverseenityname: "adx_ideas",
261+
_displayname: "Idea",
262+
_etc: "10062",
263+
_primaryidfield: "adx_ideaid",
264+
_primarynamefield: "adx_name",
265+
_disableplugins: "true",
266+
_foldername: "ideas",
267+
_exporttype: "SingleFolder",
268+
_fetchQueryParameters:
269+
"?$filter=adx_ideaid eq {entityId}&$select=adx_name,adx_copy",
270+
_multiFileFetchQueryParameters:
271+
"?$filter=_adx_ideaforumid_value ne null and adx_ideaforumId/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_copy,adx_ideaid&$count=true",
272+
_attributes: "adx_copy",
273+
_attributesExtension: new Map([["adx_copy", "html"]]),
274+
},
275+
{
276+
relationships: "", _vscodeentityname: "blogposts",
277+
_dataverseenityname: "adx_blogposts",
278+
_displayname: "Blog Post",
279+
_etc: "10056",
280+
_primaryidfield: "adx_blogpostid",
281+
_primarynamefield: "adx_name",
282+
_disableplugins: "true",
283+
_foldername: "blog-posts",
284+
_exporttype: "SingleFolder",
285+
_fetchQueryParameters:
286+
"?$filter=adx_blogpostid eq {entityId}&$select=adx_name,adx_copy",
287+
_multiFileFetchQueryParameters:
288+
"?$filter=_adx_blogid_value ne null and adx_blogid/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_copy,adx_blogpostid&$count=true",
289+
_attributes: "adx_copy",
290+
_attributesExtension: new Map([["adx_copy", "html"]]),
291+
},
292+
{
293+
relationships: "", _vscodeentityname: "ideaforums",
294+
_dataverseenityname: "adx_ideaforums",
295+
_displayname: "Idea Forum",
296+
_etc: "10063",
297+
_primaryidfield: "adx_ideaforumid",
298+
_primarynamefield: "adx_name",
299+
_disableplugins: "true",
300+
_foldername: "idea-forums",
301+
_exporttype: "SingleFolder",
302+
_fetchQueryParameters:
303+
"?$filter=adx_ideaforumid eq {entityId}&$select=adx_name,adx_summary",
304+
_multiFileFetchQueryParameters:
305+
"?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_summary,adx_ideaforumid&$count=true",
306+
_attributes: "adx_summary",
307+
_attributesExtension: new Map([["adx_summary", "html"]]),
308+
},
309+
{
310+
relationships: "",
311+
_vscodeentityname: "forumannouncements",
312+
_dataverseenityname: "adx_communityforumannouncements",
313+
_displayname: "Forum Announcement",
314+
_etc: "10064",
315+
_primaryidfield: "adx_communityforumannouncementid",
316+
_primarynamefield: "adx_name",
317+
_disableplugins: "true",
318+
_foldername: "forum-announcements",
319+
_exporttype: "SingleFolder",
320+
_fetchQueryParameters:
321+
"?$filter=adx_communityforumannouncementid eq {entityId}&$select=adx_name,adx_content",
322+
_multiFileFetchQueryParameters:
323+
"?$filter=_adx_forumid_value ne null and adx_forumid/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_content,adx_communityforumannouncementid&$count=true",
324+
_attributes: "adx_content",
325+
_attributesExtension: new Map([["adx_content", "html"]]),
326+
},
327+
{
328+
relationships: "",
329+
_vscodeentityname: "forumposts",
330+
_dataverseenityname: "adx_communityforumposts",
331+
_displayname: "Forum Post",
332+
_etc: "10065",
333+
_primaryidfield: "adx_communityforumpostid",
334+
_primarynamefield: "adx_name",
335+
_disableplugins: "true",
336+
_foldername: "forum-posts",
337+
_exporttype: "SingleFolder",
338+
_fetchQueryParameters:
339+
"?$filter=adx_communityforumpostid eq {entityId}&$select=adx_name,adx_content",
340+
_multiFileFetchQueryParameters:
341+
"?$filter=_adx_forumthreadid_value ne null &$select=adx_name,adx_content,adx_communityforumpostid&$count=true",
342+
_attributes: "adx_content",
343+
_attributesExtension: new Map([["adx_content", "html"]]),
344+
},
345+
] : []),
235346
],
236347
"_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
237348
},
@@ -470,6 +581,116 @@ export const portal_schema_V2 = {
470581
_attributes: "content.registerstartupscript",
471582
_attributesExtension: new Map([["content.registerstartupscript", "advancedformstep.customjs.js"]]),
472583
},
584+
...(ECSFeaturesClient.getConfig(EnableBlogSupport).enableBlogSupport ? [
585+
{
586+
relationships: "",
587+
_vscodeentityname: "blogs",
588+
_dataverseenityname: "adx_blogs",
589+
_displayname: "Blog",
590+
_etc: "10061",
591+
_primaryidfield: "adx_blogid",
592+
_primarynamefield: "adx_name",
593+
_disableplugins: "true",
594+
_foldername: "blogs",
595+
_exporttype: "SingleFolder",
596+
_fetchQueryParameters:
597+
"?$filter=adx_blogid eq {entityId}&$select=adx_name,adx_summary",
598+
_multiFileFetchQueryParameters:
599+
"?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_summary,adx_blogid&$count=true",
600+
_attributes: "adx_summary",
601+
_attributesExtension: new Map([["adx_summary", "html"]]),
602+
},
603+
{
604+
relationships: "",
605+
_vscodeentityname: "blogposts",
606+
_dataverseenityname: "adx_blogposts",
607+
_displayname: "Blog Post",
608+
_etc: "10056",
609+
_primaryidfield: "adx_blogpostid",
610+
_primarynamefield: "adx_name",
611+
_disableplugins: "true",
612+
_foldername: "blog-posts",
613+
_exporttype: "SingleFolder",
614+
_fetchQueryParameters:
615+
"?$filter=adx_blogpostid eq {entityId}&$select=adx_name,adx_copy",
616+
_multiFileFetchQueryParameters:
617+
"?$filter=_adx_blogid_value ne null and adx_blogid/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_copy,adx_blogpostid&$count=true",
618+
_attributes: "adx_copy",
619+
_attributesExtension: new Map([["adx_copy", "html"]]),
620+
},
621+
{
622+
relationships: "",
623+
_vscodeentityname: "ideas",
624+
_dataverseenityname: "adx_ideas",
625+
_displayname: "Idea",
626+
_etc: "10062",
627+
_primaryidfield: "adx_ideaid",
628+
_primarynamefield: "adx_name",
629+
_disableplugins: "true",
630+
_foldername: "ideas",
631+
_exporttype: "SingleFolder",
632+
_fetchQueryParameters:
633+
"?$filter=adx_ideaid eq {entityId}&$select=adx_name,adx_copy",
634+
_multiFileFetchQueryParameters:
635+
"?$filter=_adx_ideaforumid_value ne null and adx_ideaforumId/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_copy,adx_ideaid&$count=true",
636+
_attributes: "adx_copy",
637+
_attributesExtension: new Map([["adx_copy", "html"]]),
638+
},
639+
{
640+
relationships: "",
641+
_vscodeentityname: "ideaforums",
642+
_dataverseenityname: "adx_ideaforums",
643+
_displayname: "Idea Forum",
644+
_etc: "10063",
645+
_primaryidfield: "adx_ideaforumid",
646+
_primarynamefield: "adx_name",
647+
_disableplugins: "true",
648+
_foldername: "idea-forums",
649+
_exporttype: "SingleFolder",
650+
_fetchQueryParameters:
651+
"?$filter=adx_ideaforumid eq {entityId}&$select=adx_name,adx_summary",
652+
_multiFileFetchQueryParameters:
653+
"?$filter=_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_summary,adx_ideaforumid&$count=true",
654+
_attributes: "adx_summary",
655+
_attributesExtension: new Map([["adx_summary", "html"]]),
656+
},
657+
{
658+
relationships: "",
659+
_vscodeentityname: "forumannouncements",
660+
_dataverseenityname: "adx_communityforumannouncements",
661+
_displayname: "Forum Announcement",
662+
_etc: "10064",
663+
_primaryidfield: "adx_communityforumannouncementid",
664+
_primarynamefield: "adx_name",
665+
_disableplugins: "true",
666+
_foldername: "forum-announcements",
667+
_exporttype: "SingleFolder",
668+
_fetchQueryParameters:
669+
"?$filter=adx_communityforumannouncementid eq {entityId}&$select=adx_name,adx_content",
670+
_multiFileFetchQueryParameters:
671+
"?$filter=_adx_forumid_value ne null and adx_forumid/_adx_websiteid_value eq {websiteId} &$select=adx_name,adx_content,adx_communityforumannouncementid&$count=true",
672+
_attributes: "adx_content",
673+
_attributesExtension: new Map([["adx_content", "html"]]),
674+
},
675+
{
676+
relationships: "",
677+
_vscodeentityname: "forumposts",
678+
_dataverseenityname: "adx_communityforumposts",
679+
_displayname: "Forum Post",
680+
_etc: "10065",
681+
_primaryidfield: "adx_communityforumpostid",
682+
_primarynamefield: "adx_name",
683+
_disableplugins: "true",
684+
_foldername: "forum-posts",
685+
_exporttype: "SingleFolder",
686+
_fetchQueryParameters:
687+
"?$filter=adx_communityforumpostid eq {entityId}&$select=adx_name,adx_content",
688+
_multiFileFetchQueryParameters:
689+
"?$filter=_adx_forumthreadid_value ne null &$select=adx_name,adx_content,adx_communityforumpostid&$count=true",
690+
_attributes: "adx_content",
691+
_attributesExtension: new Map([["adx_content", "html"]]),
692+
},
693+
] : []),
473694
],
474695
},
475696
};

0 commit comments

Comments
 (0)