This GrapesJS plugin integrates various APIs into the editor.
It makes a new UI available to the user so that she can manage custom states on components, linking them to data from a CMS or a data base or an API.
The plugin also has data management feature needed to manage components states, expressions made of tokens, build a query from the component states.
This code is part of a larger project: about Silex v3
The output of this plugin is component states which are stored on the components. This data then needs to be used by other plugins or your application. For example you can implement a "publish" feature to generate pages and data files for a static site generator or CMSs. Or you can make a vue app generator with it, by implementing a "renderer" which takes the states and adds the vue code to the generated website.
Here is how your application can use the data generated by the user with this plugin:
- Components states
import { getStateIds, getState } from './state'
// ...
const component = editor.getSelected()
// Get one specific state
console.log('innerHTML state:', getState(component, 'innerHTML'))
// Display all states of the component
const stateIds = getStateIds(component)
console.log('Alls states:', stateIds.map(stateId => getState(component, stateId)))
// Detect state changes
editor.on('component:state:changed', ({state, component}) => {
console.log('State changed:', {state, component})
})
Here is an example output:
innerHTML state: {"expression":[{"type":"property","propType":"field","fieldId":"post","label":"post","typeIds":["PostEntityResponse"],"dataSourceId":"strapi","kind":"object","options":{"id":"1"}},{"type":"property","propType":"field","fieldId":"data","label":"data","typeIds":["PostEntity"],"dataSourceId":"strapi","kind":"object"},{"type":"property","propType":"field","fieldId":"attributes","label":"attributes","typeIds":["Post"],"dataSourceId":"strapi","kind":"object"},{"type":"property","propType":"field","fieldId":"title","label":"title","typeIds":["String"],"dataSourceId":"strapi","kind":"scalar"}]}
All states: [{"expression":[{"type":"property","propType":"field","fieldId":"post","label":"post","typeIds":["PostEntityResponse"],"dataSourceId":"strapi","kind":"object","options":{"id":"1"}},{"type":"property","propType":"field","fieldId":"data","label":"data","typeIds":["PostEntity"],"dataSourceId":"strapi","kind":"object"},{"type":"property","propType":"field","fieldId":"attributes","label":"attributes","typeIds":["Post"],"dataSourceId":"strapi","kind":"object"},{"type":"property","propType":"field","fieldId":"title","label":"title","typeIds":["String"],"dataSourceId":"strapi","kind":"scalar"}]}]
- GraphQL query to get the data needed for the current page in functino of the data used in the states
// Get the current page
var page = editor.Pages.getSelected()
// Get the GraphQL query
const query = editor.DataSourceManager.getPageQuery(page)
console.log(query)
Here is an example output:
{
"strapi": "posts {\n data {\n attributes {\n title\n content\n}\n}\n}"
}
This plugin suports only GraphQL for now, contribution are welcome for support of other REST specific APIs or more generic Open API
Here is a list of GraphQL APIs you can use, it includes fake data and demo public APIs. Also consider these open source self hostable services:
- Strapi headless CMS
- Directus headless CMS
- Supabase database (a Firebase alternative)
- Tina markdown files to GraphQL tool
- Drupal, WordPress... All have GraphQL support
Contributions welcome for documenting the use of these data sources
<link href="https://unpkg.com/grapesjs/dist/css/grapes.min.css" rel="stylesheet">
<script src="https://unpkg.com/grapesjs"></script>
<script src="https://unpkg.com/@silexlabs/grapesjs-data-source"></script>
<div id="gjs"></div>
const editor = grapesjs.init({
container: '#gjs',
height: '100%',
fromElement: true,
storageManager: false,
plugins: ['@silexlabs/grapesjs-data-source'],
pluginsOpts: {
'@silexlabs/grapesjs-data-source': {
dataSources: [{
id: 'countries',
type: 'graphql',
label: 'Countries',
url: 'https://countries.trevorblades.com/graphql',
method: 'POST',
headers: {},
}],
properties: {
el: () => editor.Panels.getPanel('views-container').view.el,
button: () => editor.Panels.getPanel('views').get('buttons').get('open-tm'),
},
filters: 'liquid',
}
}
});
body, html {
margin: 0;
height: 100%;
}
Use a local strapi to test GraphQL data source
$ cd strapi
$ yarn develop
Strapi admin
http://localhost:1337/admin/
- Login:
alex@test.com
- Password:
test_TEST1
Strapi GraphQL:
http://localhost:1337/graphql
Bearer 456fe45a764921a26a81abd857bf987cd1735fbdbe58951ff5fc45a1c0ed2c52ab920cc0498b17411cd03954da7bb3e62e6bae612024360fb89717bd2274493ce190f3be14cdf47fccd33182fd795a67e48624e37f7276d9f84e98b2ec6945926d7a150e8c5deafa272aa9d9d97ee89e227c1edb1d6740ffd37a16b2298b3cc8
Use this as a data source in the plugin options:
grapesjs.init({
// ...
// Your config here
// ...
plugins: ['@silexlabs/grapesjs-data-source'],
pluginsOpts: {
'@silexlabs/grapesjs-data-source': {
dataSources: [
{
id: 'strapi',
type: 'graphql',
name: 'Strapi',
url: 'http://localhost:1337/graphql',
method: 'POST',
headers: {
'Authorization': 'Bearer 79c9e74b3cf4a9f5ce2836b81fd8aaf8a986b5696769456d3646a3213f5d7228634a1a15a8bbad4e87c09ab864c501499c6f8955cf350e49b89311764009aee68589a4b78f22c06b7e09835b48cd6f21fb84311ce873cd5672bd4652fde3f5f0db6afb258dfe7b93371b7632b551ecdd969256ffc076ab8f735b5d8c7d228825',
'Content-Type': 'application/json',
},
},
],
properties: {
el: () => editor.Panels.getPanel('views-container').view.el,
button: () => editor.Panels.getPanel('views').get('buttons').get('open-tm'),
},
filters: 'liquid',
}
}
});
Here are examples of APIs I tested:
Directus
{
id: 'directus',
type: 'graphql',
name: 'Directus',
url: `https://localhost:8085/graphql`,
method: 'POST',
headers: {
'Authorization': 'Bearer yjgwcj...0c_0zex',
'Content-Type': 'application/json',
},
}
Strapi
{
id: 'strapi',
type: 'graphql',
name: 'Strapi',
url: 'http://localhost:1337/graphql',
method: 'POST',
headers: {
'Authorization': 'Bearer 456fe45a764921a2...6b2298b3cc8',
'Content-Type': 'application/json',
},
}
Supabase (I had a CORS problem, let's discuss this in an issue if you want to give it a try)
{
id: 'supabase',
type: 'graphql',
name: 'Supabase',
url: `https://api.supabase.io/platform/projects/jpslgeqihfj/api/graphql`,
method: 'POST',
headers: {
'Authorization': 'Bearer eyjhbgcioijiuz...tww8imndplsfm',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
}
Option | Description | Default |
---|---|---|
dataSources |
List of data sources, see config examples and the plugin code for docs (data source options and GraphQL data source options) | [] |
filters |
The string 'liquidjs' for LiquidJs filters or a list of filters (JS objects like the ones in src/filters/liquid.ts ) |
[] |
view |
Options for the UI | [] |
view.el |
UI element to attach properties, states, attributes, loop | .gjs-pn-panel.gjs-pn-views-container |
view.button |
Optional GrapesJs button or a function which returns a button. This button will show/hide the UI | undefined which means no button |
view.styles |
CSS styles which are applied to the UI (inserted in a style tag) | See the file src/view/defaultStyles.ts |
view.optionsStyles |
CSS styles which are applied to each "expression selector" UI (inserted in a style tag) | See the file src/view/defaultStyles.ts |
view.defaultFixed |
If true, the UI shows fixed by default or if false it shows expression by default | false |
- CDN
https://unpkg.com/@silexlabs/grapesjs-data-source
- NPM
npm i @silexlabs/grapesjs-data-source
- GIT
git clone https://github.com/silexlabs/grapesjs-data-source.git
Directly in the browser
<link href="https://unpkg.com/grapesjs/dist/css/grapes.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/grapesjs"></script>
<script src="path/to/grapesjs-data-source.min.js"></script>
<div id="gjs"></div>
<script type="text/javascript">
var editor = grapesjs.init({
container: '#gjs',
// ...
plugins: ['@silexlabs/grapesjs-data-source'],
pluginsOpts: {
'@silexlabs/grapesjs-data-source': { /* options */ }
}
});
</script>
Modern javascript
import grapesjs from 'grapesjs';
import plugin from '@silexlabs/grapesjs-data-source';
import 'grapesjs/dist/css/grapes.min.css';
const editor = grapesjs.init({
container : '#gjs',
// ...
plugins: [plugin],
pluginsOpts: {
[plugin]: { /* options */ }
}
// or
plugins: [
editor => plugin(editor, { /* options */ }),
],
});
Clone the repository
$ git clone https://github.com/silexlabs/grapesjs-data-source.git
$ cd grapesjs-data-source
Install dependencies
$ npm i
Start the dev server
$ npm start
Build the source
$ npm run build
Here are the key parts of the plugin:
-
editor.DataSourceManager: A Backbone collection to manage the APIs. This collection holds the different available data sources and their settings (type, url, auth...). This data is provided by the config. The main API of this class is
getDataTree()
to get the data tree -
DataTree: A class to manage component states and generate queries to APIs. Component states are used to build the query needed for the current page, and they can be used to create other states in child components or override a component's attributes or style. This collection is generated from the components attributes, it is not stored with the site data.
-
DataSource: An interface for classes managing an API, abstracting the calls and queries. It includes methods like
getData(query)
andgetTypes()
.
The components with "Loop Template" also have a current
state, similar to dynamic pages.
The plugin's architecture is designed to provide a flexible and efficient way to manage data and rendering in the editor, supporting dynamic content and static site generation. It abstracts the complexities of working with different APIs and provides a unified way to manage component states, templates, and dynamic content.
MIT