@silexlabs/silex 3.3.1-4 → 3.3.1-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +27 -2
  2. package/dist/client/index.html +2 -2
  3. package/dist/client/js/main.js +214 -214
  4. package/dist/client/js/main.js.LICENSE.txt +1 -12
  5. package/dist/plugins/server/plugins/server/FtpConnector.js +53 -8
  6. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
  7. package/dist/plugins/server/plugins/server/GitlabConnector.js +21 -66
  8. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
  9. package/dist/plugins/server/server/connectors/FsStorage.js +50 -4
  10. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
  11. package/dist/plugins/server/server/utils/websiteDataSerialization.d.ts +20 -0
  12. package/dist/plugins/server/server/utils/websiteDataSerialization.js +127 -0
  13. package/dist/plugins/server/server/utils/websiteDataSerialization.js.map +1 -0
  14. package/dist/server/page.js +14 -0
  15. package/dist/server/server/connectors/FsStorage.js +40 -4
  16. package/dist/server/server/utils/websiteDataSerialization.js +85 -0
  17. package/package.json +10 -10
  18. package/src/ts/client/grapesjs/PublicationUi.ts +1 -1
  19. package/src/ts/client/grapesjs/index.ts +9 -11
  20. package/src/ts/client/grapesjs/storage.ts +6 -9
  21. package/src/ts/client/index.ts +0 -2
  22. package/src/ts/plugins/server/FtpConnector.test.ts +2 -1
  23. package/src/ts/plugins/server/FtpConnector.ts +61 -9
  24. package/src/ts/plugins/server/GitlabConnector.ts +22 -80
  25. package/src/ts/server/connectors/FsStorage.test.ts +6 -2
  26. package/src/ts/server/connectors/FsStorage.ts +60 -5
  27. package/src/ts/server/utils/websiteDataSerialization.test.ts +59 -0
  28. package/src/ts/server/utils/websiteDataSerialization.ts +143 -0
  29. package/src/ts/client/grapesjs/dynamic-plugins.ts +0 -63
  30. package/src/ts/client/grapesjs/plugin-options.ts +0 -243
@@ -27,6 +27,7 @@ import { getPageSlug } from '../../page'
27
27
  import e from 'express'
28
28
  import { fork } from 'child_process'
29
29
  import { Page } from 'grapesjs'
30
+ import { stringify, split, merge } from '../../server/utils/websiteDataSerialization'
30
31
 
31
32
  /**
32
33
  * Gitlab connector
@@ -121,16 +122,6 @@ interface GitlabFetchCommits {
121
122
  since: string
122
123
  }
123
124
 
124
- interface GitlabPage {
125
- id: string
126
- name: string
127
- isFile: true
128
- }
129
-
130
- interface GitlabWebsiteData {
131
- fileFormatVersion: string
132
- pages: GitlabPage[]
133
- }
134
125
 
135
126
  // interface MetaRepoFileContent {
136
127
  // websites: {
@@ -221,9 +212,6 @@ function sanitizeGitlabPath(name: string): string {
221
212
  .toLowerCase()
222
213
  }
223
214
 
224
- function getPageName(page: Page | GitlabPage) {
225
- return (page as any).getName ? (page as Page).getName() : (page as GitlabPage).name
226
- }
227
215
 
228
216
  export default class GitlabConnector implements StorageConnector {
229
217
  connectorId = 'gitlab'
@@ -739,40 +727,15 @@ export default class GitlabConnector implements StorageConnector {
739
727
  */
740
728
  async readWebsite(session: GitlabSession, websiteId: string): Promise<WebsiteData> {
741
729
  const websiteDataBuf = await this.downloadRawFile(session, websiteId, WEBSITE_DATA_FILE)
742
- const websiteDataOb = JSON.parse(websiteDataBuf.toString('utf8')) as GitlabWebsiteData & WebsiteData
743
- const { fileFormatVersion, ...websiteData } = websiteDataOb
730
+ const websiteDataContent = websiteDataBuf.toString('utf8')
744
731
 
745
- // Check the file format version
746
- if (fileFormatVersion !== WEBSITE_DATA_FILE_FORMAT_VERSION) {
747
- // This should be handled by a migration mechanism
748
- console.warn('Gitlab connector: website data file format version mismatch', fileFormatVersion, '!=', WEBSITE_DATA_FILE_FORMAT_VERSION)
732
+ // Use the common merge function to reconstruct website data
733
+ const pageLoader = async (pagePath: string): Promise<string> => {
734
+ const pageBuffer = await this.downloadRawFile(session, websiteId, pagePath)
735
+ return pageBuffer.toString('utf8')
749
736
  }
750
737
 
751
- // This happens when the website was just created
752
- // Let grapesjs create the pages in the frontend
753
- if (!websiteData.pages) {
754
- return websiteData as WebsiteData
755
- }
756
-
757
- // Load each page in parallel
758
- const pages = await Promise.all(websiteData.pages.map(async (page: GitlabPage | Page) => {
759
- if ((page as GitlabPage).isFile) {
760
- const name = getPageName(page)
761
- const slug = getPageSlug(name)
762
- const fileName = (`${slug}-${page.id}`)
763
- const filePath = `${WEBSITE_PAGES_FOLDER}/${fileName}.json`
764
- const pageContent = await this.downloadRawFile(session, websiteId, filePath)
765
- const res = JSON.parse(pageContent.toString('utf8')) as Page
766
- return res
767
- }
768
- return page as Page
769
- }))
770
-
771
- // Read each page file if needed
772
- return {
773
- ...websiteData,
774
- pages,
775
- } as WebsiteData
738
+ return await merge(websiteDataContent, pageLoader)
776
739
  }
777
740
 
778
741
  /**
@@ -787,7 +750,7 @@ export default class GitlabConnector implements StorageConnector {
787
750
  name: this.options.repoPrefix + websiteMeta.name,
788
751
  }
789
752
  }) as any
790
- await this.createFile(session, project.id, WEBSITE_DATA_FILE, JSON.stringify({} as WebsiteData))
753
+ await this.createFile(session, project.id, WEBSITE_DATA_FILE, stringify({} as WebsiteData))
791
754
  //await this.createFile(session, project.id, WEBSITE_META_DATA_FILE, JSON.stringify(websiteMeta))
792
755
  //await this.updateWebsite(session, project.id, {} as WebsiteData)
793
756
  //await this.setWebsiteMeta(session, project.id, websiteMeta)
@@ -812,17 +775,19 @@ export default class GitlabConnector implements StorageConnector {
812
775
  })
813
776
 
814
777
  // **
815
- // Create the pages for batch upload
816
- const pages = websiteData.pages.map((page: Page) => {
817
- /* @ts-ignore */
818
- const fileName = encodeURIComponent(`${getPageSlug(getPageName(page))}-${page.id}`)
819
- const filePath = `${WEBSITE_PAGES_FOLDER}/${fileName}.json`
820
- const content = JSON.stringify(page)
778
+ // Use the common split function to create files
779
+ const filesToWrite = split(websiteData)
780
+
781
+ // **
782
+ // Process each file to create/update
783
+ for (const file of filesToWrite) {
784
+ const filePath = file.path
785
+ const content = file.content
821
786
  const newSha = computeGitBlobSha(content, false)
822
787
 
823
- const existingSha = existingFiles.get(filePath)
788
+ const existingSha = existingFiles.get(filePath) || (filePath === WEBSITE_DATA_FILE ? 'always-update' : undefined)
824
789
 
825
- if (existingSha) {
790
+ if (existingSha && existingSha !== 'always-update') {
826
791
  if (existingSha !== newSha) {
827
792
  batchActions.push({
828
793
  action: 'update',
@@ -832,26 +797,18 @@ export default class GitlabConnector implements StorageConnector {
832
797
  } // else: skip unchanged file
833
798
  } else {
834
799
  batchActions.push({
835
- action: 'create',
800
+ action: file.path === WEBSITE_DATA_FILE ? 'update' : 'create',
836
801
  file_path: filePath,
837
802
  content,
838
803
  })
839
804
  }
840
-
841
- return {
842
- name: getPageName(page),
843
- id: page.id,
844
- isFile: true,
845
- }
846
- })
805
+ }
847
806
 
848
807
  // **
849
808
  // Delete pages that are not in the new website data
809
+ const newPageFiles = new Set(filesToWrite.filter(f => f.path.startsWith(WEBSITE_PAGES_FOLDER)).map(f => f.path))
850
810
  for (const filePath of existingFiles.keys()) {
851
- const pageName = filePath.replace(/.*\//, '').replace(/\.json$/, '')
852
- const pageId = pageName.split('-').pop()
853
- const page = websiteData.pages.find((p: Page) => p.id === pageId)
854
- if (!page) {
811
+ if (!newPageFiles.has(filePath)) {
855
812
  batchActions.push({
856
813
  action: 'delete',
857
814
  file_path: filePath,
@@ -859,21 +816,6 @@ export default class GitlabConnector implements StorageConnector {
859
816
  }
860
817
  }
861
818
 
862
- // **
863
- // Add the main website data file
864
- const websiteDataWithGitlabPages = {
865
- ...websiteData,
866
- fileFormatVersion: WEBSITE_DATA_FILE_FORMAT_VERSION,
867
- pages,
868
- } as GitlabWebsiteData
869
-
870
- const websiteJsonContent = JSON.stringify(websiteDataWithGitlabPages)
871
- batchActions.push({
872
- action: 'update',
873
- file_path: WEBSITE_DATA_FILE,
874
- content: websiteJsonContent,
875
- })
876
-
877
819
  // **
878
820
  // Perform a batch commit
879
821
  return this.callApi({
@@ -3,6 +3,7 @@ import { ServerConfig } from '../config'
3
3
  import { FsStorage } from './FsStorage'
4
4
  import { readFileSync, rmdirSync, statSync } from 'fs'
5
5
  import { join } from 'path'
6
+ import { WEBSITE_DATA_FILE } from '../../constants'
6
7
 
7
8
  const storageRootPath = '/tmp/silex-tests'
8
9
  const assetsFolder = 'assets'
@@ -45,7 +46,10 @@ describe('FsStorage website', () => {
45
46
  })
46
47
  const id = await connector.createWebsite(dummySession, { name: 'dummy name', connectorUserSettings: {} })
47
48
  expect(id).toBeDefined()
48
- expect(() => statSync(join(storageRootPath, id, 'website.json'))).not.toThrow()
49
- expect(readFileSync(join(storageRootPath, id, 'website.json'), 'utf8')).toBe(JSON.stringify({}))
49
+ expect(() => statSync(join(storageRootPath, id, WEBSITE_DATA_FILE))).not.toThrow()
50
+ const content = readFileSync(join(storageRootPath, id, WEBSITE_DATA_FILE), 'utf8')
51
+ const parsed = JSON.parse(content)
52
+ expect(parsed).toHaveProperty('fileFormatVersion', '1.0.0')
53
+ expect(parsed).toHaveProperty('pages', [])
50
54
  })
51
55
  })
@@ -23,10 +23,11 @@ import { ConnectorUser, WebsiteMeta, JobStatus, WebsiteId, ConnectorType, Websit
23
23
  import { userInfo } from 'os'
24
24
  import { requiredParam } from '../utils/validation'
25
25
  import { ServerConfig } from '../config'
26
- import { DEFAULT_WEBSITE_ID, WEBSITE_DATA_FILE, WEBSITE_META_DATA_FILE } from '../../constants'
26
+ import { DEFAULT_WEBSITE_ID, WEBSITE_DATA_FILE, WEBSITE_META_DATA_FILE, WEBSITE_PAGES_FOLDER } from '../../constants'
27
27
  import { Readable } from 'stream'
28
28
  import { v4 as uuid } from 'uuid'
29
29
  import { fileURLToPath } from 'url'
30
+ import { stringify, split, merge } from '../utils/websiteDataSerialization'
30
31
 
31
32
  // Variables needed for jest tests
32
33
  if(!globalThis.__dirname) {
@@ -145,7 +146,7 @@ export class FsStorage implements StorageConnector<FsSession> {
145
146
 
146
147
  async setWebsiteMeta(session: any, id: string, data: WebsiteMetaFileContent): Promise<void> {
147
148
  const websiteId = requiredParam<WebsiteId>(id, 'website id')
148
- const content = JSON.stringify(data)
149
+ const content = stringify(data)
149
150
  const path = join(this.options.path, id, WEBSITE_META_DATA_FILE)
150
151
  await fs.writeFile(path, content)
151
152
  }
@@ -183,14 +184,68 @@ export class FsStorage implements StorageConnector<FsSession> {
183
184
  async readWebsite(session: FsSession, websiteId: WebsiteId): Promise<WebsiteData> {
184
185
  const id = requiredParam<WebsiteId>(websiteId, 'website id')
185
186
  const path = join(this.options.path, id, WEBSITE_DATA_FILE)
187
+
186
188
  const content = await fs.readFile(path)
187
- return JSON.parse(content.toString())
189
+ const websiteDataContent = content.toString()
190
+
191
+ // Check if this is the new split format
192
+ const parsedData = JSON.parse(websiteDataContent)
193
+ if (parsedData.fileFormatVersion === '1.0.0') {
194
+ // Use the merge function to reconstruct website data
195
+ const pageLoader = async (pagePath: string): Promise<string> => {
196
+ const fullPath = join(this.options.path, id, pagePath)
197
+ const pageContent = await fs.readFile(fullPath)
198
+ return pageContent.toString()
199
+ }
200
+
201
+ return await merge(websiteDataContent, pageLoader)
202
+ } else {
203
+ // Legacy format, return as is
204
+ return parsedData
205
+ }
188
206
  }
189
207
 
190
208
  async updateWebsite(session: FsSession, websiteId: WebsiteId, data: WebsiteData): Promise<void> {
191
209
  const id = requiredParam<WebsiteId>(websiteId, 'website id')
192
- const path = join(this.options.path, id, WEBSITE_DATA_FILE)
193
- await fs.writeFile(path, JSON.stringify(data))
210
+ const websitePath = join(this.options.path, id)
211
+
212
+ // Use the split function to create separate files for pages
213
+ const filesToWrite = split(data)
214
+
215
+ // Ensure the website directory exists
216
+ await fs.mkdir(websitePath, { recursive: true })
217
+
218
+ // Ensure the pages directory exists if we have page files
219
+ const hasPageFiles = filesToWrite.some(f => f.path.startsWith(WEBSITE_PAGES_FOLDER))
220
+ if (hasPageFiles) {
221
+ await fs.mkdir(join(websitePath, WEBSITE_PAGES_FOLDER), { recursive: true })
222
+ }
223
+
224
+ // **
225
+ // Delete pages that are not in the new website data
226
+ const pagesPath = join(websitePath, WEBSITE_PAGES_FOLDER)
227
+ try {
228
+ const existingPageFiles = await fs.readdir(pagesPath)
229
+ const newPageFiles = new Set(
230
+ filesToWrite
231
+ .filter(f => f.path.startsWith(WEBSITE_PAGES_FOLDER))
232
+ .map(f => f.path.replace(`${WEBSITE_PAGES_FOLDER}/`, ''))
233
+ )
234
+
235
+ for (const existingFile of existingPageFiles) {
236
+ if (existingFile.endsWith('.json') && !newPageFiles.has(existingFile)) {
237
+ await fs.unlink(join(pagesPath, existingFile))
238
+ }
239
+ }
240
+ } catch (error) {
241
+ // Ignore error if pages directory doesn't exist yet
242
+ }
243
+
244
+ // Write all files
245
+ for (const file of filesToWrite) {
246
+ const filePath = join(websitePath, file.path)
247
+ await fs.writeFile(filePath, file.content)
248
+ }
194
249
  }
195
250
 
196
251
  async deleteWebsite(session: FsSession, websiteId: WebsiteId): Promise<void> {
@@ -0,0 +1,59 @@
1
+ import { stringify, split, merge } from './websiteDataSerialization'
2
+ import { expect, it, describe } from '@jest/globals'
3
+ import { WebsiteData, defaultWebsiteData } from '../../types'
4
+ import { WEBSITE_DATA_FILE } from '../../constants'
5
+
6
+ describe('websiteDataSerialization', () => {
7
+ describe('stringify', () => {
8
+ it('should format JSON with sorted keys', () => {
9
+ const data = { z: 1, a: 2, m: { z: 3, a: 4 } }
10
+ const result = stringify(data)
11
+ expect(result).toBe(`{
12
+ "a": 2,
13
+ "m": {
14
+ "a": 4,
15
+ "z": 3
16
+ },
17
+ "z": 1
18
+ }`)
19
+ })
20
+ })
21
+
22
+ describe('split', () => {
23
+ it('should split website data into separate files', () => {
24
+ const websiteData: WebsiteData = {
25
+ ...defaultWebsiteData,
26
+ pages: [
27
+ { id: 'page1', getName: () => 'Home' } as any,
28
+ { id: 'page2', getName: () => 'About' } as any
29
+ ]
30
+ }
31
+
32
+ const files = split(websiteData)
33
+
34
+ expect(files).toHaveLength(3)
35
+ expect(files[0].path).toBe('src/home-page1.json')
36
+ expect(files[1].path).toBe('src/about-page2.json')
37
+ expect(files[2].path).toBe(WEBSITE_DATA_FILE)
38
+
39
+ const mainFile = JSON.parse(files[2].content)
40
+ expect(mainFile.fileFormatVersion).toBe('1.0.0')
41
+ expect(mainFile.pages[0].isFile).toBe(true)
42
+ })
43
+ })
44
+
45
+ describe('merge', () => {
46
+ it('should handle legacy format', async () => {
47
+ const legacyContent = `{
48
+ "settings": {},
49
+ "pages": [{ "id": "page1" }]
50
+ }`
51
+
52
+ const pageLoader = async () => { throw new Error('Should not be called') }
53
+ const result = await merge(legacyContent, pageLoader)
54
+
55
+ expect(result.pages).toHaveLength(1)
56
+ expect(result.pages[0].id).toBe('page1')
57
+ })
58
+ })
59
+ })
@@ -0,0 +1,143 @@
1
+ /*
2
+ * Silex website builder, free/libre no-code tool for makers.
3
+ * Copyright (c) 2023 lexoyo and Silex Labs foundation
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU Affero General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Affero General Public License
15
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import { WebsiteData } from '../../types'
19
+ import { Page } from 'grapesjs'
20
+ import { getPageSlug } from '../../page'
21
+ import { WEBSITE_PAGES_FOLDER, WEBSITE_DATA_FILE } from '../../constants'
22
+
23
+ /**
24
+ * Serialize JSON with stable formatting for git
25
+ * - Uses 2-space indentation for readability
26
+ * - Sorts object keys deterministically to avoid random diffs
27
+ */
28
+ export function stringify(data: any): string {
29
+ return JSON.stringify(data, sortKeys, 2)
30
+ }
31
+
32
+ /**
33
+ * Sort object keys for consistent output across serializations
34
+ */
35
+ function sortKeys(key: string, value: any): any {
36
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
37
+ const sorted: any = {}
38
+ Object.keys(value).sort().forEach(k => {
39
+ sorted[k] = value[k]
40
+ })
41
+ return sorted
42
+ }
43
+ return value
44
+ }
45
+
46
+ /**
47
+ * Split website data into multiple files
48
+ * Returns array of files to create/update
49
+ */
50
+ export function split(websiteData: WebsiteData): Array<{path: string, content: string}> {
51
+ const files: Array<{path: string, content: string}> = []
52
+
53
+ // Split pages into separate files
54
+ const pages = websiteData.pages?.map((page: Page) => {
55
+ const pageName = getPageName(page)
56
+ const slug = getPageSlug(pageName)
57
+ const fileName = `${slug}-${page.id}.json`
58
+ const filePath = `${WEBSITE_PAGES_FOLDER}/${fileName}`
59
+
60
+ files.push({
61
+ path: filePath,
62
+ content: stringify(page)
63
+ })
64
+
65
+ return {
66
+ name: pageName,
67
+ id: page.id,
68
+ isFile: true,
69
+ }
70
+ }) || []
71
+
72
+ // Create main website data file without pages content
73
+ const websiteDataWithoutPages = {
74
+ ...websiteData,
75
+ fileFormatVersion: '1.0.0',
76
+ pages,
77
+ }
78
+
79
+ files.push({
80
+ path: WEBSITE_DATA_FILE,
81
+ content: stringify(websiteDataWithoutPages)
82
+ })
83
+
84
+ return files
85
+ }
86
+
87
+ /**
88
+ * Reconstruct website data from main file and page loader function
89
+ * The pageLoader function will be called for each page that needs to be loaded
90
+ */
91
+ export async function merge(
92
+ websiteDataContent: string,
93
+ pageLoader: (pagePath: string) => Promise<string>
94
+ ): Promise<WebsiteData> {
95
+ const websiteDataOb = JSON.parse(websiteDataContent) as any
96
+ const { fileFormatVersion, ...websiteData } = websiteDataOb
97
+
98
+ // Check file format version
99
+ if (fileFormatVersion && fileFormatVersion !== '1.0.0') {
100
+ console.warn('Website data file format version mismatch', fileFormatVersion, '!=', '1.0.0')
101
+ }
102
+
103
+ // Handle legacy format (no split pages) or empty pages
104
+ if (!websiteData.pages || websiteData.pages.length === 0) {
105
+ return websiteData as WebsiteData
106
+ }
107
+
108
+ // Check if pages are already embedded (legacy format)
109
+ if (websiteData.pages[0] && !websiteData.pages[0].isFile) {
110
+ return websiteData as WebsiteData
111
+ }
112
+
113
+ // Load pages from separate files
114
+ const pages = await Promise.all(websiteData.pages.map(async (pageRef: any) => {
115
+ if (pageRef.isFile) {
116
+ const pageName = pageRef.name
117
+ const slug = getPageSlug(pageName)
118
+ const fileName = `${slug}-${pageRef.id}.json`
119
+ const filePath = `${WEBSITE_PAGES_FOLDER}/${fileName}`
120
+
121
+ try {
122
+ const pageContent = await pageLoader(filePath)
123
+ return JSON.parse(pageContent) as Page
124
+ } catch (error) {
125
+ console.warn(`Could not load page file: ${filePath}`, error)
126
+ return pageRef
127
+ }
128
+ }
129
+ return pageRef as Page
130
+ }))
131
+
132
+ return {
133
+ ...websiteData,
134
+ pages,
135
+ } as WebsiteData
136
+ }
137
+
138
+ /**
139
+ * Get page name from page object
140
+ */
141
+ function getPageName(page: Page | any): string {
142
+ return (page as any).getName ? (page as Page).getName() : (page as any).name
143
+ }
@@ -1,63 +0,0 @@
1
- /**
2
- * Dynamic plugin loader for external GrapesJS plugins
3
- * These plugins are loaded at runtime to reduce initial bundle size
4
- */
5
-
6
- export interface PluginDefinition {
7
- name: string
8
- value: any
9
- }
10
-
11
- /**
12
- * Load all external plugins dynamically
13
- */
14
- export async function loadDynamicPlugins(): Promise<PluginDefinition[]> {
15
- const [
16
- blocksBasicPlugin,
17
- styleFilterPlugin,
18
- formPlugin,
19
- codePlugin,
20
- filterStyles,
21
- symbolsPlugin,
22
- loadingPlugin,
23
- fontsDialogPlugin,
24
- selectorPlugin,
25
- rateLimitPlugin,
26
- borderPlugin,
27
- backgroundPlugin,
28
- notificationsPlugin,
29
- keymapsDialogPlugin,
30
- ] = await Promise.all([
31
- import('grapesjs-blocks-basic').then(m => m.default),
32
- import('grapesjs-style-filter').then(m => m.default),
33
- import('grapesjs-plugin-forms').then(m => m.default),
34
- import('grapesjs-custom-code').then(m => m.default),
35
- import('@silexlabs/grapesjs-filter-styles').then(m => m.default),
36
- import('@silexlabs/grapesjs-symbols').then(m => m.default),
37
- import('@silexlabs/grapesjs-loading').then(m => m.default),
38
- import('@silexlabs/grapesjs-fonts').then(m => m.default),
39
- import('@silexlabs/grapesjs-advanced-selector').then(m => m.default),
40
- import('@silexlabs/grapesjs-storage-rate-limit').then(m => m.default),
41
- import('grapesjs-style-border').then(m => m.default),
42
- import('grapesjs-style-bg').then(m => m.default),
43
- import('@silexlabs/grapesjs-notifications').then(m => m.default),
44
- import('@silexlabs/grapesjs-keymaps-dialog').then(m => m.default),
45
- ])
46
-
47
- return [
48
- { name: 'grapesjs-blocks-basic', value: blocksBasicPlugin },
49
- { name: 'grapesjs-style-filter', value: styleFilterPlugin },
50
- { name: 'grapesjs-plugin-forms', value: formPlugin },
51
- { name: 'grapesjs-custom-code', value: codePlugin },
52
- { name: '@silexlabs/grapesjs-filter-styles', value: filterStyles },
53
- { name: '@silexlabs/grapesjs-symbols', value: symbolsPlugin },
54
- { name: '@silexlabs/grapesjs-loading', value: loadingPlugin },
55
- { name: '@silexlabs/grapesjs-fonts', value: fontsDialogPlugin },
56
- { name: '@silexlabs/grapesjs-advanced-selector', value: selectorPlugin },
57
- { name: '@silexlabs/grapesjs-storage-rate-limit', value: rateLimitPlugin },
58
- { name: 'grapesjs-style-border', value: borderPlugin },
59
- { name: 'grapesjs-style-bg', value: backgroundPlugin },
60
- { name: '@silexlabs/grapesjs-notifications', value: notificationsPlugin },
61
- { name: '@silexlabs/grapesjs-keymaps-dialog', value: keymapsDialogPlugin },
62
- ]
63
- }