@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.
- package/CHANGELOG.md +20 -0
- package/dist/@types/actions/schema-model/DeleteSchemaModelAction.d.ts +12 -0
- package/dist/@types/core/AbstractConnection.d.ts +2 -0
- package/dist/@types/core/SchemaModelDefinition.d.ts +20 -0
- package/dist/@types/core/delete-schema-models.d.ts +8 -0
- package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
- package/dist/@types/forms/types/shared/ui.d.ts +6 -0
- package/dist/@types/index.d.ts +1 -0
- package/dist/@types/panels/query/PageResultsWidget.d.ts +5 -1
- package/dist/@types/panels/query/QueryPanelFactory.d.ts +8 -0
- package/dist/@types/panels/query/TableControlsWidget.d.ts +2 -0
- package/dist/@types/panels/query/table-controls/SelectionControlsWidget.d.ts +6 -0
- package/dist/@types/preferences/QueryControlPreferences.d.ts +14 -2
- package/dist/@types/preferences/SchemaOrderingPreferences.d.ts +22 -0
- package/dist/DataBrowserModule.js +4 -0
- package/dist/DataBrowserModule.js.map +1 -1
- package/dist/actions/schema-model/DeleteSchemaModelAction.js +27 -0
- package/dist/actions/schema-model/DeleteSchemaModelAction.js.map +1 -0
- package/dist/core/AbstractConnection.js +32 -3
- package/dist/core/AbstractConnection.js.map +1 -1
- package/dist/core/SchemaModelDefinition.js +73 -17
- package/dist/core/SchemaModelDefinition.js.map +1 -1
- package/dist/core/delete-schema-models.js +101 -0
- package/dist/core/delete-schema-models.js.map +1 -0
- package/dist/core/query/query-simple/SimpleQueryColumns.js +55 -50
- package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
- package/dist/core/query/widgets/IDCellDisplayWidget.js +9 -4
- package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -1
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelObjectEntityDefinition.js +5 -0
- package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelTreePresenterComponent.js +23 -0
- package/dist/entities/SchemaModelTreePresenterComponent.js.map +1 -0
- package/dist/forms/SchemaModelForm.js +31 -29
- package/dist/forms/SchemaModelForm.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/panels/model/ModelPanelWidget.js +12 -8
- package/dist/panels/model/ModelPanelWidget.js.map +1 -1
- package/dist/panels/query/PageResultsWidget.js +26 -6
- package/dist/panels/query/PageResultsWidget.js.map +1 -1
- package/dist/panels/query/QueryPanelFactory.js +39 -4
- package/dist/panels/query/QueryPanelFactory.js.map +1 -1
- package/dist/panels/query/QueryPanelWidget.js +25 -10
- package/dist/panels/query/QueryPanelWidget.js.map +1 -1
- package/dist/panels/query/TableControlsWidget.js +2 -0
- package/dist/panels/query/TableControlsWidget.js.map +1 -1
- package/dist/panels/query/table-controls/SelectionControlsWidget.js +11 -0
- package/dist/panels/query/table-controls/SelectionControlsWidget.js.map +1 -0
- package/dist/preferences/QueryControlPreferences.js +45 -1
- package/dist/preferences/QueryControlPreferences.js.map +1 -1
- package/dist/preferences/SchemaOrderingPreferences.js +76 -0
- package/dist/preferences/SchemaOrderingPreferences.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist-module/bundle.js +74 -74
- package/dist-module/bundle.js.map +1 -1
- package/package.json +7 -6
- package/src/DataBrowserModule.ts +4 -0
- package/src/actions/schema-model/DeleteSchemaModelAction.ts +43 -0
- package/src/core/AbstractConnection.ts +33 -3
- package/src/core/SchemaModelDefinition.ts +97 -17
- package/src/core/delete-schema-models.ts +131 -0
- package/src/core/query/query-simple/SimpleQueryColumns.tsx +81 -74
- package/src/core/query/widgets/IDCellDisplayWidget.tsx +17 -4
- package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
- package/src/entities/SchemaModelObjectEntityDefinition.ts +4 -0
- package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
- package/src/forms/SchemaModelForm.tsx +46 -41
- package/src/index.ts +1 -0
- package/src/panels/model/ModelPanelWidget.tsx +15 -8
- package/src/panels/query/PageResultsWidget.tsx +45 -8
- package/src/panels/query/QueryPanelFactory.tsx +23 -0
- package/src/panels/query/QueryPanelWidget.tsx +38 -22
- package/src/panels/query/TableControlsWidget.tsx +4 -0
- package/src/panels/query/table-controls/SelectionControlsWidget.tsx +34 -0
- package/src/preferences/QueryControlPreferences.ts +51 -2
- package/src/preferences/SchemaOrderingPreferences.ts +82 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@journeyapps-labs/reactor-mod-data-browser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.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.
|
|
18
|
+
"@fortawesome/react-fontawesome": "^3.3.0",
|
|
19
19
|
"@journeyapps-labs/client-backend-v4": "1.0.0",
|
|
20
20
|
"@journeyapps-labs/common-ioc": "^1.0.1",
|
|
21
21
|
"@journeyapps-labs/common-sdk": "^1.0.3",
|
|
22
22
|
"@journeyapps-labs/common-utils": "^1.0.1",
|
|
23
|
-
"@journeyapps-labs/lib-reactor-data-layer": "1.0.
|
|
24
|
-
"@journeyapps-labs/reactor-mod": "5.
|
|
25
|
-
"@journeyapps-labs/reactor-mod-editor": "2.2.
|
|
23
|
+
"@journeyapps-labs/lib-reactor-data-layer": "1.0.11",
|
|
24
|
+
"@journeyapps-labs/reactor-mod": "5.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.
|
|
37
|
+
"@journeyapps-labs/lib-reactor-builder": "3.0.2",
|
|
38
38
|
"@types/async": "^3.2.25",
|
|
39
39
|
"@types/lodash": "^4.17.24",
|
|
40
40
|
"@types/react": "^19.2.14",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build:module": "reactor build .",
|
|
45
|
+
"clean": "rm -rf dist-module",
|
|
45
46
|
"watch:module": "pnpm build:module --watch"
|
|
46
47
|
}
|
|
47
48
|
}
|
package/src/DataBrowserModule.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
...
|
|
237
|
-
.map((
|
|
238
|
-
if (
|
|
239
|
-
return
|
|
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
|
-
|
|
242
|
-
|
|
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:
|
|
257
|
-
label:
|
|
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
|
-
...
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 {
|
|
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`
|