Skip to content

Commit 2959f1b

Browse files
committed
form customizer enhancements
1 parent dd29786 commit 2959f1b

10 files changed

Lines changed: 1059 additions & 893 deletions

File tree

src/pages/customizers/formcustomizers/chrome/chrome-actions.ts

Lines changed: 102 additions & 716 deletions
Large diffs are not rendered by default.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
export const getAllLists = (extPath: string) => {
2+
type libTypes = [any, any, any]
3+
4+
const moduleLoader = (extPath: string) => {
5+
return new Promise<libTypes>((resolve) => {
6+
const resolveWithContext = <T>(modules: T, resolve: (value: T) => void) => {
7+
if (!(window as any)._spPageContextInfo && (window as any).moduleLoaderPromise) {
8+
;(window as any).moduleLoaderPromise.then((e: any) => {
9+
;(window as any)._spPageContextInfo = e.context._pageContext._legacyPageContext
10+
resolve(modules)
11+
})
12+
} else {
13+
resolve(modules)
14+
}
15+
}
16+
17+
if ((window as any).SystemJS) {
18+
Promise.all<libTypes>([
19+
(window as any).SystemJS.import(extPath + 'bundles/sp.es5.umd.bundle.js'),
20+
(window as any).SystemJS.import(extPath + 'bundles/logging.es5.umd.bundle.js'),
21+
(window as any).SystemJS.import(extPath + 'bundles/queryable.es5.umd.bundle.js'),
22+
]).then((modules) => {
23+
resolveWithContext(modules, resolve)
24+
})
25+
} else {
26+
const s = document.createElement('script')
27+
s.src = extPath + 'bundles/system.js'
28+
;(document.head || document.documentElement).appendChild(s)
29+
s.onload = () =>
30+
Promise.all<libTypes>([
31+
(window as any).SystemJS.import(extPath + 'bundles/sp.es5.umd.bundle.js'),
32+
(window as any).SystemJS.import(extPath + 'bundles/logging.es5.umd.bundle.js'),
33+
(window as any).SystemJS.import(extPath + 'bundles/queryable.es5.umd.bundle.js'),
34+
]).then((modules) => {
35+
resolveWithContext(modules, resolve)
36+
})
37+
}
38+
})
39+
}
40+
41+
return moduleLoader(extPath).then((modules) => {
42+
const pnpsp = modules[0]
43+
const pnpqueryable = modules[2]
44+
45+
const sp = pnpsp
46+
.spfi()
47+
.using((instance: any) => {
48+
instance.using(
49+
pnpsp.DefaultHeaders(),
50+
pnpsp.DefaultInit(),
51+
pnpqueryable.BrowserFetchWithRetry(),
52+
pnpqueryable.DefaultParse()
53+
)
54+
instance.on.pre.prepend(async (url: string, init: any, result: any) => {
55+
url = (window as any)._spPageContextInfo?.webAbsoluteUrl
56+
? new URL(
57+
url,
58+
(window as any)._spPageContextInfo.webAbsoluteUrl.endsWith('/')
59+
? (window as any)._spPageContextInfo.webAbsoluteUrl
60+
: (window as any)._spPageContextInfo.webAbsoluteUrl + '/'
61+
).toString()
62+
: url
63+
return [url, init, result]
64+
})
65+
return instance
66+
})
67+
.using(
68+
pnpqueryable.InjectHeaders({
69+
Accept: 'application/json; odata=verbose',
70+
'Cache-Control': 'no-cache',
71+
'X-ClientService-ClientTag': 'SPEDITOR',
72+
})
73+
)
74+
75+
return sp.web.lists
76+
.filter('Hidden eq false')
77+
.select('Id', 'Title')
78+
.orderBy('Title')()
79+
.then((lists: any) => ({
80+
success: true,
81+
result: lists.map((list: any) => ({
82+
Id: list.Id,
83+
Title: list.Title,
84+
})),
85+
errorMessage: '',
86+
source: 'chrome-sp-editor',
87+
}))
88+
.catch((error: any) => ({
89+
success: false,
90+
result: null,
91+
errorMessage: error.message,
92+
source: 'chrome-sp-editor',
93+
}))
94+
})
95+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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('&quot;')) {
113+
manifestString = manifestString.replace(/&quot;/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

Comments
 (0)