@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.
Files changed (133) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/@types/actions/schema-model/ViewHasManyAction.d.ts +12 -0
  3. package/dist/@types/core/AbstractConnection.d.ts +1 -0
  4. package/dist/@types/core/SchemaModelDefinition.d.ts +32 -5
  5. package/dist/@types/core/query/StandardModelFields.d.ts +4 -0
  6. package/dist/@types/core/query/query-simple/SimpleQueryFilterState.d.ts +4 -6
  7. package/dist/@types/core/query/widgets/BelongsToDisplayWidget.d.ts +1 -0
  8. package/dist/@types/core/query/widgets/ColumnDisplayWidget.d.ts +1 -0
  9. package/dist/@types/core/query/widgets/IDCellDisplayWidget.d.ts +5 -0
  10. package/dist/@types/core/query/widgets/PeekRelationshipButton.d.ts +1 -0
  11. package/dist/@types/core/query/widgets/SmartBelongsToDisplayWidget.d.ts +2 -0
  12. package/dist/@types/core/query/widgets/SmartColumnWidget.d.ts +7 -2
  13. package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
  14. package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +2 -1
  15. package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
  16. package/dist/@types/forms/types/belongs-to-filter.d.ts +10 -0
  17. package/dist/@types/forms/types/shared/type-handler.d.ts +1 -0
  18. package/dist/@types/index.d.ts +1 -0
  19. package/dist/@types/preferences/QueryControlPreferences.d.ts +14 -2
  20. package/dist/@types/preferences/SchemaOrderingPreferences.d.ts +22 -0
  21. package/dist/DataBrowserModule.js +4 -0
  22. package/dist/DataBrowserModule.js.map +1 -1
  23. package/dist/actions/schema-model/ViewHasManyAction.js +112 -0
  24. package/dist/actions/schema-model/ViewHasManyAction.js.map +1 -0
  25. package/dist/core/AbstractConnection.js +11 -3
  26. package/dist/core/AbstractConnection.js.map +1 -1
  27. package/dist/core/SchemaModelDefinition.js +121 -7
  28. package/dist/core/SchemaModelDefinition.js.map +1 -1
  29. package/dist/core/query/StandardModelFields.js +3 -0
  30. package/dist/core/query/StandardModelFields.js.map +1 -1
  31. package/dist/core/query/query-simple/SimpleQueryColumns.js +74 -42
  32. package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
  33. package/dist/core/query/query-simple/SimpleQueryFilterState.js +35 -7
  34. package/dist/core/query/query-simple/SimpleQueryFilterState.js.map +1 -1
  35. package/dist/core/query/query-simple/SimpleQuerySortState.js +0 -1
  36. package/dist/core/query/query-simple/SimpleQuerySortState.js.map +1 -1
  37. package/dist/core/query/widgets/BelongsToDisplayWidget.js +1 -1
  38. package/dist/core/query/widgets/BelongsToDisplayWidget.js.map +1 -1
  39. package/dist/core/query/widgets/ColumnDisplayWidget.js +13 -2
  40. package/dist/core/query/widgets/ColumnDisplayWidget.js.map +1 -1
  41. package/dist/core/query/widgets/IDCellDisplayWidget.js +38 -0
  42. package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -0
  43. package/dist/core/query/widgets/PeekRelationshipButton.js +23 -16
  44. package/dist/core/query/widgets/PeekRelationshipButton.js.map +1 -1
  45. package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js +1 -1
  46. package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js.map +1 -1
  47. package/dist/core/query/widgets/SmartColumnWidget.js +3 -13
  48. package/dist/core/query/widgets/SmartColumnWidget.js.map +1 -1
  49. package/dist/core/query/widgets/SmartFilterWidget.js +10 -7
  50. package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
  51. package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
  52. package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
  53. package/dist/entities/SchemaModelObjectEntityDefinition.js +15 -14
  54. package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
  55. package/dist/entities/SchemaModelTreePresenterComponent.js +23 -0
  56. package/dist/entities/SchemaModelTreePresenterComponent.js.map +1 -0
  57. package/dist/forms/SchemaModelForm.js +31 -29
  58. package/dist/forms/SchemaModelForm.js.map +1 -1
  59. package/dist/forms/types/attachment-handler.js +1 -0
  60. package/dist/forms/types/attachment-handler.js.map +1 -1
  61. package/dist/forms/types/belongs-to-filter.js +57 -0
  62. package/dist/forms/types/belongs-to-filter.js.map +1 -0
  63. package/dist/forms/types/boolean-handler.js +34 -1
  64. package/dist/forms/types/boolean-handler.js.map +1 -1
  65. package/dist/forms/types/date-handler.js +1 -0
  66. package/dist/forms/types/date-handler.js.map +1 -1
  67. package/dist/forms/types/image-handler.js +1 -0
  68. package/dist/forms/types/image-handler.js.map +1 -1
  69. package/dist/forms/types/location-handler.js +1 -0
  70. package/dist/forms/types/location-handler.js.map +1 -1
  71. package/dist/forms/types/multiple-choice-handler.js +1 -0
  72. package/dist/forms/types/multiple-choice-handler.js.map +1 -1
  73. package/dist/forms/types/multiple-choice-integer-handler.js +1 -0
  74. package/dist/forms/types/multiple-choice-integer-handler.js.map +1 -1
  75. package/dist/forms/types/number-handler.js +3 -2
  76. package/dist/forms/types/number-handler.js.map +1 -1
  77. package/dist/forms/types/single-choice-handler.js +1 -0
  78. package/dist/forms/types/single-choice-handler.js.map +1 -1
  79. package/dist/forms/types/single-choice-integer-handler.js +1 -0
  80. package/dist/forms/types/single-choice-integer-handler.js.map +1 -1
  81. package/dist/forms/types/text-handler.js +1 -0
  82. package/dist/forms/types/text-handler.js.map +1 -1
  83. package/dist/index.js +1 -0
  84. package/dist/index.js.map +1 -1
  85. package/dist/panels/query/QueryPanelWidget.js +14 -9
  86. package/dist/panels/query/QueryPanelWidget.js.map +1 -1
  87. package/dist/panels/query/table-controls/FilterControlsWidget.js +1 -0
  88. package/dist/panels/query/table-controls/FilterControlsWidget.js.map +1 -1
  89. package/dist/preferences/QueryControlPreferences.js +45 -1
  90. package/dist/preferences/QueryControlPreferences.js.map +1 -1
  91. package/dist/preferences/SchemaOrderingPreferences.js +76 -0
  92. package/dist/preferences/SchemaOrderingPreferences.js.map +1 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/dist-module/bundle.js +51 -35
  95. package/dist-module/bundle.js.map +1 -1
  96. package/package.json +7 -6
  97. package/src/DataBrowserModule.ts +4 -0
  98. package/src/actions/schema-model/ViewHasManyAction.ts +114 -0
  99. package/src/core/AbstractConnection.ts +12 -3
  100. package/src/core/SchemaModelDefinition.ts +165 -9
  101. package/src/core/query/StandardModelFields.ts +8 -0
  102. package/src/core/query/query-simple/SimpleQueryColumns.tsx +103 -58
  103. package/src/core/query/query-simple/SimpleQueryFilterState.ts +42 -9
  104. package/src/core/query/query-simple/SimpleQuerySortState.ts +0 -1
  105. package/src/core/query/widgets/BelongsToDisplayWidget.tsx +2 -1
  106. package/src/core/query/widgets/ColumnDisplayWidget.tsx +17 -4
  107. package/src/core/query/widgets/IDCellDisplayWidget.tsx +59 -0
  108. package/src/core/query/widgets/PeekRelationshipButton.tsx +23 -16
  109. package/src/core/query/widgets/SmartBelongsToDisplayWidget.tsx +3 -0
  110. package/src/core/query/widgets/SmartColumnWidget.tsx +23 -20
  111. package/src/core/query/widgets/SmartFilterWidget.tsx +14 -5
  112. package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
  113. package/src/entities/SchemaModelObjectEntityDefinition.ts +17 -15
  114. package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
  115. package/src/forms/SchemaModelForm.tsx +46 -41
  116. package/src/forms/types/attachment-handler.tsx +1 -0
  117. package/src/forms/types/belongs-to-filter.tsx +84 -0
  118. package/src/forms/types/boolean-handler.tsx +46 -2
  119. package/src/forms/types/date-handler.tsx +1 -0
  120. package/src/forms/types/image-handler.tsx +1 -0
  121. package/src/forms/types/location-handler.tsx +1 -0
  122. package/src/forms/types/multiple-choice-handler.tsx +1 -0
  123. package/src/forms/types/multiple-choice-integer-handler.tsx +1 -0
  124. package/src/forms/types/number-handler.tsx +3 -2
  125. package/src/forms/types/shared/type-handler.ts +1 -0
  126. package/src/forms/types/single-choice-handler.tsx +1 -0
  127. package/src/forms/types/single-choice-integer-handler.tsx +1 -0
  128. package/src/forms/types/text-handler.tsx +1 -0
  129. package/src/index.ts +1 -0
  130. package/src/panels/query/QueryPanelWidget.tsx +24 -22
  131. package/src/panels/query/table-controls/FilterControlsWidget.tsx +1 -0
  132. package/src/preferences/QueryControlPreferences.ts +51 -2
  133. 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.0",
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.2.0",
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.10",
24
- "@journeyapps-labs/reactor-mod": "5.3.1",
25
- "@journeyapps-labs/reactor-mod-editor": "2.2.1",
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.1",
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
  }
@@ -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 _.values(schema.objects);
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 _.map(schema.objects, (o) => {
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
- getFilterableFields(typeEngine: TypeEngine): { key: string; label: string }[] {
175
- return Object.values(this.definition.attributes)
176
- .map((attribute) => {
177
- const handler = typeEngine.getHandler(attribute.type);
178
- if (!handler?.setupFilter) {
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
- .filter((value) => !!value);
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
- <ColumnDisplayWidget
38
- label={getSortLabel(StandardModelFields.ID, STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID])}
39
- onClick={async () => {
40
- const sort = options.sortState.getSort(StandardModelFields.ID);
41
- if (!sort) {
42
- options.sortState.addSort(SimpleQuerySort.create(StandardModelFields.ID));
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
- sort.toggle();
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
- ..._.map(options.definition.definition.belongsToIdVars, (a) => {
77
- return {
78
- key: a.name,
79
- display: (
80
- <SmartColumnWidget
81
- variable={options.definition.definition.belongsToVars[a.relationship]}
82
- type={options.definition.definition.belongsTo[a.relationship].foreignType}
83
- filterChanged={(filter) => {}}
84
- />
85
- ),
86
- noWrap: true,
87
- shrink: true,
88
- accessor: (cell, row: PageRow) => {
89
- return <SmartBelongsToDisplayWidget variable_id={a} row={row} connection={options.connection} />;
90
- }
91
- } as TableColumn;
92
- }),
93
- ..._.map(options.definition.definition.attributes, (a) => {
94
- return {
95
- key: a.name,
96
- display: (
97
- <SmartColumnWidget
98
- variable={a}
99
- filter={options.filterState.getFilter(a.name)}
100
- sortDirection={options.sortState.getSort(a.name)?.direction}
101
- onToggleSort={async () => {
102
- const sort = options.sortState.getSort(a.name);
103
- if (!sort) {
104
- options.sortState.addSort(SimpleQuerySort.create(a.name));
105
- return;
106
- }
107
- sort.toggle();
108
- }}
109
- filterChanged={async (filter) => {
110
- if (!filter) {
111
- options.filterState.getFilter(a.name)?.delete();
112
- return;
113
- }
114
- options.filterState.setFilter(a.name, filter);
115
- }}
116
- />
117
- ),
118
- noWrap: true,
119
- shrink: true,
120
- accessor: (cell, row: PageRow) => {
121
- return <SmartCellDisplayWidget name={a.name} row={row} />;
122
- }
123
- } as TableColumn;
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
  };