Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/data sources #6018

Merged
merged 86 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
888a008
Start DataSourceManager
artf Feb 24, 2024
88a1f7f
Start data variable component
artf Feb 24, 2024
903d6cf
Up DataSourceManager
artf Feb 24, 2024
3e58fbe
Up data sources
artf Feb 24, 2024
9eec8b8
Update DataRecord update
artf Feb 27, 2024
b507f68
Up triggerChange
artf Feb 27, 2024
3b3b1f4
Init tests for dataSources
artf Feb 27, 2024
22edded
Refactor
artf Feb 28, 2024
970990e
Improve data variable listeners
artf Feb 28, 2024
6f52e50
Update data variable listener
artf Mar 1, 2024
98fb63c
Add remove to dataSources
artf Mar 1, 2024
9d64fe2
Add getRecord to DataSource
artf Mar 1, 2024
9137f4b
Add removeRecord
artf Mar 1, 2024
1fb6597
Up data record changes tests
artf Mar 1, 2024
32a22b9
Up
artf Mar 1, 2024
ef2d3b2
Up tests
artf Mar 1, 2024
bf04d7d
Up listenToData
artf Mar 2, 2024
7abb437
Add getInnerHTML to ComponentDataVariable
artf Mar 2, 2024
5b2b60d
Up
artf Mar 2, 2024
5f8c188
Merge branch 'dev' into feature/data-sources
danstarns Aug 2, 2024
415d81d
refactor: move dir to _ path pattern & give types to getters
danstarns Aug 2, 2024
e1dae2d
test: refactor to _ data_sources
danstarns Aug 3, 2024
121b839
feat: init datasources into style
danstarns Aug 4, 2024
d371b25
feat: data watchers
danstarns Aug 4, 2024
b8858dc
refactor: *
danstarns Aug 4, 2024
d9154c6
test: add default style var coverage
danstarns Aug 4, 2024
704c587
Merge branch 'dev' into feature/data-sources
danstarns Aug 6, 2024
1b4e092
init: DataSourceTransformers
danstarns Aug 7, 2024
597b207
Merge branch 'dev' into feature/data-sources
danstarns Aug 7, 2024
9088f92
refactor: remove type conflict
danstarns Aug 7, 2024
40c48b4
feat: add onRecordSet methoda
danstarns Aug 8, 2024
ea3ec6a
feat: add onRecordRead datasource
danstarns Aug 8, 2024
c31ef1a
feat: add onRecordDelete data source
danstarns Aug 8, 2024
21930e8
init: add traits
danstarns Aug 14, 2024
adb0544
test: add traint input update coverage
danstarns Aug 14, 2024
f117a96
Merge branch 'dev' into feature/data-sources
danstarns Aug 14, 2024
ecf07e0
refactor: use base data var class and move code into data_sources dire
danstarns Aug 14, 2024
4c24860
test: split data sources into seperate test files around topics
danstarns Aug 14, 2024
b2c9f3f
refactor: remove unused mixins
danstarns Aug 15, 2024
ac08703
test: name changes
danstarns Aug 15, 2024
18e0271
fix: add optional check for model
danstarns Aug 15, 2024
13bf741
test: add placeholder test for trait var
danstarns Aug 15, 2024
b911c08
test: add checkbox datasources trait coverage
danstarns Aug 16, 2024
69c6395
test: add image trait datasource coverage
danstarns Aug 16, 2024
a77af21
test: add link traits data sources coverage
danstarns Aug 16, 2024
4f6139a
docs: init DataSources
danstarns Aug 16, 2024
acb44a5
docs: hook datasources into sidebar
danstarns Aug 17, 2024
17eafe1
test: add datasources init Serialization
danstarns Aug 17, 2024
b53ce12
Merge 'dev' into feature/data-sources
danstarns Aug 20, 2024
592ea79
format: *
danstarns Aug 20, 2024
7ce74dc
Merge branch 'dev' into feature/data-sources
danstarns Aug 21, 2024
80f67e5
feat: working DataVariable with .getProjectData method
danstarns Aug 22, 2024
0f840ff
refactor
danstarns Aug 22, 2024
3be94a9
feat: make DataSources work with .loadProjectData
danstarns Aug 22, 2024
77cdb34
docs: init for datasources
danstarns Aug 22, 2024
2de091a
import fix
danstarns Aug 22, 2024
891f61f
up
danstarns Aug 22, 2024
7ff69fb
refactor: remove unused code
danstarns Aug 22, 2024
a058436
Merge branch 'dev' into feature/data-sources
danstarns Aug 23, 2024
02596a4
refactor: remove logs
danstarns Aug 23, 2024
305d0a8
Merge branch 'dev' into feature/data-sources
artf Aug 25, 2024
987874b
Merge branch 'dev' into feature/data-sources
danstarns Aug 26, 2024
31eb7b8
Merge branch 'dev' into feature/data-sources
danstarns Aug 27, 2024
ed0b0b7
Merge branch 'feature/data-sources' of github.com:GrapesJS/grapesjs i…
danstarns Aug 27, 2024
bceb3a2
docs: *
danstarns Aug 27, 2024
b781f9d
format
danstarns Aug 27, 2024
5d6c479
refactor: move DataSourceProps to types file
danstarns Aug 27, 2024
63b377e
fix: type import in tests
danstarns Aug 27, 2024
1d6d48a
refactor: remove redundant initialize method
danstarns Aug 27, 2024
fdd79e6
test: add component attribute checks alongside model traits
danstarns Aug 27, 2024
fa40cc0
docs: add issue pr link
danstarns Aug 28, 2024
29d2a03
refactor: simplify set logic
danstarns Aug 28, 2024
da44545
refactor: bring back getValye, getContext and fromPath, add nested tests
danstarns Aug 28, 2024
85fbea2
fix: more usage of fromPath for nested items
danstarns Aug 28, 2024
5dc734b
feat: changeProp usage
danstarns Aug 29, 2024
733656f
feat: add setRecords back
danstarns Aug 29, 2024
c0c79dd
refactor: change data var to defaultValue
danstarns Aug 29, 2024
0655954
feat: add default value record removal check and proper listeners
danstarns Aug 29, 2024
843492f
feat: reuse data listeners for style and traits
danstarns Aug 29, 2024
e01d4af
test: remove repeated test
danstarns Aug 29, 2024
7f22ab8
feat: support key value for set with transformers
danstarns Aug 30, 2024
74085e8
feat: reuse DataVariableListenerManager on ComponentDataVar
danstarns Aug 30, 2024
f4cb333
refactor: change to onRecordSetValue
danstarns Aug 30, 2024
d9e1bf5
refactor: remove not needed transformers
danstarns Aug 30, 2024
63e3e19
Merge branch 'dev' into feature/data-sources
danstarns Aug 30, 2024
575da3d
Merge branch 'dev' into feature/data-sources
artf Aug 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/abstract/Module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export abstract class ItemManagerModule<
TCollection extends Collection = Collection
> extends Module<TConf> {
cls: any[] = [];
protected all: TCollection;
all: TCollection;
view?: View;

constructor(
Expand Down
2 changes: 1 addition & 1 deletion src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface NOOP {}

export type Debounced = Function & { cancel(): void };

export type SetOptions = Backbone.ModelSetOptions & { avoidStore?: boolean };
export type SetOptions = Backbone.ModelSetOptions & { avoidStore?: boolean; avoidTransformers?: boolean };

export type AddOptions = Backbone.AddOptions & { temporary?: boolean; action?: string };

Expand Down
59 changes: 59 additions & 0 deletions src/data_sources/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ItemManagerModule, ModuleConfig } from '../abstract/Module';
import { AddOptions, RemoveOptions } from '../common';
import EditorModel from '../editor/model/Editor';
import DataSource from './model/DataSource';
import DataSources from './model/DataSources';
import { DataSourceProps, DataSourcesEvents } from './types';
import { Events } from 'backbone';

export default class DataSourceManager extends ItemManagerModule<ModuleConfig, DataSources> {
storageKey = '';
events = DataSourcesEvents;
destroy(): void {}

constructor(em: EditorModel) {
super(em, 'DataSources', new DataSources([], em), DataSourcesEvents);
Object.assign(this, Events); // Mixin Backbone.Events
}

/**
* Add new data source.
* @param {Object} props Data source properties.
* @returns {[DataSource]} Added data source.
* @example
* const ds = dsm.add({
* id: 'my_data_source_id',
* records: [
* { id: 'id1', name: 'value1' },
* { id: 'id2', name: 'value2' }
* ]
* });
*/
add(props: DataSourceProps, opts: AddOptions = {}) {
const { all } = this;
props.id = props.id || this._createId();
return all.add(props, opts);
}

/**
* Get data source.
* @param {String} id Data source id.
* @returns {[DataSource]} Data source.
* @example
* const ds = dsm.get('my_data_source_id');
*/
get(id: string) {
return this.all.get(id);
}

/**
* Remove data source.
* @param {String|[DataSource]} id Id of the data source.
* @returns {[DataSource]} Removed data source.
* @example
* const removed = dsm.remove('DS_ID');
*/
remove(id: string | DataSource, opts?: RemoveOptions) {
return this.__remove(id, opts);
}
danstarns marked this conversation as resolved.
Show resolved Hide resolved
}
94 changes: 94 additions & 0 deletions src/data_sources/model/DataRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { keys } from 'underscore';
import { Model, SetOptions } from '../../common';
import { DataRecordProps, DataSourcesEvents } from '../types';
import DataRecords from './DataRecords';
import DataSource from './DataSource';
import EditorModel from '../../editor/model/Editor';
import { _StringKey } from 'backbone';

export default class DataRecord<T extends DataRecordProps = DataRecordProps> extends Model<T> {
constructor(props: T, opts = {}) {
super(props, opts);
this.on('change', this.handleChange);
}

get cl() {
return this.collection as unknown as DataRecords;
}

get dataSource(): DataSource {
return this.cl.dataSource;
}

get em(): EditorModel {
return this.dataSource.em;
}

get index(): number {
return this.cl.indexOf(this);
}

handleChange() {
const changed = this.changedAttributes();
keys(changed).forEach(prop => this.triggerChange(prop));
}

/**
* Get path of the record
* @param {String} prop Property name to include
* @returns {String}
* @example
* const pathRecord = record.getPath();
* // eg. 'SOURCE_ID.RECORD_ID'
* const pathRecord2 = record.getPath('myProp');
* // eg. 'SOURCE_ID.RECORD_ID.myProp'
*/
getPath(prop?: string, opts: { useIndex?: boolean } = {}) {
const { dataSource, id, index } = this;
const dsId = dataSource.id;
const suffix = prop ? `.${prop}` : '';
return `${dsId}.${opts.useIndex ? index : id}${suffix}`;
}

getPaths(prop?: string) {
return [this.getPath(prop), this.getPath(prop, { useIndex: true })];
}

triggerChange(prop?: string) {
const { dataSource, em } = this;
const data = { dataSource, dataRecord: this };
const paths = this.getPaths(prop);
paths.forEach(path => em.trigger(`${DataSourcesEvents.path}:${path}`, { ...data, path }));
}

set<A extends _StringKey<T>>(
attributeName: Partial<T> | A,
value?: SetOptions | T[A] | undefined,
options?: SetOptions | undefined
): this;
set(attributeName: unknown, value?: unknown, options?: SetOptions): DataRecord {
const onRecordSet = this.dataSource?.transformers?.onRecordSet;

if (options?.avoidTransformers) {
// @ts-ignore
super.set(attributeName, value, options);
return this;
}

if (onRecordSet) {
const newValue = onRecordSet({
id: this.id,
key: attributeName as string,
value,
});

// @ts-ignore
super.set(attributeName, newValue, options);
return this;
} else {
// @ts-ignore
super.set(attributeName, value, options);
return this;
}
}
danstarns marked this conversation as resolved.
Show resolved Hide resolved
}
36 changes: 36 additions & 0 deletions src/data_sources/model/DataRecords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Model } from 'backbone';
import { AddOptions, Collection } from '../../common';
import { DataRecordProps } from '../types';
import DataRecord from './DataRecord';
import DataSource from './DataSource';

type AddRecordOptions = AddOptions & { avoidTransformers?: boolean };

export default class DataRecords extends Collection<DataRecord> {
dataSource: DataSource;

constructor(models: DataRecord[] | DataRecordProps[], options: { dataSource: DataSource }) {
super(models, options);
this.dataSource = options.dataSource;
}

add(model: {} | DataRecord<DataRecordProps>, options?: AddRecordOptions): DataRecord<DataRecordProps>;
add(models: ({} | DataRecord<DataRecordProps>)[], options?: AddRecordOptions): DataRecord<DataRecordProps>[];
add(models: unknown, options?: AddRecordOptions): DataRecord<DataRecordProps> | DataRecord<DataRecordProps>[] {
const onRecordAdd = this.dataSource?.transformers?.onRecordAdd;

if (options?.avoidTransformers) {
return super.add(models as DataRecord<DataRecordProps>, options);
}

if (onRecordAdd) {
const m = (Array.isArray(models) ? models : [models]).map(model => onRecordAdd({ record: model }));

return super.add(m, options);
} else {
return super.add(models as DataRecord<DataRecordProps>, options);
}
}
}

DataRecords.prototype.model = DataRecord;
70 changes: 70 additions & 0 deletions src/data_sources/model/DataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { AddOptions, CombinedModelConstructorOptions, Model, RemoveOptions } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { DataRecordProps, DataSourceProps, DataSourceTransformers } from '../types';
import DataRecord from './DataRecord';
import DataRecords from './DataRecords';
import DataSources from './DataSources';

interface DataSourceOptions extends CombinedModelConstructorOptions<{ em: EditorModel }, DataSource> {}

export default class DataSource extends Model<DataSourceProps> {
transformers: DataSourceTransformers;

defaults() {
return {
records: [],
transformers: {},
};
}

constructor(props: DataSourceProps, opts: DataSourceOptions) {
super(props, opts);
const { records, transformers } = props;
this.transformers = transformers || {};

if (!(records instanceof DataRecords)) {
this.set({ records: new DataRecords(records!, { dataSource: this }) });
}

this.listenTo(this.records, 'add', this.onAdd);
}

get records() {
return this.attributes.records as DataRecords;
}

get em() {
return (this.collection as unknown as DataSources).em;
}

onAdd(dr: DataRecord) {
dr.triggerChange();
}

addRecord(record: DataRecordProps, opts?: AddOptions) {
const onRecordAdd = this.transformers.onRecordAdd;
if (onRecordAdd) {
record = onRecordAdd({ record });
}

return this.records.add(record, opts);
}

getRecord(id: string | number): DataRecord | undefined {
const onRecordRead = this.transformers.onRecordRead;
const record = this.records.get(id);
if (record && onRecordRead) {
return onRecordRead({ record });
}

return record;
}

getRecords() {
return [...this.records.models];
}

removeRecord(id: string | number, opts?: RemoveOptions): DataRecord | undefined {
return this.records.remove(id, opts);
}
danstarns marked this conversation as resolved.
Show resolved Hide resolved
}
18 changes: 18 additions & 0 deletions src/data_sources/model/DataSources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Collection } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { DataSourceProps } from '../types';
import DataSource from './DataSource';

export default class DataSources extends Collection<DataSource> {
em: EditorModel;

constructor(models: DataSource[] | DataSourceProps[], em: EditorModel) {
super(models, em);
this.em = em;

// @ts-ignore We need to inject `em` for pages created on reset from the Storage load
this.model = (props: DataSourceProps, opts = {}) => {
return new DataSource(props, { ...opts, em });
};
}
}
42 changes: 42 additions & 0 deletions src/data_sources/model/StyleDataVariable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Model } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { get, stringToPath } from '../../utils/mixins';

export default class StyleDataVariable extends Model {
em?: EditorModel;

defaults() {
return {
type: 'data-variable-css',
value: '',
path: '',
};
}

initialize(attrs: any, options: any) {
super.initialize(attrs, options);
this.em = options.em;
this.listenToDataSource();

return this;
}

listenToDataSource() {
const { path } = this.attributes;
const resolvedPath = stringToPath(path).join('.');

if (this.em) {
this.listenTo(this.em.DataSources, `change:${resolvedPath}`, this.onDataSourceChange);
}
}

onDataSourceChange() {
const { path } = this.attributes;
const [dsId, drId, key] = stringToPath(path);
const ds = this?.em?.DataSources.get(dsId);
const dr = ds && ds.getRecord(drId);
const newValue = dr?.get(key);

this.set({ value: newValue });
}
}
Loading
Loading