@journeyapps-labs/reactor-mod-data-browser 3.3.0 → 3.5.0
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.
- package/CHANGELOG.md +27 -0
- package/dist/@types/actions/schema-model/ViewHasManyAction.d.ts +12 -0
- package/dist/@types/core/AbstractConnection.d.ts +1 -0
- package/dist/@types/core/SchemaModelDefinition.d.ts +32 -5
- package/dist/@types/core/query/StandardModelFields.d.ts +4 -0
- package/dist/@types/core/query/query-simple/SimpleQueryFilterState.d.ts +4 -6
- package/dist/@types/core/query/widgets/BelongsToDisplayWidget.d.ts +1 -0
- package/dist/@types/core/query/widgets/ColumnDisplayWidget.d.ts +1 -0
- package/dist/@types/core/query/widgets/IDCellDisplayWidget.d.ts +5 -0
- package/dist/@types/core/query/widgets/PeekRelationshipButton.d.ts +1 -0
- package/dist/@types/core/query/widgets/SmartBelongsToDisplayWidget.d.ts +2 -0
- package/dist/@types/core/query/widgets/SmartColumnWidget.d.ts +7 -2
- package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
- package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +2 -1
- package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
- package/dist/@types/forms/types/belongs-to-filter.d.ts +10 -0
- package/dist/@types/forms/types/shared/type-handler.d.ts +1 -0
- package/dist/@types/index.d.ts +1 -0
- package/dist/@types/preferences/QueryControlPreferences.d.ts +14 -2
- package/dist/@types/preferences/SchemaOrderingPreferences.d.ts +22 -0
- package/dist/DataBrowserModule.js +4 -0
- package/dist/DataBrowserModule.js.map +1 -1
- package/dist/actions/schema-model/ViewHasManyAction.js +112 -0
- package/dist/actions/schema-model/ViewHasManyAction.js.map +1 -0
- package/dist/core/AbstractConnection.js +11 -3
- package/dist/core/AbstractConnection.js.map +1 -1
- package/dist/core/SchemaModelDefinition.js +121 -7
- package/dist/core/SchemaModelDefinition.js.map +1 -1
- package/dist/core/query/StandardModelFields.js +3 -0
- package/dist/core/query/StandardModelFields.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQueryColumns.js +74 -42
- package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQueryFilterState.js +35 -7
- package/dist/core/query/query-simple/SimpleQueryFilterState.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQuerySortState.js +0 -1
- package/dist/core/query/query-simple/SimpleQuerySortState.js.map +1 -1
- package/dist/core/query/widgets/BelongsToDisplayWidget.js +1 -1
- package/dist/core/query/widgets/BelongsToDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/ColumnDisplayWidget.js +13 -2
- package/dist/core/query/widgets/ColumnDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/IDCellDisplayWidget.js +38 -0
- package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -0
- package/dist/core/query/widgets/PeekRelationshipButton.js +23 -16
- package/dist/core/query/widgets/PeekRelationshipButton.js.map +1 -1
- package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js +1 -1
- package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/SmartColumnWidget.js +3 -13
- package/dist/core/query/widgets/SmartColumnWidget.js.map +1 -1
- package/dist/core/query/widgets/SmartFilterWidget.js +10 -7
- package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelObjectEntityDefinition.js +15 -14
- package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelTreePresenterComponent.js +23 -0
- package/dist/entities/SchemaModelTreePresenterComponent.js.map +1 -0
- package/dist/forms/SchemaModelForm.js +31 -29
- package/dist/forms/SchemaModelForm.js.map +1 -1
- package/dist/forms/types/attachment-handler.js +1 -0
- package/dist/forms/types/attachment-handler.js.map +1 -1
- package/dist/forms/types/belongs-to-filter.js +57 -0
- package/dist/forms/types/belongs-to-filter.js.map +1 -0
- package/dist/forms/types/boolean-handler.js +34 -1
- package/dist/forms/types/boolean-handler.js.map +1 -1
- package/dist/forms/types/date-handler.js +1 -0
- package/dist/forms/types/date-handler.js.map +1 -1
- package/dist/forms/types/image-handler.js +1 -0
- package/dist/forms/types/image-handler.js.map +1 -1
- package/dist/forms/types/location-handler.js +1 -0
- package/dist/forms/types/location-handler.js.map +1 -1
- package/dist/forms/types/multiple-choice-handler.js +1 -0
- package/dist/forms/types/multiple-choice-handler.js.map +1 -1
- package/dist/forms/types/multiple-choice-integer-handler.js +1 -0
- package/dist/forms/types/multiple-choice-integer-handler.js.map +1 -1
- package/dist/forms/types/number-handler.js +3 -2
- package/dist/forms/types/number-handler.js.map +1 -1
- package/dist/forms/types/single-choice-handler.js +1 -0
- package/dist/forms/types/single-choice-handler.js.map +1 -1
- package/dist/forms/types/single-choice-integer-handler.js +1 -0
- package/dist/forms/types/single-choice-integer-handler.js.map +1 -1
- package/dist/forms/types/text-handler.js +1 -0
- package/dist/forms/types/text-handler.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/panels/query/QueryPanelWidget.js +14 -9
- package/dist/panels/query/QueryPanelWidget.js.map +1 -1
- package/dist/panels/query/table-controls/FilterControlsWidget.js +1 -0
- package/dist/panels/query/table-controls/FilterControlsWidget.js.map +1 -1
- package/dist/preferences/QueryControlPreferences.js +45 -1
- package/dist/preferences/QueryControlPreferences.js.map +1 -1
- package/dist/preferences/SchemaOrderingPreferences.js +76 -0
- package/dist/preferences/SchemaOrderingPreferences.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist-module/bundle.js +51 -35
- package/dist-module/bundle.js.map +1 -1
- package/package.json +7 -6
- package/src/DataBrowserModule.ts +4 -0
- package/src/actions/schema-model/ViewHasManyAction.ts +114 -0
- package/src/core/AbstractConnection.ts +12 -3
- package/src/core/SchemaModelDefinition.ts +165 -9
- package/src/core/query/StandardModelFields.ts +8 -0
- package/src/core/query/query-simple/SimpleQueryColumns.tsx +103 -58
- package/src/core/query/query-simple/SimpleQueryFilterState.ts +42 -9
- package/src/core/query/query-simple/SimpleQuerySortState.ts +0 -1
- package/src/core/query/widgets/BelongsToDisplayWidget.tsx +2 -1
- package/src/core/query/widgets/ColumnDisplayWidget.tsx +17 -4
- package/src/core/query/widgets/IDCellDisplayWidget.tsx +59 -0
- package/src/core/query/widgets/PeekRelationshipButton.tsx +23 -16
- package/src/core/query/widgets/SmartBelongsToDisplayWidget.tsx +3 -0
- package/src/core/query/widgets/SmartColumnWidget.tsx +23 -20
- package/src/core/query/widgets/SmartFilterWidget.tsx +14 -5
- package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
- package/src/entities/SchemaModelObjectEntityDefinition.ts +17 -15
- package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
- package/src/forms/SchemaModelForm.tsx +46 -41
- package/src/forms/types/attachment-handler.tsx +1 -0
- package/src/forms/types/belongs-to-filter.tsx +84 -0
- package/src/forms/types/boolean-handler.tsx +46 -2
- package/src/forms/types/date-handler.tsx +1 -0
- package/src/forms/types/image-handler.tsx +1 -0
- package/src/forms/types/location-handler.tsx +1 -0
- package/src/forms/types/multiple-choice-handler.tsx +1 -0
- package/src/forms/types/multiple-choice-integer-handler.tsx +1 -0
- package/src/forms/types/number-handler.tsx +3 -2
- package/src/forms/types/shared/type-handler.ts +1 -0
- package/src/forms/types/single-choice-handler.tsx +1 -0
- package/src/forms/types/single-choice-integer-handler.tsx +1 -0
- package/src/forms/types/text-handler.tsx +1 -0
- package/src/index.ts +1 -0
- package/src/panels/query/QueryPanelWidget.tsx +24 -22
- package/src/panels/query/table-controls/FilterControlsWidget.tsx +1 -0
- package/src/preferences/QueryControlPreferences.ts +51 -2
- package/src/preferences/SchemaOrderingPreferences.ts +82 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@journeyapps-labs/reactor-mod-data-browser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"typings": "./dist/@types/index",
|
|
6
6
|
"publishConfig": {
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@emotion/styled": "^11.14.1",
|
|
18
|
-
"@fortawesome/react-fontawesome": "^3.
|
|
18
|
+
"@fortawesome/react-fontawesome": "^3.3.0",
|
|
19
19
|
"@journeyapps-labs/client-backend-v4": "1.0.0",
|
|
20
20
|
"@journeyapps-labs/common-ioc": "^1.0.1",
|
|
21
21
|
"@journeyapps-labs/common-sdk": "^1.0.3",
|
|
22
22
|
"@journeyapps-labs/common-utils": "^1.0.1",
|
|
23
|
-
"@journeyapps-labs/lib-reactor-data-layer": "1.0.
|
|
24
|
-
"@journeyapps-labs/reactor-mod": "5.
|
|
25
|
-
"@journeyapps-labs/reactor-mod-editor": "2.2.
|
|
23
|
+
"@journeyapps-labs/lib-reactor-data-layer": "1.0.11",
|
|
24
|
+
"@journeyapps-labs/reactor-mod": "5.4.0",
|
|
25
|
+
"@journeyapps-labs/reactor-mod-editor": "2.2.2",
|
|
26
26
|
"@journeyapps/db": "^8.1.1",
|
|
27
27
|
"@journeyapps/parser-schema": "^8.2.5",
|
|
28
28
|
"@projectstorm/react-workspaces-core": "4.2.3",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"uuid": "^13.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@journeyapps-labs/lib-reactor-builder": "3.0.
|
|
37
|
+
"@journeyapps-labs/lib-reactor-builder": "3.0.2",
|
|
38
38
|
"@types/async": "^3.2.25",
|
|
39
39
|
"@types/lodash": "^4.17.24",
|
|
40
40
|
"@types/react": "^19.2.14",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build:module": "reactor build .",
|
|
45
|
+
"clean": "rm -rf dist-module",
|
|
45
46
|
"watch:module": "pnpm build:module --watch"
|
|
46
47
|
}
|
|
47
48
|
}
|
package/src/DataBrowserModule.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { SchemaModelObjectEntityDefinition } from './entities/SchemaModelObjectE
|
|
|
17
17
|
import { EditSchemaModelAction } from './actions/schema-model/EditSchemaModelAction';
|
|
18
18
|
import { TypeEngine } from './forms/TypeEngine';
|
|
19
19
|
import { ViewSchemaModelAsJsonAction } from './actions/schema-model/ViewSchemaModelAsJsonAction';
|
|
20
|
+
import { ViewHasManyAction } from './actions/schema-model/ViewHasManyAction';
|
|
20
21
|
import { ModelJsonPanelFactory } from './panels/model-json/ModelJsonPanelFactory';
|
|
21
22
|
import { SchemaModelIndexDefinition } from './entities/SchemaModelIndexDefinition';
|
|
22
23
|
import { SavedQueryStore } from './stores/SavedQueryStore';
|
|
@@ -24,6 +25,7 @@ import { SavedQueryEntityDefinition } from './entities/SavedQueryEntityDefinitio
|
|
|
24
25
|
import { OpenSavedQueryAction } from './actions/saved-queries/OpenSavedQueryAction';
|
|
25
26
|
import { RemoveSavedQueryAction } from './actions/saved-queries/RemoveSavedQueryAction';
|
|
26
27
|
import { registerQueryControlPreferences } from './preferences/QueryControlPreferences';
|
|
28
|
+
import { registerSchemaOrderingPreferences } from './preferences/SchemaOrderingPreferences';
|
|
27
29
|
|
|
28
30
|
export class DataBrowserModule extends AbstractReactorModule {
|
|
29
31
|
constructor() {
|
|
@@ -49,12 +51,14 @@ export class DataBrowserModule extends AbstractReactorModule {
|
|
|
49
51
|
actionStore.registerAction(new CreateModelAction());
|
|
50
52
|
actionStore.registerAction(new EditSchemaModelAction());
|
|
51
53
|
actionStore.registerAction(new ViewSchemaModelAsJsonAction());
|
|
54
|
+
actionStore.registerAction(new ViewHasManyAction());
|
|
52
55
|
actionStore.registerAction(new OpenSavedQueryAction());
|
|
53
56
|
actionStore.registerAction(new RemoveSavedQueryAction());
|
|
54
57
|
|
|
55
58
|
system.addStore(ConnectionStore, connectionStore);
|
|
56
59
|
system.addStore(SavedQueryStore, new SavedQueryStore());
|
|
57
60
|
registerQueryControlPreferences(ioc.get(PrefsStore));
|
|
61
|
+
registerSchemaOrderingPreferences(ioc.get(PrefsStore));
|
|
58
62
|
|
|
59
63
|
system.registerDefinition(new ConnectionEntityDefinition());
|
|
60
64
|
system.registerDefinition(new ConnectionFactoryEntityDefinition());
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActionStore,
|
|
3
|
+
ComboBoxItem,
|
|
4
|
+
ComboBoxStore2,
|
|
5
|
+
EntityAction,
|
|
6
|
+
EntityActionEvent,
|
|
7
|
+
NotificationStore,
|
|
8
|
+
NotificationType,
|
|
9
|
+
SimpleComboBoxDirective,
|
|
10
|
+
WorkspaceStore,
|
|
11
|
+
inject,
|
|
12
|
+
ioc
|
|
13
|
+
} from '@journeyapps-labs/reactor-mod';
|
|
14
|
+
import { Relationship } from '@journeyapps/parser-schema';
|
|
15
|
+
import { DataBrowserEntities } from '../../entities';
|
|
16
|
+
import { SchemaModelObject } from '../../core/SchemaModelObject';
|
|
17
|
+
import { QueryPanelModel } from '../../panels/query/QueryPanelFactory';
|
|
18
|
+
import { SimpleQuery } from '../../core/query/query-simple/SimpleQuery';
|
|
19
|
+
import { Condition, SimpleFilter, Statement } from '../../core/query/filters';
|
|
20
|
+
|
|
21
|
+
export class ViewHasManyAction extends EntityAction<SchemaModelObject> {
|
|
22
|
+
static ID = 'VIEW_HAS_MANY';
|
|
23
|
+
|
|
24
|
+
@inject(ComboBoxStore2)
|
|
25
|
+
accessor comboStore: ComboBoxStore2;
|
|
26
|
+
|
|
27
|
+
@inject(WorkspaceStore)
|
|
28
|
+
accessor workspaceStore: WorkspaceStore;
|
|
29
|
+
|
|
30
|
+
@inject(NotificationStore)
|
|
31
|
+
accessor notifications: NotificationStore;
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
super({
|
|
35
|
+
id: ViewHasManyAction.ID,
|
|
36
|
+
name: 'View has many',
|
|
37
|
+
icon: 'list',
|
|
38
|
+
target: DataBrowserEntities.SCHEMA_MODEL_OBJECT
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async fireEvent(event: EntityActionEvent<SchemaModelObject>): Promise<any> {
|
|
43
|
+
const relationships = Object.values(event.targetEntity.definition.definition.hasMany || {});
|
|
44
|
+
if (relationships.length === 0) {
|
|
45
|
+
this.notifications.showNotification({
|
|
46
|
+
title: 'No relationships',
|
|
47
|
+
description: 'This record has no has-many relationships to view.',
|
|
48
|
+
type: NotificationType.ERROR
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const directive = await this.comboStore.show(
|
|
54
|
+
new SimpleComboBoxDirective({
|
|
55
|
+
title: 'View has many',
|
|
56
|
+
subtitle: event.targetEntity.data.display || event.targetEntity.id,
|
|
57
|
+
event: event.position,
|
|
58
|
+
items: relationships.map((relationship) => {
|
|
59
|
+
return {
|
|
60
|
+
key: relationship.foreignName || relationship.name,
|
|
61
|
+
title: relationship.foreignName || relationship.name,
|
|
62
|
+
subtitle: relationship.objectType.label || relationship.objectType.name,
|
|
63
|
+
action: async () => {}
|
|
64
|
+
} as ComboBoxItem;
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const selected = directive.getSelectedItem();
|
|
70
|
+
if (!selected?.key) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const relationship = relationships.find((entry) => (entry.foreignName || entry.name) === selected.key);
|
|
75
|
+
if (!relationship) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await this.openRelationshipQuery(event.targetEntity, relationship);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private async openRelationshipQuery(parent: SchemaModelObject, relationship: Relationship) {
|
|
83
|
+
const definition = await parent.definition.connection.waitForSchemaModelDefinitionByName(
|
|
84
|
+
relationship.objectType.name
|
|
85
|
+
);
|
|
86
|
+
const variable = definition.getBelongsToIdVariableForRelationship(relationship.name);
|
|
87
|
+
if (!variable) {
|
|
88
|
+
this.notifications.showNotification({
|
|
89
|
+
title: 'Cannot open relationship',
|
|
90
|
+
description: `No belongs-to field found for ${relationship.name}.`,
|
|
91
|
+
type: NotificationType.ERROR
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
variable.label = relationship.name;
|
|
97
|
+
|
|
98
|
+
const query = new SimpleQuery({
|
|
99
|
+
definition,
|
|
100
|
+
limit: 30
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
query.filterState.setFilter(
|
|
104
|
+
variable.name,
|
|
105
|
+
new SimpleFilter(variable, [new Statement(Condition.EQUALS, parent.id)])
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
this.workspaceStore.addModel(new QueryPanelModel(query));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static get() {
|
|
112
|
+
return ioc.get(ActionStore).getActionByID<ViewHasManyAction>(ViewHasManyAction.ID);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Database, ObjectType } from '@journeyapps/db';
|
|
2
2
|
import { Schema } from '@journeyapps/parser-schema';
|
|
3
3
|
import { AbstractConnectionFactory } from './AbstractConnectionFactory';
|
|
4
|
-
import * as _ from 'lodash';
|
|
5
4
|
import { SchemaModelDefinition } from './SchemaModelDefinition';
|
|
6
5
|
import { v4 } from 'uuid';
|
|
7
6
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
@@ -12,6 +11,8 @@ import { EntityDescription } from '@journeyapps-labs/reactor-mod';
|
|
|
12
11
|
import { V4BackendClient, V4Index, V4Indexes } from '@journeyapps-labs/client-backend-v4';
|
|
13
12
|
import { SchemaModelObject } from './SchemaModelObject';
|
|
14
13
|
import { getDefaultConnectionColor } from './connection-colors';
|
|
14
|
+
import { SchemaModelOrderValue, SchemaModelOrderingPreference } from '../preferences/SchemaOrderingPreferences';
|
|
15
|
+
import * as _ from 'lodash';
|
|
15
16
|
|
|
16
17
|
export interface AbstractConnectionSerialized {
|
|
17
18
|
factory: string;
|
|
@@ -118,10 +119,18 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
|
|
|
118
119
|
return connection.schema;
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
protected getOrderedSchemaObjects(schema: Schema): ObjectType[] {
|
|
123
|
+
const objects = Object.keys(schema.objects).map((key) => schema.objects[key]);
|
|
124
|
+
if (SchemaModelOrderingPreference.getValue() === SchemaModelOrderValue.ALPHABETICAL) {
|
|
125
|
+
return _.sortBy(objects, (object) => (object.label || object.name || '').toLowerCase());
|
|
126
|
+
}
|
|
127
|
+
return objects;
|
|
128
|
+
}
|
|
129
|
+
|
|
121
130
|
async reload() {
|
|
122
131
|
await this.schema_models_collection.load(async () => {
|
|
123
132
|
const schema = await this.getSchema();
|
|
124
|
-
return
|
|
133
|
+
return this.getOrderedSchemaObjects(schema);
|
|
125
134
|
});
|
|
126
135
|
}
|
|
127
136
|
|
|
@@ -156,7 +165,7 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
|
|
|
156
165
|
|
|
157
166
|
protected async getSchemaModelDefinitions() {
|
|
158
167
|
const schema = await this.getSchema();
|
|
159
|
-
return
|
|
168
|
+
return this.getOrderedSchemaObjects(schema).map((o) => {
|
|
160
169
|
return new SchemaModelDefinition({
|
|
161
170
|
definition: o,
|
|
162
171
|
connection: this
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AbstractConnection } from './AbstractConnection';
|
|
2
2
|
import { ObjectType } from '@journeyapps/parser-schema';
|
|
3
|
-
import { Collection, JourneyAPIAdapter, Query } from '@journeyapps/db';
|
|
3
|
+
import { Collection, JourneyAPIAdapter, Query, Variable } from '@journeyapps/db';
|
|
4
|
+
import * as _ from 'lodash';
|
|
4
5
|
import { SchemaModelObject } from './SchemaModelObject';
|
|
5
6
|
import { LifecycleModel } from '@journeyapps-labs/lib-reactor-data-layer';
|
|
6
7
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
@@ -10,6 +11,8 @@ import { V4Index } from '@journeyapps-labs/client-backend-v4';
|
|
|
10
11
|
import { action, observable } from 'mobx';
|
|
11
12
|
import { IndexModel } from './IndexModel';
|
|
12
13
|
import { TypeEngine } from '../forms/TypeEngine';
|
|
14
|
+
import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields, idVariable } from './query/StandardModelFields';
|
|
15
|
+
import { SchemaFieldOrderValue, SchemaFieldOrderingPreference } from '../preferences/SchemaOrderingPreferences';
|
|
13
16
|
|
|
14
17
|
export interface SchemaModelDefinitionListener {
|
|
15
18
|
resolved: (event: { object: SchemaModelObject }) => any;
|
|
@@ -20,6 +23,33 @@ export interface SchemaModelDefinitionOptions {
|
|
|
20
23
|
connection: AbstractConnection;
|
|
21
24
|
definition: ObjectType;
|
|
22
25
|
}
|
|
26
|
+
|
|
27
|
+
export interface FilterableField {
|
|
28
|
+
key: string;
|
|
29
|
+
label: string;
|
|
30
|
+
group: 'Fields' | 'Belongs to';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export enum OrderedSchemaFieldType {
|
|
34
|
+
FIELD = 'FIELD',
|
|
35
|
+
BELONGS_TO = 'BELONGS_TO'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type OrderedSchemaFieldOrRelationship =
|
|
39
|
+
| {
|
|
40
|
+
type: OrderedSchemaFieldType.FIELD;
|
|
41
|
+
object: Variable;
|
|
42
|
+
key: string;
|
|
43
|
+
label: string;
|
|
44
|
+
}
|
|
45
|
+
| {
|
|
46
|
+
type: OrderedSchemaFieldType.BELONGS_TO;
|
|
47
|
+
object: ObjectType['belongsTo'][string];
|
|
48
|
+
key: string;
|
|
49
|
+
label: string;
|
|
50
|
+
variable: Variable;
|
|
51
|
+
};
|
|
52
|
+
|
|
23
53
|
export class SchemaModelDefinition
|
|
24
54
|
extends BaseObserver<SchemaModelDefinitionListener>
|
|
25
55
|
implements LifecycleModel<ObjectType>
|
|
@@ -171,18 +201,144 @@ export class SchemaModelDefinition
|
|
|
171
201
|
});
|
|
172
202
|
}
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.
|
|
177
|
-
|
|
178
|
-
|
|
204
|
+
getBelongsToIdVariableForRelationship(relationshipName: string): Variable | undefined {
|
|
205
|
+
const variable = _.find(_.values(this.definition.belongsToIdVars), (entry) => {
|
|
206
|
+
return entry.relationship === relationshipName;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (!variable) {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const relationship = this.definition.belongsTo[relationshipName];
|
|
214
|
+
if (relationship) {
|
|
215
|
+
variable.label = relationship.name;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return variable;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getBelongsToRelationshipForField(field: string):
|
|
222
|
+
| {
|
|
223
|
+
variable: Variable;
|
|
224
|
+
relationship: ObjectType['belongsTo'][string];
|
|
225
|
+
}
|
|
226
|
+
| undefined {
|
|
227
|
+
const variable = _.find(_.values(this.definition.belongsToIdVars), (entry) => {
|
|
228
|
+
return entry.name === field;
|
|
229
|
+
});
|
|
230
|
+
if (!variable?.relationship) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const relationship = this.definition.belongsTo[variable.relationship];
|
|
235
|
+
if (!relationship) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
variable.label = relationship.name;
|
|
240
|
+
return {
|
|
241
|
+
variable,
|
|
242
|
+
relationship
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private getSchemaOrderedFields(): Variable[] {
|
|
247
|
+
return Object.keys(this.definition.attributes).map((key) => this.definition.attributes[key]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private getSchemaOrderedBelongsToFields(): OrderedSchemaFieldOrRelationship[] {
|
|
251
|
+
return Object.keys(this.definition.belongsTo)
|
|
252
|
+
.map((relationshipName) => {
|
|
253
|
+
const relationship = this.definition.belongsTo[relationshipName];
|
|
254
|
+
const variable = this.getBelongsToIdVariableForRelationship(relationshipName);
|
|
255
|
+
if (!relationship || !variable) {
|
|
179
256
|
return null;
|
|
180
257
|
}
|
|
181
258
|
return {
|
|
259
|
+
type: OrderedSchemaFieldType.BELONGS_TO,
|
|
260
|
+
object: relationship,
|
|
261
|
+
key: variable.name,
|
|
262
|
+
label: relationship.name || variable.label || variable.name,
|
|
263
|
+
variable
|
|
264
|
+
} as OrderedSchemaFieldOrRelationship;
|
|
265
|
+
})
|
|
266
|
+
.filter((value): value is OrderedSchemaFieldOrRelationship => !!value);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private getAlphabeticalOrderedFields(): OrderedSchemaFieldOrRelationship[] {
|
|
270
|
+
return _.sortBy(
|
|
271
|
+
this.getSchemaOrderedFields().map((attribute) => {
|
|
272
|
+
return {
|
|
273
|
+
type: OrderedSchemaFieldType.FIELD,
|
|
274
|
+
object: attribute,
|
|
182
275
|
key: attribute.name,
|
|
183
276
|
label: attribute.label || attribute.name
|
|
184
|
-
};
|
|
185
|
-
})
|
|
186
|
-
|
|
277
|
+
} as OrderedSchemaFieldOrRelationship;
|
|
278
|
+
}),
|
|
279
|
+
(item) => item.label.toLowerCase()
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
getOrderedFieldsAndRelationships(): OrderedSchemaFieldOrRelationship[] {
|
|
284
|
+
const orderedFields = this.getAlphabeticalOrderedFields();
|
|
285
|
+
const orderedBelongsTo = _.sortBy(this.getSchemaOrderedBelongsToFields(), (item) => item.label.toLowerCase());
|
|
286
|
+
|
|
287
|
+
switch (SchemaFieldOrderingPreference.getValue()) {
|
|
288
|
+
case SchemaFieldOrderValue.ALPHABETICAL:
|
|
289
|
+
return _.sortBy([...orderedFields, ...orderedBelongsTo], (item) => item.label.toLowerCase());
|
|
290
|
+
case SchemaFieldOrderValue.BELONGS_TO_FIRST:
|
|
291
|
+
return [...orderedBelongsTo, ...orderedFields];
|
|
292
|
+
case SchemaFieldOrderValue.BELONGS_TO_LAST:
|
|
293
|
+
return [...orderedFields, ...orderedBelongsTo];
|
|
294
|
+
case SchemaFieldOrderValue.AS_DEFINED_IN_SCHEMA:
|
|
295
|
+
default:
|
|
296
|
+
return [
|
|
297
|
+
...this.getSchemaOrderedFields().map((attribute) => {
|
|
298
|
+
return {
|
|
299
|
+
type: OrderedSchemaFieldType.FIELD,
|
|
300
|
+
object: attribute,
|
|
301
|
+
key: attribute.name,
|
|
302
|
+
label: attribute.label || attribute.name
|
|
303
|
+
} as OrderedSchemaFieldOrRelationship;
|
|
304
|
+
}),
|
|
305
|
+
...this.getSchemaOrderedBelongsToFields()
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
getFilterableFields(typeEngine: TypeEngine): FilterableField[] {
|
|
311
|
+
return [
|
|
312
|
+
...(typeEngine.getHandler(idVariable.type)?.setupFilter
|
|
313
|
+
? [
|
|
314
|
+
{
|
|
315
|
+
key: StandardModelFields.ID,
|
|
316
|
+
label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID],
|
|
317
|
+
group: 'Fields' as const
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
: []),
|
|
321
|
+
...this.getOrderedFieldsAndRelationships()
|
|
322
|
+
.map((entry) => {
|
|
323
|
+
if (entry.type === OrderedSchemaFieldType.BELONGS_TO) {
|
|
324
|
+
return {
|
|
325
|
+
key: entry.key,
|
|
326
|
+
label: entry.label,
|
|
327
|
+
group: 'Belongs to' as const
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const handler = typeEngine.getHandler(entry.object.type);
|
|
332
|
+
if (!handler?.setupFilter) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
key: entry.key,
|
|
337
|
+
label: entry.label,
|
|
338
|
+
group: 'Fields' as const
|
|
339
|
+
};
|
|
340
|
+
})
|
|
341
|
+
.filter((value) => !!value)
|
|
342
|
+
];
|
|
187
343
|
}
|
|
188
344
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TextType, Variable } from '@journeyapps/db';
|
|
2
|
+
|
|
1
3
|
export enum StandardModelFields {
|
|
2
4
|
ID = 'id',
|
|
3
5
|
UPDATED_AT = 'updated_at'
|
|
@@ -7,3 +9,9 @@ export const STANDARD_MODEL_FIELD_LABELS: Record<StandardModelFields, string> =
|
|
|
7
9
|
[StandardModelFields.ID]: 'ID',
|
|
8
10
|
[StandardModelFields.UPDATED_AT]: 'Updated at'
|
|
9
11
|
};
|
|
12
|
+
|
|
13
|
+
export const idVariable = new Variable(StandardModelFields.ID, new TextType()) as Variable & {
|
|
14
|
+
label?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
idVariable.label = STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { TableColumn } from '@journeyapps-labs/reactor-mod';
|
|
2
|
+
import { ioc, TableColumn } from '@journeyapps-labs/reactor-mod';
|
|
3
3
|
import * as _ from 'lodash';
|
|
4
4
|
import { PageRow } from '../Page';
|
|
5
5
|
import { CellDisplayWidget } from '../widgets/CellDisplayWidget';
|
|
@@ -7,12 +7,17 @@ import { SmartColumnWidget } from '../widgets/SmartColumnWidget';
|
|
|
7
7
|
import { SmartCellDisplayWidget } from '../widgets/SmartCellDisplayWidget';
|
|
8
8
|
import { SmartBelongsToDisplayWidget } from '../widgets/SmartBelongsToDisplayWidget';
|
|
9
9
|
import { ColumnDisplayWidget } from '../widgets/ColumnDisplayWidget';
|
|
10
|
+
import { IDCellDisplayWidget } from '../widgets/IDCellDisplayWidget';
|
|
10
11
|
import { SchemaModelDefinition } from '../../SchemaModelDefinition';
|
|
11
12
|
import { AbstractConnection } from '../../AbstractConnection';
|
|
12
13
|
import { SimpleQuerySort, SortDirection } from './SimpleQueryTypes';
|
|
13
14
|
import { SimpleQuerySortState } from './SimpleQuerySortState';
|
|
14
15
|
import { SimpleQueryFilterState } from './SimpleQueryFilterState';
|
|
15
|
-
import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields } from '../StandardModelFields';
|
|
16
|
+
import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields, idVariable } from '../StandardModelFields';
|
|
17
|
+
import { TypeEngine } from '../../../forms/TypeEngine';
|
|
18
|
+
import { setupBelongsToFilter } from '../../../forms/types/belongs-to-filter';
|
|
19
|
+
import { Condition, SimpleFilter, Statement } from '../filters';
|
|
20
|
+
import { OrderedSchemaFieldType } from '../../SchemaModelDefinition';
|
|
16
21
|
|
|
17
22
|
export interface BuildSimpleQueryColumnsOptions {
|
|
18
23
|
definition: SchemaModelDefinition;
|
|
@@ -34,20 +39,24 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
|
|
|
34
39
|
{
|
|
35
40
|
key: StandardModelFields.ID,
|
|
36
41
|
display: (
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
<SmartColumnWidget
|
|
43
|
+
variable={idVariable}
|
|
44
|
+
typeLabel={ioc.get(TypeEngine).getHandler(idVariable.type)?.getTypeLabel?.(idVariable.type)}
|
|
45
|
+
filter={options.filterState.getFilter(StandardModelFields.ID)}
|
|
46
|
+
filterChanged={async (filter) => {
|
|
47
|
+
if (!filter) {
|
|
48
|
+
options.filterState.getFilter(StandardModelFields.ID)?.delete();
|
|
43
49
|
return;
|
|
44
50
|
}
|
|
45
|
-
|
|
51
|
+
options.filterState.setFilter(StandardModelFields.ID, filter);
|
|
46
52
|
}}
|
|
47
53
|
/>
|
|
48
54
|
),
|
|
49
55
|
noWrap: true,
|
|
50
|
-
shrink: true
|
|
56
|
+
shrink: true,
|
|
57
|
+
accessor: (cell, row: PageRow) => {
|
|
58
|
+
return <IDCellDisplayWidget id={row.model.id} />;
|
|
59
|
+
}
|
|
51
60
|
},
|
|
52
61
|
{
|
|
53
62
|
key: StandardModelFields.UPDATED_AT,
|
|
@@ -73,54 +82,90 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
|
|
|
73
82
|
return <CellDisplayWidget name={StandardModelFields.UPDATED_AT} cell={row.model.updated_at} row={row} />;
|
|
74
83
|
}
|
|
75
84
|
},
|
|
76
|
-
...
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
85
|
+
...options.definition.getOrderedFieldsAndRelationships().flatMap((entry) => {
|
|
86
|
+
if (entry.type === OrderedSchemaFieldType.BELONGS_TO) {
|
|
87
|
+
const variable = entry.variable;
|
|
88
|
+
const relationship = entry.object;
|
|
89
|
+
return [
|
|
90
|
+
{
|
|
91
|
+
key: variable.name,
|
|
92
|
+
display: (
|
|
93
|
+
<SmartColumnWidget
|
|
94
|
+
variable={options.definition.definition.belongsToVars[variable.relationship]}
|
|
95
|
+
typeLabel={`Belongs To: ${relationship.foreignType.label}`}
|
|
96
|
+
filter={options.filterState.getFilter(variable.name)}
|
|
97
|
+
setupFilter={async ({ filter }) => {
|
|
98
|
+
return await setupBelongsToFilter({
|
|
99
|
+
definition: options.definition,
|
|
100
|
+
relationship,
|
|
101
|
+
variable,
|
|
102
|
+
filter
|
|
103
|
+
});
|
|
104
|
+
}}
|
|
105
|
+
filterChanged={async (filter) => {
|
|
106
|
+
if (!filter) {
|
|
107
|
+
options.filterState.getFilter(variable.name)?.delete();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
options.filterState.setFilter(variable.name, filter);
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
),
|
|
114
|
+
noWrap: true,
|
|
115
|
+
shrink: true,
|
|
116
|
+
accessor: (cell, row: PageRow) => {
|
|
117
|
+
return (
|
|
118
|
+
<SmartBelongsToDisplayWidget
|
|
119
|
+
variable_id={variable}
|
|
120
|
+
row={row}
|
|
121
|
+
connection={options.connection}
|
|
122
|
+
filterBelongsTo={async (object) => {
|
|
123
|
+
options.filterState.setFilter(
|
|
124
|
+
variable.name,
|
|
125
|
+
new SimpleFilter(variable, [new Statement(Condition.EQUALS, object.id)])
|
|
126
|
+
);
|
|
127
|
+
}}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
} as TableColumn
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const attribute = entry.object;
|
|
136
|
+
return [
|
|
137
|
+
{
|
|
138
|
+
key: attribute.name,
|
|
139
|
+
display: (
|
|
140
|
+
<SmartColumnWidget
|
|
141
|
+
variable={attribute}
|
|
142
|
+
typeLabel={ioc.get(TypeEngine).getHandler(attribute.type)?.getTypeLabel?.(attribute.type)}
|
|
143
|
+
filter={options.filterState.getFilter(attribute.name)}
|
|
144
|
+
sortDirection={options.sortState.getSort(attribute.name)?.direction}
|
|
145
|
+
onToggleSort={async () => {
|
|
146
|
+
const sort = options.sortState.getSort(attribute.name);
|
|
147
|
+
if (!sort) {
|
|
148
|
+
options.sortState.addSort(SimpleQuerySort.create(attribute.name));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
sort.toggle();
|
|
152
|
+
}}
|
|
153
|
+
filterChanged={async (filter) => {
|
|
154
|
+
if (!filter) {
|
|
155
|
+
options.filterState.getFilter(attribute.name)?.delete();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
options.filterState.setFilter(attribute.name, filter);
|
|
159
|
+
}}
|
|
160
|
+
/>
|
|
161
|
+
),
|
|
162
|
+
noWrap: true,
|
|
163
|
+
shrink: true,
|
|
164
|
+
accessor: (cell, row: PageRow) => {
|
|
165
|
+
return <SmartCellDisplayWidget name={attribute.name} row={row} />;
|
|
166
|
+
}
|
|
167
|
+
} as TableColumn
|
|
168
|
+
];
|
|
124
169
|
})
|
|
125
170
|
];
|
|
126
171
|
};
|