@journeyapps-labs/reactor-mod-data-browser 3.4.0 → 3.6.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 (78) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/@types/actions/schema-model/DeleteSchemaModelAction.d.ts +12 -0
  3. package/dist/@types/core/AbstractConnection.d.ts +2 -0
  4. package/dist/@types/core/SchemaModelDefinition.d.ts +20 -0
  5. package/dist/@types/core/delete-schema-models.d.ts +8 -0
  6. package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
  7. package/dist/@types/forms/types/shared/ui.d.ts +6 -0
  8. package/dist/@types/index.d.ts +1 -0
  9. package/dist/@types/panels/query/PageResultsWidget.d.ts +5 -1
  10. package/dist/@types/panels/query/QueryPanelFactory.d.ts +8 -0
  11. package/dist/@types/panels/query/TableControlsWidget.d.ts +2 -0
  12. package/dist/@types/panels/query/table-controls/SelectionControlsWidget.d.ts +6 -0
  13. package/dist/@types/preferences/QueryControlPreferences.d.ts +14 -2
  14. package/dist/@types/preferences/SchemaOrderingPreferences.d.ts +22 -0
  15. package/dist/DataBrowserModule.js +4 -0
  16. package/dist/DataBrowserModule.js.map +1 -1
  17. package/dist/actions/schema-model/DeleteSchemaModelAction.js +27 -0
  18. package/dist/actions/schema-model/DeleteSchemaModelAction.js.map +1 -0
  19. package/dist/core/AbstractConnection.js +32 -3
  20. package/dist/core/AbstractConnection.js.map +1 -1
  21. package/dist/core/SchemaModelDefinition.js +73 -17
  22. package/dist/core/SchemaModelDefinition.js.map +1 -1
  23. package/dist/core/delete-schema-models.js +101 -0
  24. package/dist/core/delete-schema-models.js.map +1 -0
  25. package/dist/core/query/query-simple/SimpleQueryColumns.js +55 -50
  26. package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
  27. package/dist/core/query/widgets/IDCellDisplayWidget.js +9 -4
  28. package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -1
  29. package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
  30. package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
  31. package/dist/entities/SchemaModelObjectEntityDefinition.js +5 -0
  32. package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
  33. package/dist/entities/SchemaModelTreePresenterComponent.js +23 -0
  34. package/dist/entities/SchemaModelTreePresenterComponent.js.map +1 -0
  35. package/dist/forms/SchemaModelForm.js +31 -29
  36. package/dist/forms/SchemaModelForm.js.map +1 -1
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/panels/model/ModelPanelWidget.js +12 -8
  40. package/dist/panels/model/ModelPanelWidget.js.map +1 -1
  41. package/dist/panels/query/PageResultsWidget.js +26 -6
  42. package/dist/panels/query/PageResultsWidget.js.map +1 -1
  43. package/dist/panels/query/QueryPanelFactory.js +39 -4
  44. package/dist/panels/query/QueryPanelFactory.js.map +1 -1
  45. package/dist/panels/query/QueryPanelWidget.js +25 -10
  46. package/dist/panels/query/QueryPanelWidget.js.map +1 -1
  47. package/dist/panels/query/TableControlsWidget.js +2 -0
  48. package/dist/panels/query/TableControlsWidget.js.map +1 -1
  49. package/dist/panels/query/table-controls/SelectionControlsWidget.js +11 -0
  50. package/dist/panels/query/table-controls/SelectionControlsWidget.js.map +1 -0
  51. package/dist/preferences/QueryControlPreferences.js +45 -1
  52. package/dist/preferences/QueryControlPreferences.js.map +1 -1
  53. package/dist/preferences/SchemaOrderingPreferences.js +76 -0
  54. package/dist/preferences/SchemaOrderingPreferences.js.map +1 -0
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/dist-module/bundle.js +74 -74
  57. package/dist-module/bundle.js.map +1 -1
  58. package/package.json +7 -6
  59. package/src/DataBrowserModule.ts +4 -0
  60. package/src/actions/schema-model/DeleteSchemaModelAction.ts +43 -0
  61. package/src/core/AbstractConnection.ts +33 -3
  62. package/src/core/SchemaModelDefinition.ts +97 -17
  63. package/src/core/delete-schema-models.ts +131 -0
  64. package/src/core/query/query-simple/SimpleQueryColumns.tsx +81 -74
  65. package/src/core/query/widgets/IDCellDisplayWidget.tsx +17 -4
  66. package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
  67. package/src/entities/SchemaModelObjectEntityDefinition.ts +4 -0
  68. package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
  69. package/src/forms/SchemaModelForm.tsx +46 -41
  70. package/src/index.ts +1 -0
  71. package/src/panels/model/ModelPanelWidget.tsx +15 -8
  72. package/src/panels/query/PageResultsWidget.tsx +45 -8
  73. package/src/panels/query/QueryPanelFactory.tsx +23 -0
  74. package/src/panels/query/QueryPanelWidget.tsx +38 -22
  75. package/src/panels/query/TableControlsWidget.tsx +4 -0
  76. package/src/panels/query/table-controls/SelectionControlsWidget.tsx +34 -0
  77. package/src/preferences/QueryControlPreferences.ts +51 -2
  78. 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.4.0",
3
+ "version": "3.6.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.6.0",
25
+ "@journeyapps-labs/reactor-mod-editor": "2.2.4",
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
  }
@@ -18,6 +18,7 @@ import { EditSchemaModelAction } from './actions/schema-model/EditSchemaModelAct
18
18
  import { TypeEngine } from './forms/TypeEngine';
19
19
  import { ViewSchemaModelAsJsonAction } from './actions/schema-model/ViewSchemaModelAsJsonAction';
20
20
  import { ViewHasManyAction } from './actions/schema-model/ViewHasManyAction';
21
+ import { DeleteSchemaModelAction } from './actions/schema-model/DeleteSchemaModelAction';
21
22
  import { ModelJsonPanelFactory } from './panels/model-json/ModelJsonPanelFactory';
22
23
  import { SchemaModelIndexDefinition } from './entities/SchemaModelIndexDefinition';
23
24
  import { SavedQueryStore } from './stores/SavedQueryStore';
@@ -25,6 +26,7 @@ import { SavedQueryEntityDefinition } from './entities/SavedQueryEntityDefinitio
25
26
  import { OpenSavedQueryAction } from './actions/saved-queries/OpenSavedQueryAction';
26
27
  import { RemoveSavedQueryAction } from './actions/saved-queries/RemoveSavedQueryAction';
27
28
  import { registerQueryControlPreferences } from './preferences/QueryControlPreferences';
29
+ import { registerSchemaOrderingPreferences } from './preferences/SchemaOrderingPreferences';
28
30
 
29
31
  export class DataBrowserModule extends AbstractReactorModule {
30
32
  constructor() {
@@ -51,12 +53,14 @@ export class DataBrowserModule extends AbstractReactorModule {
51
53
  actionStore.registerAction(new EditSchemaModelAction());
52
54
  actionStore.registerAction(new ViewSchemaModelAsJsonAction());
53
55
  actionStore.registerAction(new ViewHasManyAction());
56
+ actionStore.registerAction(new DeleteSchemaModelAction());
54
57
  actionStore.registerAction(new OpenSavedQueryAction());
55
58
  actionStore.registerAction(new RemoveSavedQueryAction());
56
59
 
57
60
  system.addStore(ConnectionStore, connectionStore);
58
61
  system.addStore(SavedQueryStore, new SavedQueryStore());
59
62
  registerQueryControlPreferences(ioc.get(PrefsStore));
63
+ registerSchemaOrderingPreferences(ioc.get(PrefsStore));
60
64
 
61
65
  system.registerDefinition(new ConnectionEntityDefinition());
62
66
  system.registerDefinition(new ConnectionFactoryEntityDefinition());
@@ -0,0 +1,43 @@
1
+ import {
2
+ ActionStore,
3
+ EntityAction,
4
+ EntityActionEvent,
5
+ ioc,
6
+ setupDeleteConfirmation
7
+ } from '@journeyapps-labs/reactor-mod';
8
+ import { DataBrowserEntities } from '../../entities';
9
+ import { SchemaModelObject } from '../../core/SchemaModelObject';
10
+ import { runDeleteSchemaModels } from '../../core/delete-schema-models';
11
+ import { ModelPanelModel } from '../../panels/model/ModelPanelFactory';
12
+
13
+ export interface DeleteSchemaModelActionEvent extends EntityActionEvent<SchemaModelObject> {
14
+ sourcePanel?: ModelPanelModel;
15
+ }
16
+
17
+ export class DeleteSchemaModelAction extends EntityAction<SchemaModelObject, DeleteSchemaModelActionEvent> {
18
+ static ID = 'DELETE_SCHEMA_MODEL';
19
+
20
+ constructor() {
21
+ super({
22
+ id: DeleteSchemaModelAction.ID,
23
+ name: 'Delete schema model',
24
+ icon: 'trash',
25
+ target: DataBrowserEntities.SCHEMA_MODEL_OBJECT
26
+ });
27
+
28
+ setupDeleteConfirmation({
29
+ action: this
30
+ });
31
+ }
32
+
33
+ async fireEvent(event: DeleteSchemaModelActionEvent): Promise<any> {
34
+ await runDeleteSchemaModels({
35
+ models: [event.targetEntity],
36
+ sourcePanel: event.sourcePanel
37
+ });
38
+ }
39
+
40
+ static get() {
41
+ return ioc.get(ActionStore).getActionByID<DeleteSchemaModelAction>(DeleteSchemaModelAction.ID);
42
+ }
43
+ }
@@ -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;
@@ -93,6 +94,27 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
93
94
  }
94
95
  }
95
96
 
97
+ async batchDelete(models: SchemaModelObject[]) {
98
+ if (models.length === 0) {
99
+ return;
100
+ }
101
+ const database = await this.getConnection();
102
+ let batch = new database.Batch();
103
+ for (let model of models) {
104
+ if (!model?.model?.persisted) {
105
+ continue;
106
+ }
107
+ batch.destroy(model.model);
108
+ }
109
+ await batch.execute();
110
+ for (let model of models) {
111
+ if (!model?.model?.persisted) {
112
+ continue;
113
+ }
114
+ model.definition.cache.delete(model.id);
115
+ }
116
+ }
117
+
96
118
  getSchemaModelDefinitionByName(name: string) {
97
119
  return this.schema_models.items.find((i) => i.definition.name === name);
98
120
  }
@@ -118,10 +140,18 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
118
140
  return connection.schema;
119
141
  }
120
142
 
143
+ protected getOrderedSchemaObjects(schema: Schema): ObjectType[] {
144
+ const objects = Object.keys(schema.objects).map((key) => schema.objects[key]);
145
+ if (SchemaModelOrderingPreference.getValue() === SchemaModelOrderValue.ALPHABETICAL) {
146
+ return _.sortBy(objects, (object) => (object.label || object.name || '').toLowerCase());
147
+ }
148
+ return objects;
149
+ }
150
+
121
151
  async reload() {
122
152
  await this.schema_models_collection.load(async () => {
123
153
  const schema = await this.getSchema();
124
- return _.values(schema.objects);
154
+ return this.getOrderedSchemaObjects(schema);
125
155
  });
126
156
  }
127
157
 
@@ -156,7 +186,7 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
156
186
 
157
187
  protected async getSchemaModelDefinitions() {
158
188
  const schema = await this.getSchema();
159
- return _.map(schema.objects, (o) => {
189
+ return this.getOrderedSchemaObjects(schema).map((o) => {
160
190
  return new SchemaModelDefinition({
161
191
  definition: o,
162
192
  connection: this
@@ -12,6 +12,7 @@ import { action, observable } from 'mobx';
12
12
  import { IndexModel } from './IndexModel';
13
13
  import { TypeEngine } from '../forms/TypeEngine';
14
14
  import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields, idVariable } from './query/StandardModelFields';
15
+ import { SchemaFieldOrderValue, SchemaFieldOrderingPreference } from '../preferences/SchemaOrderingPreferences';
15
16
 
16
17
  export interface SchemaModelDefinitionListener {
17
18
  resolved: (event: { object: SchemaModelObject }) => any;
@@ -29,6 +30,26 @@ export interface FilterableField {
29
30
  group: 'Fields' | 'Belongs to';
30
31
  }
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
+
32
53
  export class SchemaModelDefinition
33
54
  extends BaseObserver<SchemaModelDefinitionListener>
34
55
  implements LifecycleModel<ObjectType>
@@ -222,6 +243,70 @@ export class SchemaModelDefinition
222
243
  };
223
244
  }
224
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) {
256
+ return null;
257
+ }
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,
275
+ key: attribute.name,
276
+ label: attribute.label || attribute.name
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
+
225
310
  getFilterableFields(typeEngine: TypeEngine): FilterableField[] {
226
311
  return [
227
312
  ...(typeEngine.getHandler(idVariable.type)?.setupFilter
@@ -233,28 +318,23 @@ export class SchemaModelDefinition
233
318
  }
234
319
  ]
235
320
  : []),
236
- ...Object.values(this.definition.belongsToIdVars)
237
- .map((variable) => {
238
- if (!variable?.name || !variable.relationship) {
239
- return null;
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
+ };
240
329
  }
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);
330
+
331
+ const handler = typeEngine.getHandler(entry.object.type);
252
332
  if (!handler?.setupFilter) {
253
333
  return null;
254
334
  }
255
335
  return {
256
- key: attribute.name,
257
- label: attribute.label || attribute.name,
336
+ key: entry.key,
337
+ label: entry.label,
258
338
  group: 'Fields' as const
259
339
  };
260
340
  })
@@ -0,0 +1,131 @@
1
+ import { CrudError } from '@journeyapps/db';
2
+ import {
3
+ DialogStore,
4
+ ioc,
5
+ NotificationStore,
6
+ NotificationType,
7
+ ReactorPanelModel,
8
+ WorkspaceStore
9
+ } from '@journeyapps-labs/reactor-mod';
10
+ import * as _ from 'lodash';
11
+ import { SchemaModelObject } from './SchemaModelObject';
12
+ import { QueryPanelModel } from '../panels/query/QueryPanelFactory';
13
+ import { ModelPanelModel } from '../panels/model/ModelPanelFactory';
14
+
15
+ export interface DeleteSchemaModelsOptions {
16
+ models: SchemaModelObject[];
17
+ sourcePanel?: ReactorPanelModel;
18
+ }
19
+
20
+ const normalizeModels = (models: SchemaModelObject[]) => {
21
+ return _.uniqBy(
22
+ models.filter((model) => model?.model?.persisted),
23
+ (model) => model.id
24
+ );
25
+ };
26
+
27
+ const getErrorMessage = (error: unknown) => {
28
+ if (error instanceof CrudError) {
29
+ return error.firstError()?.detail || error.message;
30
+ }
31
+ if (error instanceof Error) {
32
+ return error.message;
33
+ }
34
+ return 'An unknown error occurred while deleting the selected models.';
35
+ };
36
+
37
+ const buildDeleteMarkdown = (models: SchemaModelObject[]) => {
38
+ if (models.length === 1) {
39
+ const model = models[0];
40
+ const display = model.data?.display || model.id;
41
+ return `Delete **${display}**?\n\nThis action cannot be undone.`;
42
+ }
43
+
44
+ return `Delete **${models.length}** models?\n\nThis action cannot be undone.`;
45
+ };
46
+
47
+ export const runDeleteSchemaModels = async (options: DeleteSchemaModelsOptions): Promise<boolean> => {
48
+ const models = normalizeModels(options.models);
49
+
50
+ if (models.length === 0) {
51
+ return false;
52
+ }
53
+
54
+ const definition = models[0].definition;
55
+ const mismatchedModel = models.find((model) => model.definition.connection !== definition.connection);
56
+ if (mismatchedModel) {
57
+ ioc.get(NotificationStore).showNotification({
58
+ title: 'Cannot delete models',
59
+ description: 'Selected models must come from the same connection.',
60
+ type: NotificationType.ERROR
61
+ });
62
+ return false;
63
+ }
64
+
65
+ try {
66
+ await definition.connection.batchDelete(models);
67
+ const sourcePanelID = options.sourcePanel?.id;
68
+ if (options.sourcePanel instanceof ModelPanelModel) {
69
+ options.sourcePanel.delete();
70
+ }
71
+ await Promise.all(
72
+ ioc
73
+ .get(WorkspaceStore)
74
+ .flatten(ioc.get(WorkspaceStore).getRoot())
75
+ .map(async (panel) => {
76
+ if (panel.id === sourcePanelID) {
77
+ return;
78
+ }
79
+ if (panel instanceof QueryPanelModel) {
80
+ await panel.reloadQuery();
81
+ return;
82
+ }
83
+ if (panel instanceof ModelPanelModel && models.some((model) => model.id === panel.model?.id)) {
84
+ panel.delete();
85
+ }
86
+ })
87
+ );
88
+ ioc.get(NotificationStore).showNotification({
89
+ title: models.length === 1 ? 'Model deleted' : 'Models deleted',
90
+ description:
91
+ models.length === 1
92
+ ? 'The selected model has been deleted.'
93
+ : `${models.length} selected models have been deleted.`,
94
+ type: NotificationType.SUCCESS
95
+ });
96
+ return true;
97
+ } catch (error) {
98
+ ioc.get(NotificationStore).showNotification({
99
+ title: 'Delete failed',
100
+ description: getErrorMessage(error),
101
+ type: NotificationType.ERROR
102
+ });
103
+ return false;
104
+ }
105
+ };
106
+
107
+ export const deleteSchemaModels = async (options: DeleteSchemaModelsOptions): Promise<boolean> => {
108
+ const models = normalizeModels(options.models);
109
+
110
+ if (models.length <= 1) {
111
+ return false;
112
+ }
113
+
114
+ const confirmed = await ioc.get(DialogStore).showConfirmDialog({
115
+ title: 'Delete selected models',
116
+ markdown: buildDeleteMarkdown(models),
117
+ yesBtn: {
118
+ label: `Delete ${models.length} models`,
119
+ icon: 'trash'
120
+ }
121
+ });
122
+
123
+ if (!confirmed) {
124
+ return false;
125
+ }
126
+
127
+ return runDeleteSchemaModels({
128
+ ...options,
129
+ models
130
+ });
131
+ };
@@ -17,6 +17,7 @@ import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields, idVariable } from '..
17
17
  import { TypeEngine } from '../../../forms/TypeEngine';
18
18
  import { setupBelongsToFilter } from '../../../forms/types/belongs-to-filter';
19
19
  import { Condition, SimpleFilter, Statement } from '../filters';
20
+ import { OrderedSchemaFieldType } from '../../SchemaModelDefinition';
20
21
 
21
22
  export interface BuildSimpleQueryColumnsOptions {
22
23
  definition: SchemaModelDefinition;
@@ -81,82 +82,88 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
81
82
  return <CellDisplayWidget name={StandardModelFields.UPDATED_AT} cell={row.model.updated_at} row={row} />;
82
83
  }
83
84
  },
84
- ..._.map(options.definition.definition.belongsToIdVars, (a) => {
85
- return {
86
- key: a.name,
87
- display: (
88
- <SmartColumnWidget
89
- variable={options.definition.definition.belongsToVars[a.relationship]}
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
- }}
107
- />
108
- ),
109
- noWrap: true,
110
- shrink: true,
111
- accessor: (cell, row: PageRow) => {
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
- );
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
+ accessor: (cell, row: PageRow) => {
116
+ return (
117
+ <SmartBelongsToDisplayWidget
118
+ variable_id={variable}
119
+ row={row}
120
+ connection={options.connection}
121
+ filterBelongsTo={async (object) => {
122
+ options.filterState.setFilter(
123
+ variable.name,
124
+ new SimpleFilter(variable, [new Statement(Condition.EQUALS, object.id)])
125
+ );
126
+ }}
127
+ />
128
+ );
129
+ }
130
+ } as TableColumn
131
+ ];
132
+ }
133
+
134
+ const attribute = entry.object;
135
+ return [
136
+ {
137
+ key: attribute.name,
138
+ display: (
139
+ <SmartColumnWidget
140
+ variable={attribute}
141
+ typeLabel={ioc.get(TypeEngine).getHandler(attribute.type)?.getTypeLabel?.(attribute.type)}
142
+ filter={options.filterState.getFilter(attribute.name)}
143
+ sortDirection={options.sortState.getSort(attribute.name)?.direction}
144
+ onToggleSort={async () => {
145
+ const sort = options.sortState.getSort(attribute.name);
146
+ if (!sort) {
147
+ options.sortState.addSort(SimpleQuerySort.create(attribute.name));
148
+ return;
149
+ }
150
+ sort.toggle();
151
+ }}
152
+ filterChanged={async (filter) => {
153
+ if (!filter) {
154
+ options.filterState.getFilter(attribute.name)?.delete();
155
+ return;
156
+ }
157
+ options.filterState.setFilter(attribute.name, filter);
122
158
  }}
123
159
  />
124
- );
125
- }
126
- } as TableColumn;
127
- }),
128
- ..._.map(options.definition.definition.attributes, (a) => {
129
- return {
130
- key: a.name,
131
- display: (
132
- <SmartColumnWidget
133
- variable={a}
134
- typeLabel={ioc.get(TypeEngine).getHandler(a.type)?.getTypeLabel?.(a.type)}
135
- filter={options.filterState.getFilter(a.name)}
136
- sortDirection={options.sortState.getSort(a.name)?.direction}
137
- onToggleSort={async () => {
138
- const sort = options.sortState.getSort(a.name);
139
- if (!sort) {
140
- options.sortState.addSort(SimpleQuerySort.create(a.name));
141
- return;
142
- }
143
- sort.toggle();
144
- }}
145
- filterChanged={async (filter) => {
146
- if (!filter) {
147
- options.filterState.getFilter(a.name)?.delete();
148
- return;
149
- }
150
- options.filterState.setFilter(a.name, filter);
151
- }}
152
- />
153
- ),
154
- noWrap: true,
155
- shrink: true,
156
- accessor: (cell, row: PageRow) => {
157
- return <SmartCellDisplayWidget name={a.name} row={row} />;
158
- }
159
- } as TableColumn;
160
+ ),
161
+ noWrap: true,
162
+ accessor: (cell, row: PageRow) => {
163
+ return <SmartCellDisplayWidget name={attribute.name} row={row} />;
164
+ }
165
+ } as TableColumn
166
+ ];
160
167
  })
161
168
  ];
162
169
  };
@@ -1,17 +1,30 @@
1
1
  import * as React from 'react';
2
- import { NotificationStore, NotificationType, TableButtonWidget, ioc, styled } from '@journeyapps-labs/reactor-mod';
2
+ import { observer } from 'mobx-react';
3
+ import {
4
+ BooleanSetting,
5
+ NotificationStore,
6
+ NotificationType,
7
+ PrefsStore,
8
+ TableButtonWidget,
9
+ ioc,
10
+ styled
11
+ } from '@journeyapps-labs/reactor-mod';
3
12
  import { copyTextToClipboard } from '@journeyapps-labs/lib-reactor-utils';
13
+ import { QueryControlPreferences } from '../../../preferences/QueryControlPreferences';
4
14
 
5
15
  export interface IDCellDisplayWidgetProps {
6
16
  id: string;
7
17
  }
8
18
 
9
- export const IDCellDisplayWidget: React.FC<IDCellDisplayWidgetProps> = (props) => {
19
+ export const IDCellDisplayWidget: React.FC<IDCellDisplayWidgetProps> = observer((props) => {
10
20
  const notifications = ioc.get(NotificationStore);
21
+ const showIdValue = ioc
22
+ .get(PrefsStore)
23
+ .getPreference<BooleanSetting>(QueryControlPreferences.SHOW_ID_VALUE_IN_ID_COLUMN).checked;
11
24
 
12
25
  return (
13
26
  <S.Container>
14
- <S.Value>{props.id}</S.Value>
27
+ {showIdValue ? <S.Value>{props.id}</S.Value> : null}
15
28
  <TableButtonWidget
16
29
  icon="copy"
17
30
  tooltip="Copy ID"
@@ -26,7 +39,7 @@ export const IDCellDisplayWidget: React.FC<IDCellDisplayWidgetProps> = (props) =
26
39
  />
27
40
  </S.Container>
28
41
  );
29
- };
42
+ });
30
43
 
31
44
  namespace S {
32
45
  export const Container = styled.div`