1+ export interface IAppCatalogFormCustomizer {
2+ id : string
3+ alias : string
4+ solutionName : string
5+ }
6+
7+ export const getAvailableCustomizers = ( extPath : string ) => {
8+ type libTypes = [ any , any , any ]
9+
10+ const moduleLoader = ( extPath : string ) => {
11+ return new Promise < libTypes > ( ( resolve ) => {
12+ const resolveWithContext = < T > ( modules : T , resolve : ( value : T ) => void ) => {
13+ if ( ! ( window as any ) . _spPageContextInfo && ( window as any ) . moduleLoaderPromise ) {
14+ ; ( window as any ) . moduleLoaderPromise . then ( ( e : any ) => {
15+ ; ( window as any ) . _spPageContextInfo = e . context . _pageContext . _legacyPageContext
16+ resolve ( modules )
17+ } )
18+ } else {
19+ resolve ( modules )
20+ }
21+ }
22+
23+ if ( ( window as any ) . SystemJS ) {
24+ Promise . all < libTypes > ( [
25+ ( window as any ) . SystemJS . import ( extPath + 'bundles/sp.es5.umd.bundle.js' ) ,
26+ ( window as any ) . SystemJS . import ( extPath + 'bundles/logging.es5.umd.bundle.js' ) ,
27+ ( window as any ) . SystemJS . import ( extPath + 'bundles/queryable.es5.umd.bundle.js' ) ,
28+ ] ) . then ( ( modules ) => {
29+ resolveWithContext ( modules , resolve )
30+ } )
31+ } else {
32+ const s = document . createElement ( 'script' )
33+ s . src = extPath + 'bundles/system.js'
34+ ; ( document . head || document . documentElement ) . appendChild ( s )
35+ s . onload = ( ) =>
36+ Promise . all < libTypes > ( [
37+ ( window as any ) . SystemJS . import ( extPath + 'bundles/sp.es5.umd.bundle.js' ) ,
38+ ( window as any ) . SystemJS . import ( extPath + 'bundles/logging.es5.umd.bundle.js' ) ,
39+ ( window as any ) . SystemJS . import ( extPath + 'bundles/queryable.es5.umd.bundle.js' ) ,
40+ ] ) . then ( ( modules ) => {
41+ resolveWithContext ( modules , resolve )
42+ } )
43+ }
44+ } )
45+ }
46+
47+ return moduleLoader ( extPath ) . then ( async ( modules ) => {
48+ const pnpsp = modules [ 0 ]
49+ const pnpqueryable = modules [ 2 ]
50+
51+ const sp = pnpsp
52+ . spfi ( )
53+ . using ( ( instance : any ) => {
54+ instance . using (
55+ pnpsp . DefaultHeaders ( ) ,
56+ pnpsp . DefaultInit ( ) ,
57+ pnpqueryable . BrowserFetchWithRetry ( ) ,
58+ pnpqueryable . DefaultParse ( )
59+ )
60+ instance . on . pre . prepend ( async ( url : string , init : any , result : any ) => {
61+ url = ( window as any ) . _spPageContextInfo ?. webAbsoluteUrl
62+ ? new URL (
63+ url ,
64+ ( window as any ) . _spPageContextInfo . webAbsoluteUrl . endsWith ( '/' )
65+ ? ( window as any ) . _spPageContextInfo . webAbsoluteUrl
66+ : ( window as any ) . _spPageContextInfo . webAbsoluteUrl + '/'
67+ ) . toString ( )
68+ : url
69+ return [ url , init , result ]
70+ } )
71+ return instance
72+ } )
73+ . using (
74+ pnpqueryable . InjectHeaders ( {
75+ Accept : 'application/json; odata=verbose' ,
76+ 'Cache-Control' : 'no-cache' ,
77+ 'X-ClientService-ClientTag' : 'SPEDITOR' ,
78+ } )
79+ )
80+
81+ try {
82+ // Get tenant app catalog web
83+ const appCatalogWeb = await sp . getTenantAppCatalogWeb ( )
84+
85+ // Get the ComponentManifests list
86+ const cmListInfo = await appCatalogWeb . lists
87+ . filter ( "EntityTypeName eq 'ComponentManifestsList'" )
88+ . select ( 'Title' , 'Id' ) ( )
89+
90+ if ( cmListInfo . length === 0 ) {
91+ return {
92+ success : true ,
93+ result : [ ] ,
94+ errorMessage : '' ,
95+ source : 'chrome-sp-editor' ,
96+ }
97+ }
98+
99+ const cmListTitle = cmListInfo [ 0 ] . Title
100+
101+ // Get all SPFx extensions
102+ const items = await appCatalogWeb . lists
103+ . getByTitle ( cmListTitle )
104+ . items . select ( 'ClientComponentId' , 'ClientComponentType' , 'ClientComponentManifest' , 'SolutionName' )
105+ . filter ( "ClientComponentType eq 'Extension'" ) ( )
106+
107+ // Parse manifest + filter Form Customizers
108+ const formCustomizers = items
109+ . map ( ( i : any ) => {
110+ try {
111+ let manifestString = i . ClientComponentManifest
112+ if ( manifestString && manifestString . includes ( '"' ) ) {
113+ manifestString = manifestString . replace ( / & q u o t ; / g, '"' )
114+ }
115+ const manifest = JSON . parse ( manifestString )
116+ return {
117+ id : i . ClientComponentId ?. replace ( / [ { } ] / g, '' ) ,
118+ alias : manifest . alias || '' ,
119+ extensionType : manifest . extensionType || '' ,
120+ solutionName : i . SolutionName || '' ,
121+ }
122+ } catch {
123+ return null
124+ }
125+ } )
126+ . filter ( ( x : any ) => x && x . extensionType === 'FormCustomizer' )
127+ . map ( ( x : any ) => ( {
128+ id : x . id ,
129+ alias : x . alias ,
130+ solutionName : x . solutionName ,
131+ } ) )
132+
133+ return {
134+ success : true ,
135+ result : formCustomizers ,
136+ errorMessage : '' ,
137+ source : 'chrome-sp-editor' ,
138+ }
139+ } catch ( error : any ) {
140+ return {
141+ success : false ,
142+ result : [ ] as IAppCatalogFormCustomizer [ ] ,
143+ errorMessage : error . message || 'Failed to load available customizers' ,
144+ source : 'chrome-sp-editor' ,
145+ }
146+ }
147+ } )
148+ }
0 commit comments