@journeyapps-labs/reactor-mod-data-browser 3.2.1 → 3.4.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 +23 -0
- package/dist/@types/actions/schema-model/ViewHasManyAction.d.ts +12 -0
- package/dist/@types/core/AbstractConnection.d.ts +12 -0
- package/dist/@types/core/SchemaModelDefinition.d.ts +12 -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 +8 -3
- package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
- package/dist/@types/core/types/ManualConnection.d.ts +1 -0
- package/dist/@types/entities/ConnectionEntityDefinition.d.ts +2 -1
- package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +2 -1
- 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/forms/types/shared/ui.d.ts +12 -0
- package/dist/@types/panels/query/QueryPanelFactory.d.ts +2 -2
- package/dist/DataBrowserModule.js +2 -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 +58 -5
- package/dist/core/AbstractConnection.js.map +1 -1
- package/dist/core/SchemaModelDefinition.js +70 -12
- 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 +37 -12
- 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 +33 -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 +7 -14
- 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/core/types/ManualConnection.js +3 -0
- package/dist/core/types/ManualConnection.js.map +1 -1
- package/dist/entities/ConnectionEntityDefinition.js +29 -6
- package/dist/entities/ConnectionEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelObjectEntityDefinition.js +15 -14
- package/dist/entities/SchemaModelObjectEntityDefinition.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/panels/model-json/ModelJsonPanelWidget.js +4 -3
- package/dist/panels/model-json/ModelJsonPanelWidget.js.map +1 -1
- package/dist/panels/query/QueryPanelFactory.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/stores/ConnectionStore.js +15 -3
- package/dist/stores/ConnectionStore.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist-module/bundle.js +51 -35
- package/dist-module/bundle.js.map +1 -1
- package/package.json +4 -4
- package/src/DataBrowserModule.ts +2 -0
- package/src/actions/schema-model/ViewHasManyAction.ts +114 -0
- package/src/core/AbstractConnection.ts +45 -2
- package/src/core/SchemaModelDefinition.ts +90 -14
- package/src/core/query/StandardModelFields.ts +8 -0
- package/src/core/query/query-simple/SimpleQueryColumns.tsx +50 -14
- 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 +46 -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 +27 -23
- package/src/core/query/widgets/SmartFilterWidget.tsx +14 -5
- package/src/core/types/ManualConnection.ts +4 -0
- package/src/entities/ConnectionEntityDefinition.tsx +32 -4
- package/src/entities/SchemaModelObjectEntityDefinition.ts +17 -15
- 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/panels/model-json/ModelJsonPanelWidget.tsx +8 -6
- package/src/panels/query/QueryPanelFactory.tsx +2 -2
- package/src/panels/query/table-controls/FilterControlsWidget.tsx +1 -0
- package/src/stores/ConnectionStore.ts +17 -6
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.4.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"typings": "./dist/@types/index",
|
|
6
6
|
"publishConfig": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"@journeyapps-labs/common-sdk": "^1.0.3",
|
|
22
22
|
"@journeyapps-labs/common-utils": "^1.0.1",
|
|
23
23
|
"@journeyapps-labs/lib-reactor-data-layer": "1.0.10",
|
|
24
|
-
"@journeyapps-labs/reactor-mod": "5.
|
|
25
|
-
"@journeyapps-labs/reactor-mod-editor": "2.1
|
|
24
|
+
"@journeyapps-labs/reactor-mod": "5.3.1",
|
|
25
|
+
"@journeyapps-labs/reactor-mod-editor": "2.2.1",
|
|
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": "
|
|
37
|
+
"@journeyapps-labs/lib-reactor-builder": "3.0.1",
|
|
38
38
|
"@types/async": "^3.2.25",
|
|
39
39
|
"@types/lodash": "^4.17.24",
|
|
40
40
|
"@types/react": "^19.2.14",
|
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';
|
|
@@ -49,6 +50,7 @@ export class DataBrowserModule extends AbstractReactorModule {
|
|
|
49
50
|
actionStore.registerAction(new CreateModelAction());
|
|
50
51
|
actionStore.registerAction(new EditSchemaModelAction());
|
|
51
52
|
actionStore.registerAction(new ViewSchemaModelAsJsonAction());
|
|
53
|
+
actionStore.registerAction(new ViewHasManyAction());
|
|
52
54
|
actionStore.registerAction(new OpenSavedQueryAction());
|
|
53
55
|
actionStore.registerAction(new RemoveSavedQueryAction());
|
|
54
56
|
|
|
@@ -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
|
+
}
|
|
@@ -7,7 +7,7 @@ import { v4 } from 'uuid';
|
|
|
7
7
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
8
8
|
import { Collection, LifecycleCollection } from '@journeyapps-labs/lib-reactor-data-layer';
|
|
9
9
|
import { when } from 'mobx';
|
|
10
|
-
import { observable } from 'mobx';
|
|
10
|
+
import { computed, observable } from 'mobx';
|
|
11
11
|
import { EntityDescription } from '@journeyapps-labs/reactor-mod';
|
|
12
12
|
import { V4BackendClient, V4Index, V4Indexes } from '@journeyapps-labs/client-backend-v4';
|
|
13
13
|
import { SchemaModelObject } from './SchemaModelObject';
|
|
@@ -24,18 +24,27 @@ export interface AbstractConnectionListener {
|
|
|
24
24
|
removed: () => any;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export enum ConnectionOnlineState {
|
|
28
|
+
OFFLINE = 'offline',
|
|
29
|
+
LOADING = 'loading',
|
|
30
|
+
ONLINE = 'online'
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
export abstract class AbstractConnection extends BaseObserver<AbstractConnectionListener> {
|
|
28
34
|
id: string;
|
|
29
35
|
@observable accessor color: string;
|
|
36
|
+
@observable accessor onlineState: ConnectionOnlineState;
|
|
30
37
|
|
|
31
38
|
schema_models_collection: Collection<ObjectType>;
|
|
32
39
|
schema_models: LifecycleCollection<ObjectType, SchemaModelDefinition>;
|
|
33
40
|
private fetch_indexes_promise: Promise<V4Indexes['models']>;
|
|
41
|
+
private initialize_online_promise: Promise<void>;
|
|
34
42
|
|
|
35
43
|
constructor(public factory: AbstractConnectionFactory) {
|
|
36
44
|
super();
|
|
37
45
|
this.id = v4();
|
|
38
46
|
this.color = getDefaultConnectionColor(this.id);
|
|
47
|
+
this.onlineState = ConnectionOnlineState.OFFLINE;
|
|
39
48
|
this.schema_models_collection = new Collection();
|
|
40
49
|
this.schema_models = new LifecycleCollection({
|
|
41
50
|
collection: this.schema_models_collection,
|
|
@@ -88,7 +97,16 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
|
|
|
88
97
|
return this.schema_models.items.find((i) => i.definition.name === name);
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
@computed get isOnline() {
|
|
101
|
+
return this.onlineState === ConnectionOnlineState.ONLINE;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@computed get isLoadingOnline() {
|
|
105
|
+
return this.onlineState === ConnectionOnlineState.LOADING;
|
|
106
|
+
}
|
|
107
|
+
|
|
91
108
|
async waitForSchemaModelDefinitionByName(name: string) {
|
|
109
|
+
await this.ensureOnline();
|
|
92
110
|
await when(() => !!this.getSchemaModelDefinitionByName(name));
|
|
93
111
|
return this.getSchemaModelDefinitionByName(name);
|
|
94
112
|
}
|
|
@@ -107,10 +125,35 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
|
|
|
107
125
|
});
|
|
108
126
|
}
|
|
109
127
|
|
|
110
|
-
async init() {
|
|
128
|
+
async init() {}
|
|
129
|
+
|
|
130
|
+
protected async connectOnline() {
|
|
111
131
|
await this.reload();
|
|
112
132
|
}
|
|
113
133
|
|
|
134
|
+
async ensureOnline() {
|
|
135
|
+
if (this.isOnline) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (!this.initialize_online_promise) {
|
|
139
|
+
this.initialize_online_promise = this.initializeOnline();
|
|
140
|
+
}
|
|
141
|
+
await this.initialize_online_promise;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private async initializeOnline() {
|
|
145
|
+
this.onlineState = ConnectionOnlineState.LOADING;
|
|
146
|
+
try {
|
|
147
|
+
await this.connectOnline();
|
|
148
|
+
this.onlineState = ConnectionOnlineState.ONLINE;
|
|
149
|
+
} finally {
|
|
150
|
+
if (this.onlineState === ConnectionOnlineState.LOADING) {
|
|
151
|
+
this.onlineState = ConnectionOnlineState.OFFLINE;
|
|
152
|
+
}
|
|
153
|
+
this.initialize_online_promise = null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
114
157
|
protected async getSchemaModelDefinitions() {
|
|
115
158
|
const schema = await this.getSchema();
|
|
116
159
|
return _.map(schema.objects, (o) => {
|
|
@@ -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,7 @@ 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';
|
|
13
15
|
|
|
14
16
|
export interface SchemaModelDefinitionListener {
|
|
15
17
|
resolved: (event: { object: SchemaModelObject }) => any;
|
|
@@ -20,6 +22,13 @@ export interface SchemaModelDefinitionOptions {
|
|
|
20
22
|
connection: AbstractConnection;
|
|
21
23
|
definition: ObjectType;
|
|
22
24
|
}
|
|
25
|
+
|
|
26
|
+
export interface FilterableField {
|
|
27
|
+
key: string;
|
|
28
|
+
label: string;
|
|
29
|
+
group: 'Fields' | 'Belongs to';
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
export class SchemaModelDefinition
|
|
24
33
|
extends BaseObserver<SchemaModelDefinitionListener>
|
|
25
34
|
implements LifecycleModel<ObjectType>
|
|
@@ -171,18 +180,85 @@ export class SchemaModelDefinition
|
|
|
171
180
|
});
|
|
172
181
|
}
|
|
173
182
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
getBelongsToIdVariableForRelationship(relationshipName: string): Variable | undefined {
|
|
184
|
+
const variable = _.find(_.values(this.definition.belongsToIdVars), (entry) => {
|
|
185
|
+
return entry.relationship === relationshipName;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (!variable) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const relationship = this.definition.belongsTo[relationshipName];
|
|
193
|
+
if (relationship) {
|
|
194
|
+
variable.label = relationship.name;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return variable;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getBelongsToRelationshipForField(field: string):
|
|
201
|
+
| {
|
|
202
|
+
variable: Variable;
|
|
203
|
+
relationship: ObjectType['belongsTo'][string];
|
|
204
|
+
}
|
|
205
|
+
| undefined {
|
|
206
|
+
const variable = _.find(_.values(this.definition.belongsToIdVars), (entry) => {
|
|
207
|
+
return entry.name === field;
|
|
208
|
+
});
|
|
209
|
+
if (!variable?.relationship) {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const relationship = this.definition.belongsTo[variable.relationship];
|
|
214
|
+
if (!relationship) {
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
variable.label = relationship.name;
|
|
219
|
+
return {
|
|
220
|
+
variable,
|
|
221
|
+
relationship
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getFilterableFields(typeEngine: TypeEngine): FilterableField[] {
|
|
226
|
+
return [
|
|
227
|
+
...(typeEngine.getHandler(idVariable.type)?.setupFilter
|
|
228
|
+
? [
|
|
229
|
+
{
|
|
230
|
+
key: StandardModelFields.ID,
|
|
231
|
+
label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID],
|
|
232
|
+
group: 'Fields' as const
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
: []),
|
|
236
|
+
...Object.values(this.definition.belongsToIdVars)
|
|
237
|
+
.map((variable) => {
|
|
238
|
+
if (!variable?.name || !variable.relationship) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const relationship = this.definition.belongsTo[variable.relationship];
|
|
242
|
+
return {
|
|
243
|
+
key: variable.name,
|
|
244
|
+
label: relationship?.name || variable.label || variable.name,
|
|
245
|
+
group: 'Belongs to' as const
|
|
246
|
+
};
|
|
247
|
+
})
|
|
248
|
+
.filter((value) => !!value),
|
|
249
|
+
...Object.values(this.definition.attributes)
|
|
250
|
+
.map((attribute) => {
|
|
251
|
+
const handler = typeEngine.getHandler(attribute.type);
|
|
252
|
+
if (!handler?.setupFilter) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
key: attribute.name,
|
|
257
|
+
label: attribute.label || attribute.name,
|
|
258
|
+
group: 'Fields' as const
|
|
259
|
+
};
|
|
260
|
+
})
|
|
261
|
+
.filter((value) => !!value)
|
|
262
|
+
];
|
|
187
263
|
}
|
|
188
264
|
}
|
|
@@ -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,16 @@ 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';
|
|
16
20
|
|
|
17
21
|
export interface BuildSimpleQueryColumnsOptions {
|
|
18
22
|
definition: SchemaModelDefinition;
|
|
@@ -27,27 +31,31 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
|
|
|
27
31
|
if (!direction) {
|
|
28
32
|
return label;
|
|
29
33
|
}
|
|
30
|
-
return `${label} ${direction === SortDirection.ASC ? '
|
|
34
|
+
return `${label} ${direction === SortDirection.ASC ? '↓' : '↑'}`;
|
|
31
35
|
};
|
|
32
36
|
|
|
33
37
|
return [
|
|
34
38
|
{
|
|
35
39
|
key: StandardModelFields.ID,
|
|
36
40
|
display: (
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
<SmartColumnWidget
|
|
42
|
+
variable={idVariable}
|
|
43
|
+
typeLabel={ioc.get(TypeEngine).getHandler(idVariable.type)?.getTypeLabel?.(idVariable.type)}
|
|
44
|
+
filter={options.filterState.getFilter(StandardModelFields.ID)}
|
|
45
|
+
filterChanged={async (filter) => {
|
|
46
|
+
if (!filter) {
|
|
47
|
+
options.filterState.getFilter(StandardModelFields.ID)?.delete();
|
|
43
48
|
return;
|
|
44
49
|
}
|
|
45
|
-
|
|
50
|
+
options.filterState.setFilter(StandardModelFields.ID, filter);
|
|
46
51
|
}}
|
|
47
52
|
/>
|
|
48
53
|
),
|
|
49
54
|
noWrap: true,
|
|
50
|
-
shrink: true
|
|
55
|
+
shrink: true,
|
|
56
|
+
accessor: (cell, row: PageRow) => {
|
|
57
|
+
return <IDCellDisplayWidget id={row.model.id} />;
|
|
58
|
+
}
|
|
51
59
|
},
|
|
52
60
|
{
|
|
53
61
|
key: StandardModelFields.UPDATED_AT,
|
|
@@ -79,14 +87,41 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
|
|
|
79
87
|
display: (
|
|
80
88
|
<SmartColumnWidget
|
|
81
89
|
variable={options.definition.definition.belongsToVars[a.relationship]}
|
|
82
|
-
|
|
83
|
-
|
|
90
|
+
typeLabel={`Belongs To: ${options.definition.definition.belongsTo[a.relationship].foreignType.label}`}
|
|
91
|
+
filter={options.filterState.getFilter(a.name)}
|
|
92
|
+
setupFilter={async ({ filter }) => {
|
|
93
|
+
return await setupBelongsToFilter({
|
|
94
|
+
definition: options.definition,
|
|
95
|
+
relationship: options.definition.definition.belongsTo[a.relationship],
|
|
96
|
+
variable: a,
|
|
97
|
+
filter
|
|
98
|
+
});
|
|
99
|
+
}}
|
|
100
|
+
filterChanged={async (filter) => {
|
|
101
|
+
if (!filter) {
|
|
102
|
+
options.filterState.getFilter(a.name)?.delete();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
options.filterState.setFilter(a.name, filter);
|
|
106
|
+
}}
|
|
84
107
|
/>
|
|
85
108
|
),
|
|
86
109
|
noWrap: true,
|
|
87
110
|
shrink: true,
|
|
88
111
|
accessor: (cell, row: PageRow) => {
|
|
89
|
-
return
|
|
112
|
+
return (
|
|
113
|
+
<SmartBelongsToDisplayWidget
|
|
114
|
+
variable_id={a}
|
|
115
|
+
row={row}
|
|
116
|
+
connection={options.connection}
|
|
117
|
+
filterBelongsTo={async (object) => {
|
|
118
|
+
options.filterState.setFilter(
|
|
119
|
+
a.name,
|
|
120
|
+
new SimpleFilter(a, [new Statement(Condition.EQUALS, object.id)])
|
|
121
|
+
);
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
90
125
|
}
|
|
91
126
|
} as TableColumn;
|
|
92
127
|
}),
|
|
@@ -96,6 +131,7 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
|
|
|
96
131
|
display: (
|
|
97
132
|
<SmartColumnWidget
|
|
98
133
|
variable={a}
|
|
134
|
+
typeLabel={ioc.get(TypeEngine).getHandler(a.type)?.getTypeLabel?.(a.type)}
|
|
99
135
|
filter={options.filterState.getFilter(a.name)}
|
|
100
136
|
sortDirection={options.sortState.getSort(a.name)?.direction}
|
|
101
137
|
onToggleSort={async () => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Variable } from '@journeyapps/db';
|
|
2
2
|
import * as _ from 'lodash';
|
|
3
3
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
4
|
-
import { SchemaModelDefinition } from '../../SchemaModelDefinition';
|
|
4
|
+
import { FilterableField, SchemaModelDefinition } from '../../SchemaModelDefinition';
|
|
5
5
|
import { SerializedSimpleFilter, SimpleFilter } from '../filters';
|
|
6
6
|
import { TypeEngine } from '../../../forms/TypeEngine';
|
|
7
|
+
import { setupBelongsToFilter } from '../../../forms/types/belongs-to-filter';
|
|
8
|
+
import { idVariable, StandardModelFields } from '../StandardModelFields';
|
|
7
9
|
|
|
8
10
|
export interface SimpleQueryFilterStateListener {
|
|
9
11
|
changed: () => any;
|
|
@@ -52,7 +54,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
52
54
|
return definitionChanged || hadFilters;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
getFilterableFields():
|
|
57
|
+
getFilterableFields(): FilterableField[] {
|
|
56
58
|
if (!this.definition?.definition) {
|
|
57
59
|
return [];
|
|
58
60
|
}
|
|
@@ -69,7 +71,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
getFilter(field: string): SimpleFilter | undefined {
|
|
72
|
-
const variable = this.
|
|
74
|
+
const variable = this.resolveField(field);
|
|
73
75
|
return variable ? this.simpleFilters.get(variable) : undefined;
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -87,9 +89,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
87
89
|
if (!SimpleFilter.canDeserialize(filter)) {
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
|
-
const variable =
|
|
91
|
-
return attribute.name === filter.variable;
|
|
92
|
-
});
|
|
92
|
+
const variable = this.resolveField(filter.variable);
|
|
93
93
|
if (!variable) {
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -98,7 +98,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
setFilter(field: string, filter: SimpleFilter) {
|
|
101
|
-
const variable = this.
|
|
101
|
+
const variable = this.resolveField(field);
|
|
102
102
|
if (!variable) {
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
@@ -106,7 +106,21 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
async setupFilterForField(field: string, position?: MouseEvent): Promise<boolean> {
|
|
109
|
-
const
|
|
109
|
+
const relationship = this.resolveBelongsToField(field);
|
|
110
|
+
if (relationship) {
|
|
111
|
+
const existing = this.simpleFilters.get(relationship.variable);
|
|
112
|
+
const nextFilter = await setupBelongsToFilter({
|
|
113
|
+
definition: this.definition,
|
|
114
|
+
relationship: relationship.relationship,
|
|
115
|
+
variable: relationship.variable,
|
|
116
|
+
filter: existing
|
|
117
|
+
});
|
|
118
|
+
if (!nextFilter) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return this.addFilter(relationship.variable, nextFilter);
|
|
122
|
+
}
|
|
123
|
+
const variable = this.resolveField(field);
|
|
110
124
|
if (!variable) {
|
|
111
125
|
return false;
|
|
112
126
|
}
|
|
@@ -149,12 +163,31 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
149
163
|
return true;
|
|
150
164
|
}
|
|
151
165
|
|
|
152
|
-
private
|
|
166
|
+
private resolveField(field: string): Variable | undefined {
|
|
153
167
|
if (!this.definition?.definition) {
|
|
154
168
|
return undefined;
|
|
155
169
|
}
|
|
170
|
+
if (field === StandardModelFields.ID) {
|
|
171
|
+
return idVariable;
|
|
172
|
+
}
|
|
173
|
+
const relationship = this.resolveBelongsToField(field);
|
|
174
|
+
if (relationship) {
|
|
175
|
+
return relationship.variable;
|
|
176
|
+
}
|
|
156
177
|
return _.find(_.values(this.definition.definition.attributes), (attribute) => {
|
|
157
178
|
return attribute.name === field;
|
|
158
179
|
});
|
|
159
180
|
}
|
|
181
|
+
|
|
182
|
+
private resolveBelongsToField(field: string):
|
|
183
|
+
| {
|
|
184
|
+
variable: Variable;
|
|
185
|
+
relationship: any;
|
|
186
|
+
}
|
|
187
|
+
| undefined {
|
|
188
|
+
if (!this.definition?.definition) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
return this.definition.getBelongsToRelationshipForField(field);
|
|
192
|
+
}
|
|
160
193
|
}
|
|
@@ -105,7 +105,6 @@ export class SimpleQuerySortState extends BaseObserver<SimpleQuerySortStateListe
|
|
|
105
105
|
};
|
|
106
106
|
});
|
|
107
107
|
return [
|
|
108
|
-
{ key: StandardModelFields.ID, label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID] },
|
|
109
108
|
{
|
|
110
109
|
key: StandardModelFields.UPDATED_AT,
|
|
111
110
|
label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.UPDATED_AT]
|
|
@@ -14,6 +14,7 @@ export interface BelongsToDisplayWidgetProps {
|
|
|
14
14
|
id: string;
|
|
15
15
|
connection: AbstractConnection;
|
|
16
16
|
open: (object: SchemaModelObject) => any;
|
|
17
|
+
filterBelongsTo?: (object: SchemaModelObject) => any;
|
|
17
18
|
className?: any;
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -62,7 +63,7 @@ export const BelongsToDisplayWidget: React.FC<BelongsToDisplayWidgetProps> = obs
|
|
|
62
63
|
<S.Container className={props.className}>
|
|
63
64
|
{object.data.display}
|
|
64
65
|
<S.Actions>
|
|
65
|
-
<PeekRelationshipButton object={object} open={props.open} />
|
|
66
|
+
<PeekRelationshipButton object={object} open={props.open} filterBelongsTo={props.filterBelongsTo} />
|
|
66
67
|
<TableButtonWidget
|
|
67
68
|
icon="arrow-right"
|
|
68
69
|
action={() => {
|