@journeyapps-labs/reactor-mod-data-browser 3.6.0 → 3.6.1
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 +12 -0
- package/dist/@types/core/SchemaModelObject.d.ts +3 -0
- package/dist/@types/core/query/AbstractQuery.d.ts +3 -1
- package/dist/actions/schema-definitions/CreateModelAction.js +1 -1
- package/dist/actions/schema-definitions/CreateModelAction.js.map +1 -1
- package/dist/core/AbstractConnection.js +2 -1
- package/dist/core/AbstractConnection.js.map +1 -1
- package/dist/core/SchemaModelDefinition.js +2 -2
- package/dist/core/SchemaModelDefinition.js.map +1 -1
- package/dist/core/SchemaModelObject.js +52 -9
- package/dist/core/SchemaModelObject.js.map +1 -1
- package/dist/core/query/AbstractQuery.js +48 -10
- package/dist/core/query/AbstractQuery.js.map +1 -1
- package/dist/core/query/widgets/SmartFilterWidget.js +1 -1
- package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
- package/dist/forms/SchemaModelForm.js +9 -3
- package/dist/forms/SchemaModelForm.js.map +1 -1
- package/dist/panels/_shared/SharedModelPanelFactory.js +4 -2
- package/dist/panels/_shared/SharedModelPanelFactory.js.map +1 -1
- package/dist/panels/model/ModelPanelWidget.js +3 -3
- package/dist/panels/model/ModelPanelWidget.js.map +1 -1
- package/dist/panels/query/TableControlsWidget.js +11 -2
- package/dist/panels/query/TableControlsWidget.js.map +1 -1
- package/dist/panels/query/table-controls/ChangesControlsWidget.js +1 -1
- package/dist/panels/query/table-controls/ChangesControlsWidget.js.map +1 -1
- package/dist/panels/query/table-controls/PageControlsWidget.js +8 -5
- package/dist/panels/query/table-controls/PageControlsWidget.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist-module/bundle.js +36 -36
- package/dist-module/bundle.js.map +1 -1
- package/package.json +6 -6
- package/src/actions/schema-definitions/CreateModelAction.ts +1 -1
- package/src/core/AbstractConnection.ts +2 -1
- package/src/core/SchemaModelDefinition.ts +3 -5
- package/src/core/SchemaModelObject.ts +30 -7
- package/src/core/query/AbstractQuery.ts +16 -2
- package/src/core/query/widgets/SmartFilterWidget.tsx +1 -1
- package/src/forms/SchemaModelForm.tsx +7 -2
- package/src/panels/_shared/SharedModelPanelFactory.tsx +4 -2
- package/src/panels/model/ModelPanelWidget.tsx +3 -3
- package/src/panels/query/TableControlsWidget.tsx +22 -2
- package/src/panels/query/table-controls/ChangesControlsWidget.tsx +1 -1
- package/src/panels/query/table-controls/PageControlsWidget.tsx +7 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@journeyapps-labs/reactor-mod-data-browser",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"typings": "./dist/@types/index",
|
|
6
6
|
"publishConfig": {
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@emotion/styled": "^11.14.1",
|
|
18
|
-
"@fortawesome/react-fontawesome": "^3.3.
|
|
18
|
+
"@fortawesome/react-fontawesome": "^3.3.1",
|
|
19
19
|
"@journeyapps-labs/client-backend-v4": "1.0.0",
|
|
20
20
|
"@journeyapps-labs/common-ioc": "^1.0.1",
|
|
21
|
-
"@journeyapps-labs/common-sdk": "^1.0.
|
|
21
|
+
"@journeyapps-labs/common-sdk": "^1.0.4",
|
|
22
22
|
"@journeyapps-labs/common-utils": "^1.0.1",
|
|
23
23
|
"@journeyapps-labs/lib-reactor-data-layer": "1.0.11",
|
|
24
24
|
"@journeyapps-labs/reactor-mod": "5.6.0",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@journeyapps/parser-schema": "^8.2.5",
|
|
28
28
|
"@projectstorm/react-workspaces-core": "4.2.3",
|
|
29
29
|
"async": "^3.2.6",
|
|
30
|
-
"lodash": "^4.
|
|
30
|
+
"lodash": "^4.18.1",
|
|
31
31
|
"mobx": "^6.15.0",
|
|
32
32
|
"mobx-react": "^9.2.1",
|
|
33
|
-
"react": "19.2.
|
|
34
|
-
"uuid": "^
|
|
33
|
+
"react": "19.2.5",
|
|
34
|
+
"uuid": "^14.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@journeyapps-labs/lib-reactor-builder": "3.0.2",
|
|
@@ -6,13 +6,11 @@ import { SchemaModelObject } from './SchemaModelObject';
|
|
|
6
6
|
import { LifecycleModel } from '@journeyapps-labs/lib-reactor-data-layer';
|
|
7
7
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
8
8
|
import { queue, QueueObject } from 'async';
|
|
9
|
-
import {
|
|
10
|
-
import { V4Index } from '@journeyapps-labs/client-backend-v4';
|
|
11
|
-
import { action, observable } from 'mobx';
|
|
9
|
+
import { observable } from 'mobx';
|
|
12
10
|
import { IndexModel } from './IndexModel';
|
|
13
11
|
import { TypeEngine } from '../forms/TypeEngine';
|
|
14
|
-
import { STANDARD_MODEL_FIELD_LABELS, StandardModelFields
|
|
15
|
-
import {
|
|
12
|
+
import { idVariable, STANDARD_MODEL_FIELD_LABELS, StandardModelFields } from './query/StandardModelFields';
|
|
13
|
+
import { SchemaFieldOrderingPreference, SchemaFieldOrderValue } from '../preferences/SchemaOrderingPreferences';
|
|
16
14
|
|
|
17
15
|
export interface SchemaModelDefinitionListener {
|
|
18
16
|
resolved: (event: { object: SchemaModelObject }) => any;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ApiObjectData, DatabaseAdapter, DatabaseObject } from '@journeyapps/db';
|
|
2
2
|
import { SchemaModelDefinition } from './SchemaModelDefinition';
|
|
3
|
-
import { action, observable } from 'mobx';
|
|
3
|
+
import { action, observable, runInAction } from 'mobx';
|
|
4
|
+
import { inject, NotificationStore, NotificationType, VisorStore } from '@journeyapps-labs/reactor-mod';
|
|
4
5
|
|
|
5
6
|
export interface SchemaModelObjectOptions {
|
|
6
7
|
definition: SchemaModelDefinition;
|
|
@@ -9,6 +10,12 @@ export interface SchemaModelObjectOptions {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export class SchemaModelObject {
|
|
13
|
+
@inject(VisorStore)
|
|
14
|
+
accessor visorStore: VisorStore;
|
|
15
|
+
|
|
16
|
+
@inject(NotificationStore)
|
|
17
|
+
accessor notificationStore: NotificationStore;
|
|
18
|
+
|
|
12
19
|
@observable
|
|
13
20
|
accessor data: ApiObjectData;
|
|
14
21
|
|
|
@@ -31,30 +38,42 @@ export class SchemaModelObject {
|
|
|
31
38
|
async applyPatches() {
|
|
32
39
|
if (!this.model) {
|
|
33
40
|
const collection = await this.definition.getCollection();
|
|
34
|
-
|
|
41
|
+
runInAction(() => {
|
|
42
|
+
this.model = collection.create();
|
|
43
|
+
});
|
|
35
44
|
}
|
|
36
45
|
for (let entry of this.patch.entries()) {
|
|
37
46
|
if (this.definition.definition.belongsTo[entry[0]]) {
|
|
38
|
-
this.model[entry[0]](entry[1]
|
|
47
|
+
this.model[entry[0]](entry[1]?.model || null);
|
|
39
48
|
} else {
|
|
40
49
|
this.model[entry[0]] = entry[1];
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
|
-
this.
|
|
52
|
+
this.clearEdits();
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
async save() {
|
|
47
|
-
await this.definition.
|
|
56
|
+
await this.visorStore.wrap(`Saving ${this.definition.definition.label}`, async () => {
|
|
57
|
+
await this.definition.connection.batchSave([this]);
|
|
58
|
+
});
|
|
59
|
+
this.notificationStore.showNotification({
|
|
60
|
+
title: 'Model updated',
|
|
61
|
+
description: `${this.definition.definition.label} was updated`,
|
|
62
|
+
type: NotificationType.SUCCESS
|
|
63
|
+
});
|
|
48
64
|
}
|
|
49
65
|
|
|
66
|
+
@action
|
|
50
67
|
clearEdits() {
|
|
51
68
|
this.patch.clear();
|
|
52
69
|
}
|
|
53
70
|
|
|
71
|
+
@action
|
|
54
72
|
revert(field: string) {
|
|
55
73
|
this.patch.delete(field);
|
|
56
74
|
}
|
|
57
75
|
|
|
76
|
+
@action
|
|
58
77
|
set(field: string, value: any) {
|
|
59
78
|
if (this.model?.[field] === value) {
|
|
60
79
|
this.patch.delete(field);
|
|
@@ -72,7 +91,11 @@ export class SchemaModelObject {
|
|
|
72
91
|
}
|
|
73
92
|
|
|
74
93
|
async reload() {
|
|
75
|
-
await this.definition.load(this.id);
|
|
94
|
+
const model = await this.definition.load(this.id);
|
|
95
|
+
if (model && model !== this) {
|
|
96
|
+
this.setData(model.data);
|
|
97
|
+
this.definition.cache.set(this.id, this);
|
|
98
|
+
}
|
|
76
99
|
}
|
|
77
100
|
|
|
78
101
|
get definition(): SchemaModelDefinition {
|
|
@@ -80,6 +103,6 @@ export class SchemaModelObject {
|
|
|
80
103
|
}
|
|
81
104
|
|
|
82
105
|
get id() {
|
|
83
|
-
return this.data
|
|
106
|
+
return this.data?.id;
|
|
84
107
|
}
|
|
85
108
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Page } from './Page';
|
|
2
2
|
import { AbstractConnection } from '../AbstractConnection';
|
|
3
3
|
import { v4 } from 'uuid';
|
|
4
|
-
import { TableColumn } from '@journeyapps-labs/reactor-mod';
|
|
4
|
+
import { inject, NotificationStore, NotificationType, TableColumn, VisorStore } from '@journeyapps-labs/reactor-mod';
|
|
5
5
|
import { SchemaModelObject } from '../SchemaModelObject';
|
|
6
6
|
|
|
7
7
|
export abstract class AbstractQuery {
|
|
8
|
+
@inject(VisorStore)
|
|
9
|
+
accessor visorStore: VisorStore;
|
|
10
|
+
|
|
11
|
+
@inject(NotificationStore)
|
|
12
|
+
accessor notificationStore: NotificationStore;
|
|
13
|
+
|
|
8
14
|
id: string;
|
|
9
15
|
|
|
10
16
|
constructor(
|
|
@@ -15,7 +21,15 @@ export abstract class AbstractQuery {
|
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
async batchSave() {
|
|
18
|
-
|
|
24
|
+
const dirtyObjects = this.getDirtyObjects();
|
|
25
|
+
await this.visorStore.wrap(`Saving ${dirtyObjects.length} models`, async () => {
|
|
26
|
+
await this.connection.batchSave(dirtyObjects);
|
|
27
|
+
});
|
|
28
|
+
this.notificationStore.showNotification({
|
|
29
|
+
title: 'Models updated',
|
|
30
|
+
description: `${dirtyObjects.length} ${dirtyObjects.length === 1 ? 'model was' : 'models were'} updated`,
|
|
31
|
+
type: NotificationType.SUCCESS
|
|
32
|
+
});
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
abstract getDirtyObjects(): SchemaModelObject[];
|
|
@@ -73,7 +73,7 @@ export const SmartFilterWidget: React.FC<SmartFilterWidgetProps> = (props) => {
|
|
|
73
73
|
active={isActive}
|
|
74
74
|
{...setupTooltipProps({
|
|
75
75
|
tooltip: getFilterTooltip(props.filter),
|
|
76
|
-
tooltipPos: TooltipPosition.
|
|
76
|
+
tooltipPos: TooltipPosition.BOTTOM_RIGHT
|
|
77
77
|
})}
|
|
78
78
|
onClick={async (event) => {
|
|
79
79
|
const filter = await props.setupFilter({
|
|
@@ -81,7 +81,7 @@ export class TypedBinding extends Binding {
|
|
|
81
81
|
super({
|
|
82
82
|
...options,
|
|
83
83
|
resolve: async () => {
|
|
84
|
-
return options.model?.model[options.name];
|
|
84
|
+
return options.model?.model?.[options.name];
|
|
85
85
|
}
|
|
86
86
|
});
|
|
87
87
|
this.handler = this.typeEngine.getHandler(options.variable.type);
|
|
@@ -110,6 +110,7 @@ export class SchemaModelForm extends FormModel {
|
|
|
110
110
|
.map((entry) => {
|
|
111
111
|
if (entry.type === OrderedSchemaFieldType.BELONGS_TO) {
|
|
112
112
|
const relationship = entry.object;
|
|
113
|
+
const idVariable = options.definition.getBelongsToIdVariableForRelationship(relationship.name);
|
|
113
114
|
const definition = options.definition.connection.getSchemaModelDefinitionByName(
|
|
114
115
|
relationship.foreignType.name
|
|
115
116
|
);
|
|
@@ -130,7 +131,11 @@ export class SchemaModelForm extends FormModel {
|
|
|
130
131
|
model: this.options.object,
|
|
131
132
|
input: entity,
|
|
132
133
|
resolve: () => {
|
|
133
|
-
if (
|
|
134
|
+
if (idVariable && options.object?.model) {
|
|
135
|
+
const objectId = options.object.model[idVariable.name];
|
|
136
|
+
return objectId ? definition.resolve(objectId) : null;
|
|
137
|
+
}
|
|
138
|
+
if (!options.object?.data?.belongs_to?.[relationship.name]) {
|
|
134
139
|
return null;
|
|
135
140
|
}
|
|
136
141
|
return definition.resolve(options.object.data.belongs_to[relationship.name]);
|
|
@@ -36,8 +36,10 @@ export class SharedModelPanelModel extends ReactorPanelModel {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async decodeEntities(data: ReturnType<this['encodeEntities']>) {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const definition = data.definition;
|
|
40
|
+
const model = definition ? data.model || (await definition.generateNewModelObject()) : null;
|
|
41
|
+
this.definition = definition;
|
|
42
|
+
this.model = model;
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -42,7 +42,7 @@ export const ModelPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props
|
|
|
42
42
|
const _theme = ioc.get(ThemeStore).getCurrentTheme(theme);
|
|
43
43
|
|
|
44
44
|
useEffect(() => {
|
|
45
|
-
if (!props.model.definition) {
|
|
45
|
+
if (!props.model.definition || !props.model.model) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
let _form = new SchemaModelForm({
|
|
@@ -95,8 +95,8 @@ export const ModelPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props
|
|
|
95
95
|
label="Save"
|
|
96
96
|
icon="save"
|
|
97
97
|
iconColor={_theme.status.success}
|
|
98
|
-
action={() => {
|
|
99
|
-
props.model.model.save();
|
|
98
|
+
action={async () => {
|
|
99
|
+
await props.model.model.save();
|
|
100
100
|
}}
|
|
101
101
|
/>
|
|
102
102
|
<PanelButtonWidget
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BooleanSetting,
|
|
4
|
+
IconWidget,
|
|
5
|
+
ioc,
|
|
6
|
+
PanelButtonMode,
|
|
7
|
+
PanelButtonWidget,
|
|
8
|
+
PrefsStore,
|
|
9
|
+
styled
|
|
10
|
+
} from '@journeyapps-labs/reactor-mod';
|
|
3
11
|
import { AbstractQuery } from '../../core/query/AbstractQuery';
|
|
4
12
|
import { observer } from 'mobx-react';
|
|
5
13
|
import * as _ from 'lodash';
|
|
@@ -13,6 +21,7 @@ import { ChangesControlsWidget } from './table-controls/ChangesControlsWidget';
|
|
|
13
21
|
import { FilterControlsWidget } from './table-controls/FilterControlsWidget';
|
|
14
22
|
import { QueryControlPreferences } from '../../preferences/QueryControlPreferences';
|
|
15
23
|
import { SelectionControlsWidget } from './table-controls/SelectionControlsWidget';
|
|
24
|
+
import { CreateModelAction } from '../../actions/schema-definitions/CreateModelAction';
|
|
16
25
|
|
|
17
26
|
export interface TableControlsWidgetProps {
|
|
18
27
|
current_page: Page;
|
|
@@ -39,9 +48,20 @@ export const TableControlsWidget: React.FC<TableControlsWidgetProps> = observer(
|
|
|
39
48
|
const showFilterControls = prefsStore.getPreference<BooleanSetting>(
|
|
40
49
|
QueryControlPreferences.SHOW_FILTER_CONTROLS
|
|
41
50
|
).checked;
|
|
51
|
+
const createModelButton = simpleQuery?.options.definition
|
|
52
|
+
? CreateModelAction.get().renderAsButton(
|
|
53
|
+
(btn) => {
|
|
54
|
+
return <PanelButtonWidget {...btn} label="Create model" mode={PanelButtonMode.PRIMARY} />;
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
targetEntity: simpleQuery.options.definition
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
: null;
|
|
42
61
|
|
|
43
62
|
return (
|
|
44
63
|
<S.Container className={props.className}>
|
|
64
|
+
{createModelButton}
|
|
45
65
|
<PageControlsWidget query={props.query} currentPage={props.current_page} goToPage={props.goToPage} />
|
|
46
66
|
<QueryControlsWidget
|
|
47
67
|
query={props.query}
|
|
@@ -69,7 +89,7 @@ namespace S {
|
|
|
69
89
|
column-gap: 20px;
|
|
70
90
|
row-gap: 20px;
|
|
71
91
|
padding: 5px 5px;
|
|
72
|
-
align-items:
|
|
92
|
+
align-items: flex-end;
|
|
73
93
|
flex-wrap: wrap;
|
|
74
94
|
`;
|
|
75
95
|
|
|
@@ -21,6 +21,9 @@ export interface PageControlsWidgetProps {
|
|
|
21
21
|
export const PageControlsWidget: React.FC<PageControlsWidgetProps> = observer((props) => {
|
|
22
22
|
const hasCurrentPage = !!props.currentPage;
|
|
23
23
|
const currentPageIndex = props.currentPage?.index ?? 0;
|
|
24
|
+
const totalPages = props.query.totalPages;
|
|
25
|
+
const totalPagesLoading = totalPages === 0 && !!props.currentPage?.loading;
|
|
26
|
+
const canGoNext = hasCurrentPage && totalPages > currentPageIndex + 1;
|
|
24
27
|
|
|
25
28
|
return (
|
|
26
29
|
<InputContainerWidget label="Page">
|
|
@@ -36,7 +39,7 @@ export const PageControlsWidget: React.FC<PageControlsWidgetProps> = observer((p
|
|
|
36
39
|
}}
|
|
37
40
|
/>
|
|
38
41
|
<PanelButtonWidget
|
|
39
|
-
disabled={!
|
|
42
|
+
disabled={!canGoNext}
|
|
40
43
|
label="Next"
|
|
41
44
|
action={() => {
|
|
42
45
|
if (!hasCurrentPage) {
|
|
@@ -47,20 +50,19 @@ export const PageControlsWidget: React.FC<PageControlsWidgetProps> = observer((p
|
|
|
47
50
|
/>
|
|
48
51
|
<S.PageSelector>
|
|
49
52
|
<PanelDropdownWidget
|
|
53
|
+
disabled={totalPages === 0}
|
|
50
54
|
onChange={({ key }) => {
|
|
51
55
|
props.goToPage?.(parseInt(key));
|
|
52
56
|
}}
|
|
53
57
|
selected={`${currentPageIndex}`}
|
|
54
|
-
items={_.range(0,
|
|
58
|
+
items={_.range(0, totalPages).map((r) => {
|
|
55
59
|
return {
|
|
56
60
|
title: `${r + 1}`,
|
|
57
61
|
key: `${r}`
|
|
58
62
|
} as ComboBoxItem;
|
|
59
63
|
})}
|
|
60
64
|
/>
|
|
61
|
-
<S.TotalPages>
|
|
62
|
-
/ {props.query.totalPages === 0 ? <S.Spinner icon="spinner" spin={true} /> : props.query.totalPages}
|
|
63
|
-
</S.TotalPages>
|
|
65
|
+
<S.TotalPages>/ {totalPagesLoading ? <S.Spinner icon="spinner" spin={true} /> : totalPages}</S.TotalPages>
|
|
64
66
|
</S.PageSelector>
|
|
65
67
|
</S.Group>
|
|
66
68
|
</InputContainerWidget>
|