@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.
- package/CHANGELOG.md +27 -0
- package/dist/@types/actions/schema-model/ViewHasManyAction.d.ts +12 -0
- package/dist/@types/core/AbstractConnection.d.ts +1 -0
- package/dist/@types/core/SchemaModelDefinition.d.ts +32 -5
- package/dist/@types/core/query/StandardModelFields.d.ts +4 -0
- package/dist/@types/core/query/query-simple/SimpleQueryFilterState.d.ts +4 -6
- package/dist/@types/core/query/widgets/BelongsToDisplayWidget.d.ts +1 -0
- package/dist/@types/core/query/widgets/ColumnDisplayWidget.d.ts +1 -0
- package/dist/@types/core/query/widgets/IDCellDisplayWidget.d.ts +5 -0
- package/dist/@types/core/query/widgets/PeekRelationshipButton.d.ts +1 -0
- package/dist/@types/core/query/widgets/SmartBelongsToDisplayWidget.d.ts +2 -0
- package/dist/@types/core/query/widgets/SmartColumnWidget.d.ts +7 -2
- package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
- package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +2 -1
- package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
- package/dist/@types/forms/types/belongs-to-filter.d.ts +10 -0
- package/dist/@types/forms/types/shared/type-handler.d.ts +1 -0
- package/dist/@types/index.d.ts +1 -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/ViewHasManyAction.js +112 -0
- package/dist/actions/schema-model/ViewHasManyAction.js.map +1 -0
- package/dist/core/AbstractConnection.js +11 -3
- package/dist/core/AbstractConnection.js.map +1 -1
- package/dist/core/SchemaModelDefinition.js +121 -7
- package/dist/core/SchemaModelDefinition.js.map +1 -1
- package/dist/core/query/StandardModelFields.js +3 -0
- package/dist/core/query/StandardModelFields.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQueryColumns.js +74 -42
- package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQueryFilterState.js +35 -7
- package/dist/core/query/query-simple/SimpleQueryFilterState.js.map +1 -1
- package/dist/core/query/query-simple/SimpleQuerySortState.js +0 -1
- package/dist/core/query/query-simple/SimpleQuerySortState.js.map +1 -1
- package/dist/core/query/widgets/BelongsToDisplayWidget.js +1 -1
- package/dist/core/query/widgets/BelongsToDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/ColumnDisplayWidget.js +13 -2
- package/dist/core/query/widgets/ColumnDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/IDCellDisplayWidget.js +38 -0
- package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -0
- package/dist/core/query/widgets/PeekRelationshipButton.js +23 -16
- package/dist/core/query/widgets/PeekRelationshipButton.js.map +1 -1
- package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js +1 -1
- package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js.map +1 -1
- package/dist/core/query/widgets/SmartColumnWidget.js +3 -13
- package/dist/core/query/widgets/SmartColumnWidget.js.map +1 -1
- package/dist/core/query/widgets/SmartFilterWidget.js +10 -7
- package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelObjectEntityDefinition.js +15 -14
- 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/forms/types/attachment-handler.js +1 -0
- package/dist/forms/types/attachment-handler.js.map +1 -1
- package/dist/forms/types/belongs-to-filter.js +57 -0
- package/dist/forms/types/belongs-to-filter.js.map +1 -0
- package/dist/forms/types/boolean-handler.js +34 -1
- package/dist/forms/types/boolean-handler.js.map +1 -1
- package/dist/forms/types/date-handler.js +1 -0
- package/dist/forms/types/date-handler.js.map +1 -1
- package/dist/forms/types/image-handler.js +1 -0
- package/dist/forms/types/image-handler.js.map +1 -1
- package/dist/forms/types/location-handler.js +1 -0
- package/dist/forms/types/location-handler.js.map +1 -1
- package/dist/forms/types/multiple-choice-handler.js +1 -0
- package/dist/forms/types/multiple-choice-handler.js.map +1 -1
- package/dist/forms/types/multiple-choice-integer-handler.js +1 -0
- package/dist/forms/types/multiple-choice-integer-handler.js.map +1 -1
- package/dist/forms/types/number-handler.js +3 -2
- package/dist/forms/types/number-handler.js.map +1 -1
- package/dist/forms/types/single-choice-handler.js +1 -0
- package/dist/forms/types/single-choice-handler.js.map +1 -1
- package/dist/forms/types/single-choice-integer-handler.js +1 -0
- package/dist/forms/types/single-choice-integer-handler.js.map +1 -1
- package/dist/forms/types/text-handler.js +1 -0
- package/dist/forms/types/text-handler.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/panels/query/QueryPanelWidget.js +14 -9
- package/dist/panels/query/QueryPanelWidget.js.map +1 -1
- package/dist/panels/query/table-controls/FilterControlsWidget.js +1 -0
- package/dist/panels/query/table-controls/FilterControlsWidget.js.map +1 -1
- package/dist/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 +51 -35
- package/dist-module/bundle.js.map +1 -1
- package/package.json +7 -6
- package/src/DataBrowserModule.ts +4 -0
- package/src/actions/schema-model/ViewHasManyAction.ts +114 -0
- package/src/core/AbstractConnection.ts +12 -3
- package/src/core/SchemaModelDefinition.ts +165 -9
- package/src/core/query/StandardModelFields.ts +8 -0
- package/src/core/query/query-simple/SimpleQueryColumns.tsx +103 -58
- package/src/core/query/query-simple/SimpleQueryFilterState.ts +42 -9
- package/src/core/query/query-simple/SimpleQuerySortState.ts +0 -1
- package/src/core/query/widgets/BelongsToDisplayWidget.tsx +2 -1
- package/src/core/query/widgets/ColumnDisplayWidget.tsx +17 -4
- package/src/core/query/widgets/IDCellDisplayWidget.tsx +59 -0
- package/src/core/query/widgets/PeekRelationshipButton.tsx +23 -16
- package/src/core/query/widgets/SmartBelongsToDisplayWidget.tsx +3 -0
- package/src/core/query/widgets/SmartColumnWidget.tsx +23 -20
- package/src/core/query/widgets/SmartFilterWidget.tsx +14 -5
- package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
- package/src/entities/SchemaModelObjectEntityDefinition.ts +17 -15
- package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
- package/src/forms/SchemaModelForm.tsx +46 -41
- package/src/forms/types/attachment-handler.tsx +1 -0
- package/src/forms/types/belongs-to-filter.tsx +84 -0
- package/src/forms/types/boolean-handler.tsx +46 -2
- package/src/forms/types/date-handler.tsx +1 -0
- package/src/forms/types/image-handler.tsx +1 -0
- package/src/forms/types/location-handler.tsx +1 -0
- package/src/forms/types/multiple-choice-handler.tsx +1 -0
- package/src/forms/types/multiple-choice-integer-handler.tsx +1 -0
- package/src/forms/types/number-handler.tsx +3 -2
- package/src/forms/types/shared/type-handler.ts +1 -0
- package/src/forms/types/single-choice-handler.tsx +1 -0
- package/src/forms/types/single-choice-integer-handler.tsx +1 -0
- package/src/forms/types/text-handler.tsx +1 -0
- package/src/index.ts +1 -0
- package/src/panels/query/QueryPanelWidget.tsx +24 -22
- package/src/panels/query/table-controls/FilterControlsWidget.tsx +1 -0
- package/src/preferences/QueryControlPreferences.ts +51 -2
- package/src/preferences/SchemaOrderingPreferences.ts +82 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Variable } from '@journeyapps/db';
|
|
2
2
|
import * as _ from 'lodash';
|
|
3
3
|
import { BaseObserver } from '@journeyapps-labs/common-utils';
|
|
4
|
-
import { SchemaModelDefinition } from '../../SchemaModelDefinition';
|
|
4
|
+
import { FilterableField, SchemaModelDefinition } from '../../SchemaModelDefinition';
|
|
5
5
|
import { SerializedSimpleFilter, SimpleFilter } from '../filters';
|
|
6
6
|
import { TypeEngine } from '../../../forms/TypeEngine';
|
|
7
|
+
import { setupBelongsToFilter } from '../../../forms/types/belongs-to-filter';
|
|
8
|
+
import { idVariable, StandardModelFields } from '../StandardModelFields';
|
|
7
9
|
|
|
8
10
|
export interface SimpleQueryFilterStateListener {
|
|
9
11
|
changed: () => any;
|
|
@@ -52,7 +54,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
52
54
|
return definitionChanged || hadFilters;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
getFilterableFields():
|
|
57
|
+
getFilterableFields(): FilterableField[] {
|
|
56
58
|
if (!this.definition?.definition) {
|
|
57
59
|
return [];
|
|
58
60
|
}
|
|
@@ -69,7 +71,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
getFilter(field: string): SimpleFilter | undefined {
|
|
72
|
-
const variable = this.
|
|
74
|
+
const variable = this.resolveField(field);
|
|
73
75
|
return variable ? this.simpleFilters.get(variable) : undefined;
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -87,9 +89,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
87
89
|
if (!SimpleFilter.canDeserialize(filter)) {
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
|
-
const variable =
|
|
91
|
-
return attribute.name === filter.variable;
|
|
92
|
-
});
|
|
92
|
+
const variable = this.resolveField(filter.variable);
|
|
93
93
|
if (!variable) {
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -98,7 +98,7 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
setFilter(field: string, filter: SimpleFilter) {
|
|
101
|
-
const variable = this.
|
|
101
|
+
const variable = this.resolveField(field);
|
|
102
102
|
if (!variable) {
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
@@ -106,7 +106,21 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
async setupFilterForField(field: string, position?: MouseEvent): Promise<boolean> {
|
|
109
|
-
const
|
|
109
|
+
const relationship = this.resolveBelongsToField(field);
|
|
110
|
+
if (relationship) {
|
|
111
|
+
const existing = this.simpleFilters.get(relationship.variable);
|
|
112
|
+
const nextFilter = await setupBelongsToFilter({
|
|
113
|
+
definition: this.definition,
|
|
114
|
+
relationship: relationship.relationship,
|
|
115
|
+
variable: relationship.variable,
|
|
116
|
+
filter: existing
|
|
117
|
+
});
|
|
118
|
+
if (!nextFilter) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return this.addFilter(relationship.variable, nextFilter);
|
|
122
|
+
}
|
|
123
|
+
const variable = this.resolveField(field);
|
|
110
124
|
if (!variable) {
|
|
111
125
|
return false;
|
|
112
126
|
}
|
|
@@ -149,12 +163,31 @@ export class SimpleQueryFilterState extends BaseObserver<SimpleQueryFilterStateL
|
|
|
149
163
|
return true;
|
|
150
164
|
}
|
|
151
165
|
|
|
152
|
-
private
|
|
166
|
+
private resolveField(field: string): Variable | undefined {
|
|
153
167
|
if (!this.definition?.definition) {
|
|
154
168
|
return undefined;
|
|
155
169
|
}
|
|
170
|
+
if (field === StandardModelFields.ID) {
|
|
171
|
+
return idVariable;
|
|
172
|
+
}
|
|
173
|
+
const relationship = this.resolveBelongsToField(field);
|
|
174
|
+
if (relationship) {
|
|
175
|
+
return relationship.variable;
|
|
176
|
+
}
|
|
156
177
|
return _.find(_.values(this.definition.definition.attributes), (attribute) => {
|
|
157
178
|
return attribute.name === field;
|
|
158
179
|
});
|
|
159
180
|
}
|
|
181
|
+
|
|
182
|
+
private resolveBelongsToField(field: string):
|
|
183
|
+
| {
|
|
184
|
+
variable: Variable;
|
|
185
|
+
relationship: any;
|
|
186
|
+
}
|
|
187
|
+
| undefined {
|
|
188
|
+
if (!this.definition?.definition) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
return this.definition.getBelongsToRelationshipForField(field);
|
|
192
|
+
}
|
|
160
193
|
}
|
|
@@ -105,7 +105,6 @@ export class SimpleQuerySortState extends BaseObserver<SimpleQuerySortStateListe
|
|
|
105
105
|
};
|
|
106
106
|
});
|
|
107
107
|
return [
|
|
108
|
-
{ key: StandardModelFields.ID, label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.ID] },
|
|
109
108
|
{
|
|
110
109
|
key: StandardModelFields.UPDATED_AT,
|
|
111
110
|
label: STANDARD_MODEL_FIELD_LABELS[StandardModelFields.UPDATED_AT]
|
|
@@ -14,6 +14,7 @@ export interface BelongsToDisplayWidgetProps {
|
|
|
14
14
|
id: string;
|
|
15
15
|
connection: AbstractConnection;
|
|
16
16
|
open: (object: SchemaModelObject) => any;
|
|
17
|
+
filterBelongsTo?: (object: SchemaModelObject) => any;
|
|
17
18
|
className?: any;
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -62,7 +63,7 @@ export const BelongsToDisplayWidget: React.FC<BelongsToDisplayWidgetProps> = obs
|
|
|
62
63
|
<S.Container className={props.className}>
|
|
63
64
|
{object.data.display}
|
|
64
65
|
<S.Actions>
|
|
65
|
-
<PeekRelationshipButton object={object} open={props.open} />
|
|
66
|
+
<PeekRelationshipButton object={object} open={props.open} filterBelongsTo={props.filterBelongsTo} />
|
|
66
67
|
<TableButtonWidget
|
|
67
68
|
icon="arrow-right"
|
|
68
69
|
action={() => {
|
|
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
|
|
|
3
3
|
|
|
4
4
|
export interface ColumnDisplayWidgetProps {
|
|
5
5
|
label: string;
|
|
6
|
+
secondaryLabel?: string;
|
|
6
7
|
className?: any;
|
|
7
8
|
onClick?: () => any;
|
|
8
9
|
}
|
|
@@ -11,15 +12,16 @@ export const ColumnDisplayWidget: React.FC<ColumnDisplayWidgetProps> = (props) =
|
|
|
11
12
|
const parts = (props.label || '').split(' ');
|
|
12
13
|
const minWidth = parts.length >= 5 ? 150 : parts.length >= 3 ? 80 : undefined;
|
|
13
14
|
return (
|
|
14
|
-
<S.
|
|
15
|
+
<S.Container
|
|
15
16
|
className={props.className}
|
|
16
17
|
minWidth={minWidth}
|
|
17
18
|
clickable={!!props.onClick}
|
|
18
19
|
nowrap={!minWidth}
|
|
19
20
|
onClick={props.onClick}
|
|
20
21
|
>
|
|
21
|
-
{props.label}
|
|
22
|
-
|
|
22
|
+
<S.Label>{props.label}</S.Label>
|
|
23
|
+
{props.secondaryLabel ? <S.SecondaryLabel>{props.secondaryLabel}</S.SecondaryLabel> : null}
|
|
24
|
+
</S.Container>
|
|
23
25
|
);
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -32,9 +34,20 @@ namespace S {
|
|
|
32
34
|
}
|
|
33
35
|
`;
|
|
34
36
|
|
|
35
|
-
export const
|
|
37
|
+
export const Container = styled.div<{ minWidth?: number; clickable: boolean; nowrap: boolean }>`
|
|
36
38
|
${(p) => (p.minWidth ? `min-width: ${p.minWidth}px;` : '')};
|
|
37
39
|
${(p) => (p.nowrap ? 'white-space: nowrap;' : '')};
|
|
38
40
|
${(p) => (p.clickable ? clickableStyle : '')};
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
align-items: flex-start;
|
|
44
|
+
row-gap: 2px;
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
export const Label = styled.div``;
|
|
48
|
+
|
|
49
|
+
export const SecondaryLabel = styled.div`
|
|
50
|
+
opacity: 0.4;
|
|
51
|
+
font-size: 12px;
|
|
39
52
|
`;
|
|
40
53
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
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';
|
|
12
|
+
import { copyTextToClipboard } from '@journeyapps-labs/lib-reactor-utils';
|
|
13
|
+
import { QueryControlPreferences } from '../../../preferences/QueryControlPreferences';
|
|
14
|
+
|
|
15
|
+
export interface IDCellDisplayWidgetProps {
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const IDCellDisplayWidget: React.FC<IDCellDisplayWidgetProps> = observer((props) => {
|
|
20
|
+
const notifications = ioc.get(NotificationStore);
|
|
21
|
+
const showIdValue = ioc
|
|
22
|
+
.get(PrefsStore)
|
|
23
|
+
.getPreference<BooleanSetting>(QueryControlPreferences.SHOW_ID_VALUE_IN_ID_COLUMN).checked;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<S.Container>
|
|
27
|
+
{showIdValue ? <S.Value>{props.id}</S.Value> : null}
|
|
28
|
+
<TableButtonWidget
|
|
29
|
+
icon="copy"
|
|
30
|
+
tooltip="Copy ID"
|
|
31
|
+
action={() => {
|
|
32
|
+
copyTextToClipboard(props.id);
|
|
33
|
+
notifications.showNotification({
|
|
34
|
+
title: 'Copied',
|
|
35
|
+
description: 'ID copied to clipboard',
|
|
36
|
+
type: NotificationType.SUCCESS
|
|
37
|
+
});
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
</S.Container>
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
namespace S {
|
|
45
|
+
export const Container = styled.div`
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: row;
|
|
48
|
+
align-items: center;
|
|
49
|
+
justify-content: space-between;
|
|
50
|
+
column-gap: 5px;
|
|
51
|
+
width: 100%;
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
export const Value = styled.div`
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
text-overflow: ellipsis;
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
@@ -21,6 +21,7 @@ import { EmptyValueWidget } from '../../../widgets/EmptyValueWidget';
|
|
|
21
21
|
export interface PeekRelationshipButtonProps {
|
|
22
22
|
object: SchemaModelObject;
|
|
23
23
|
open: (object: SchemaModelObject) => any;
|
|
24
|
+
filterBelongsTo?: (object: SchemaModelObject) => any;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export const PeekRelationshipButton: React.FC<PeekRelationshipButtonProps> = (props) => {
|
|
@@ -89,8 +90,15 @@ export const PeekRelationshipButton: React.FC<PeekRelationshipButtonProps> = (pr
|
|
|
89
90
|
title: 'ID',
|
|
90
91
|
icon: 'copy',
|
|
91
92
|
right: <S.FieldValue>{props.object.id}</S.FieldValue>,
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
group: 'Object',
|
|
94
|
+
action: async () => {
|
|
95
|
+
copyTextToClipboard(props.object.id);
|
|
96
|
+
notifications.showNotification({
|
|
97
|
+
title: 'Copied',
|
|
98
|
+
description: 'Relationship ID copied to clipboard',
|
|
99
|
+
type: NotificationType.SUCCESS
|
|
100
|
+
});
|
|
101
|
+
}
|
|
94
102
|
},
|
|
95
103
|
{
|
|
96
104
|
key: 'meta-updated',
|
|
@@ -114,20 +122,19 @@ export const PeekRelationshipButton: React.FC<PeekRelationshipButtonProps> = (pr
|
|
|
114
122
|
props.open(props.object);
|
|
115
123
|
}
|
|
116
124
|
},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
125
|
+
...(props.filterBelongsTo
|
|
126
|
+
? [
|
|
127
|
+
{
|
|
128
|
+
key: 'filter-belongs-to',
|
|
129
|
+
title: 'Filter belongs to',
|
|
130
|
+
icon: 'filter',
|
|
131
|
+
group: 'Actions',
|
|
132
|
+
action: async () => {
|
|
133
|
+
await props.filterBelongsTo?.(props.object);
|
|
134
|
+
}
|
|
135
|
+
} as ComboBoxItem
|
|
136
|
+
]
|
|
137
|
+
: [])
|
|
131
138
|
];
|
|
132
139
|
const directive = await ioc.get(ComboBoxStore2).show(
|
|
133
140
|
new SimpleComboBoxDirective({
|
|
@@ -4,6 +4,7 @@ import { BelongsToDisplayWidget } from './BelongsToDisplayWidget';
|
|
|
4
4
|
import { PageRow } from '../Page';
|
|
5
5
|
import { ActionSource, styled } from '@journeyapps-labs/reactor-mod';
|
|
6
6
|
import { AbstractConnection } from '../../AbstractConnection';
|
|
7
|
+
import { SchemaModelObject } from '../../SchemaModelObject';
|
|
7
8
|
import { Variable } from '@journeyapps/db';
|
|
8
9
|
import { observer } from 'mobx-react';
|
|
9
10
|
|
|
@@ -11,6 +12,7 @@ export interface SmartBelongsToDisplayWidgetProps {
|
|
|
11
12
|
row: PageRow;
|
|
12
13
|
connection: AbstractConnection;
|
|
13
14
|
variable_id: Variable;
|
|
15
|
+
filterBelongsTo?: (object: SchemaModelObject) => any;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export const SmartBelongsToDisplayWidget: React.FC<SmartBelongsToDisplayWidgetProps> = observer((props) => {
|
|
@@ -35,6 +37,7 @@ export const SmartBelongsToDisplayWidget: React.FC<SmartBelongsToDisplayWidgetPr
|
|
|
35
37
|
relationship={row.model.definition.definition.belongsTo[variable_id.relationship]}
|
|
36
38
|
connection={connection}
|
|
37
39
|
id={value}
|
|
40
|
+
filterBelongsTo={props.filterBelongsTo}
|
|
38
41
|
/>
|
|
39
42
|
);
|
|
40
43
|
});
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
|
-
import {
|
|
3
|
+
import { Variable } from '@journeyapps/db';
|
|
4
4
|
import { ColumnDisplayWidget } from './ColumnDisplayWidget';
|
|
5
|
-
import { SmartFilterWidget } from './SmartFilterWidget';
|
|
5
|
+
import { SmartFilterWidget, SmartTypeEngineFilterWidget } from './SmartFilterWidget';
|
|
6
6
|
import { SimpleFilter } from '../filters';
|
|
7
7
|
import { SortDirection } from '../query-simple/SimpleQuery';
|
|
8
8
|
|
|
9
9
|
export interface SmartColumnWidgetProps {
|
|
10
10
|
variable: Variable;
|
|
11
|
-
|
|
11
|
+
typeLabel?: string;
|
|
12
12
|
filter?: SimpleFilter;
|
|
13
13
|
sortDirection?: SortDirection;
|
|
14
14
|
onToggleSort?: () => Promise<any> | any;
|
|
15
|
+
setupFilter?: (event: {
|
|
16
|
+
variable: Variable;
|
|
17
|
+
filter?: SimpleFilter;
|
|
18
|
+
position?: MouseEvent;
|
|
19
|
+
}) => Promise<SimpleFilter | null>;
|
|
15
20
|
filterChanged: (filter: SimpleFilter | null) => any;
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -20,20 +25,24 @@ export const SmartColumnWidget: React.FC<SmartColumnWidgetProps> = (props) => {
|
|
|
20
25
|
const displayLabel = props.sortDirection
|
|
21
26
|
? `${baseLabel} ${props.sortDirection === SortDirection.ASC ? '↓' : '↑'}`
|
|
22
27
|
: baseLabel;
|
|
23
|
-
let display = <ColumnDisplayWidget label={displayLabel} onClick={props.onToggleSort} />;
|
|
24
|
-
if (props.type) {
|
|
25
|
-
display = (
|
|
26
|
-
<S.TypeGroup>
|
|
27
|
-
{display}
|
|
28
|
-
<S.Type label={props.type.label} />
|
|
29
|
-
</S.TypeGroup>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
28
|
return (
|
|
33
29
|
<S.Container>
|
|
34
30
|
<S.TopRow>
|
|
35
|
-
{
|
|
36
|
-
|
|
31
|
+
<ColumnDisplayWidget label={displayLabel} secondaryLabel={props.typeLabel} onClick={props.onToggleSort} />
|
|
32
|
+
{props.setupFilter ? (
|
|
33
|
+
<SmartFilterWidget
|
|
34
|
+
filter={props.filter}
|
|
35
|
+
variable={props.variable}
|
|
36
|
+
setupFilter={props.setupFilter}
|
|
37
|
+
filterChanged={props.filterChanged}
|
|
38
|
+
/>
|
|
39
|
+
) : (
|
|
40
|
+
<SmartTypeEngineFilterWidget
|
|
41
|
+
filter={props.filter}
|
|
42
|
+
variable={props.variable}
|
|
43
|
+
filterChanged={props.filterChanged}
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
37
46
|
</S.TopRow>
|
|
38
47
|
</S.Container>
|
|
39
48
|
);
|
|
@@ -54,12 +63,6 @@ namespace S {
|
|
|
54
63
|
column-gap: 5px;
|
|
55
64
|
`;
|
|
56
65
|
|
|
57
|
-
export const Type = styled(ColumnDisplayWidget)`
|
|
58
|
-
opacity: 0.5;
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
export const TypeGroup = styled.div``;
|
|
62
|
-
|
|
63
66
|
export const FilterMetaRow = styled.div`
|
|
64
67
|
display: flex;
|
|
65
68
|
align-items: center;
|
|
@@ -15,6 +15,11 @@ import { SimpleFilter, StatementMatch } from '../filters';
|
|
|
15
15
|
export interface SmartFilterWidgetProps {
|
|
16
16
|
variable: Variable;
|
|
17
17
|
filter?: SimpleFilter;
|
|
18
|
+
setupFilter: (event: {
|
|
19
|
+
variable: Variable;
|
|
20
|
+
filter?: SimpleFilter;
|
|
21
|
+
position?: MouseEvent;
|
|
22
|
+
}) => Promise<SimpleFilter | null>;
|
|
18
23
|
filterChanged: (filter: SimpleFilter | null) => any;
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -63,10 +68,6 @@ export const SmartFilterMetadataWidget: React.FC<SmartFilterMetadataWidgetProps>
|
|
|
63
68
|
|
|
64
69
|
export const SmartFilterWidget: React.FC<SmartFilterWidgetProps> = (props) => {
|
|
65
70
|
const isActive = (props.filter?.statements?.length || 0) > 0;
|
|
66
|
-
const handler = ioc.get(TypeEngine).getHandler(props.variable.type);
|
|
67
|
-
if (!handler?.setupFilter) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
71
|
return (
|
|
71
72
|
<S.FilterButton
|
|
72
73
|
active={isActive}
|
|
@@ -75,7 +76,7 @@ export const SmartFilterWidget: React.FC<SmartFilterWidgetProps> = (props) => {
|
|
|
75
76
|
tooltipPos: TooltipPosition.BOTTOM
|
|
76
77
|
})}
|
|
77
78
|
onClick={async (event) => {
|
|
78
|
-
const filter = await
|
|
79
|
+
const filter = await props.setupFilter({
|
|
79
80
|
variable: props.variable,
|
|
80
81
|
filter: props.filter,
|
|
81
82
|
position: event.nativeEvent
|
|
@@ -91,6 +92,14 @@ export const SmartFilterWidget: React.FC<SmartFilterWidgetProps> = (props) => {
|
|
|
91
92
|
);
|
|
92
93
|
};
|
|
93
94
|
|
|
95
|
+
export const SmartTypeEngineFilterWidget: React.FC<Omit<SmartFilterWidgetProps, 'setupFilter'>> = (props) => {
|
|
96
|
+
const setupFilter = ioc.get(TypeEngine).getHandler(props.variable.type)?.setupFilter;
|
|
97
|
+
if (!setupFilter) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return <SmartFilterWidget {...props} setupFilter={setupFilter} />;
|
|
101
|
+
};
|
|
102
|
+
|
|
94
103
|
namespace S {
|
|
95
104
|
export const MetaList = styled.div`
|
|
96
105
|
display: flex;
|
|
@@ -3,9 +3,8 @@ import {
|
|
|
3
3
|
EntityActionHandlerComponent,
|
|
4
4
|
EntityDefinition,
|
|
5
5
|
EntityDescriberComponent,
|
|
6
|
-
inject,
|
|
7
6
|
InlineEntityEncoderComponent,
|
|
8
|
-
|
|
7
|
+
inject,
|
|
9
8
|
SimpleParentEntitySearchEngine
|
|
10
9
|
} from '@journeyapps-labs/reactor-mod';
|
|
11
10
|
import { DataBrowserEntities } from '../entities';
|
|
@@ -14,6 +13,7 @@ import { AbstractConnection } from '../core/AbstractConnection';
|
|
|
14
13
|
import { SchemaModelDefinition } from '../core/SchemaModelDefinition';
|
|
15
14
|
import { QuerySchemaModelAction } from '../actions/schema-definitions/QuerySchemaModelAction';
|
|
16
15
|
import { IndexModel } from '../core/IndexModel';
|
|
16
|
+
import { SchemaModelTreePresenterComponent } from './SchemaModelTreePresenterComponent';
|
|
17
17
|
|
|
18
18
|
export interface SchemaModelDefinitionEntityDefinitionEncoded {
|
|
19
19
|
connection_id: string;
|
|
@@ -77,17 +77,7 @@ export class SchemaModelDefinitionEntityDefinition extends EntityDefinition<Sche
|
|
|
77
77
|
})
|
|
78
78
|
);
|
|
79
79
|
|
|
80
|
-
this.registerComponent(
|
|
81
|
-
new InlineTreePresenterComponent({
|
|
82
|
-
loadChildrenAsNodesAreOpened: true,
|
|
83
|
-
cacheTreeEntities: true,
|
|
84
|
-
augmentTreeNodeProps: () => {
|
|
85
|
-
return {
|
|
86
|
-
openOnSingleClick: false
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
);
|
|
80
|
+
this.registerComponent(new SchemaModelTreePresenterComponent({ loadChildrenAsNodesAreOpened: true }));
|
|
91
81
|
|
|
92
82
|
this.registerComponent(
|
|
93
83
|
new SimpleParentEntitySearchEngine<AbstractConnection, SchemaModelDefinition>({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Action,
|
|
2
3
|
EntityDefinition,
|
|
3
4
|
EntityDescriberComponent,
|
|
4
5
|
inject,
|
|
@@ -10,6 +11,8 @@ import { DataBrowserEntities } from '../entities';
|
|
|
10
11
|
import { ConnectionStore } from '../stores/ConnectionStore';
|
|
11
12
|
import { SchemaModelObject } from '../core/SchemaModelObject';
|
|
12
13
|
import { SchemaModelDefinition } from '../core/SchemaModelDefinition';
|
|
14
|
+
import { validate as validateUUID } from 'uuid';
|
|
15
|
+
import { ViewHasManyAction } from '../actions/schema-model/ViewHasManyAction';
|
|
13
16
|
|
|
14
17
|
export interface SchemaModelObjectEntityDefinitionEncoded {
|
|
15
18
|
connection_id: string;
|
|
@@ -42,21 +45,6 @@ export class SchemaModelObjectEntityDefinition extends EntityDefinition<SchemaMo
|
|
|
42
45
|
})
|
|
43
46
|
);
|
|
44
47
|
|
|
45
|
-
// this.registerComponent(
|
|
46
|
-
// new SimpleParentEntitySearchEngine<SchemaModelDefinition,SchemaModelObject>({
|
|
47
|
-
// label: 'ID',
|
|
48
|
-
// filterResultsWithMatcher: false,
|
|
49
|
-
// type: DataBrowserEntities.SCHEMA_MODEL_DEFINITION,
|
|
50
|
-
// getEntities: async (event) => {
|
|
51
|
-
// let object = await event.parameters.parent.resolve(event.value);
|
|
52
|
-
// if(object){
|
|
53
|
-
// return [object]
|
|
54
|
-
// }
|
|
55
|
-
// return []
|
|
56
|
-
// }
|
|
57
|
-
// })
|
|
58
|
-
// );
|
|
59
|
-
|
|
60
48
|
this.registerComponent(
|
|
61
49
|
new SimpleParentEntitySearchEngine<SchemaModelDefinition, SchemaModelObject>({
|
|
62
50
|
label: 'Label',
|
|
@@ -66,6 +54,13 @@ export class SchemaModelObjectEntityDefinition extends EntityDefinition<SchemaMo
|
|
|
66
54
|
if (!event.value) {
|
|
67
55
|
return [];
|
|
68
56
|
}
|
|
57
|
+
if (validateUUID(event.value)) {
|
|
58
|
+
const object = await event.parameters.parent.resolve(event.value);
|
|
59
|
+
if (object) {
|
|
60
|
+
return [object];
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
69
64
|
return await event.parameters.parent.search(event.value);
|
|
70
65
|
}
|
|
71
66
|
})
|
|
@@ -101,4 +96,11 @@ export class SchemaModelObjectEntityDefinition extends EntityDefinition<SchemaMo
|
|
|
101
96
|
getEntityUID(t: SchemaModelObject) {
|
|
102
97
|
return t.model.id;
|
|
103
98
|
}
|
|
99
|
+
|
|
100
|
+
isActionAllowedForEntity(action: Action, entity: SchemaModelObject) {
|
|
101
|
+
if (action.id === ViewHasManyAction.ID) {
|
|
102
|
+
return Object.keys(entity.definition.definition.hasMany || {}).length > 0;
|
|
103
|
+
}
|
|
104
|
+
return super.isActionAllowedForEntity(action, entity);
|
|
105
|
+
}
|
|
104
106
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CachedEntityTreePresenterContext,
|
|
3
|
+
EntityReactorNode,
|
|
4
|
+
EntityTreePresenterComponent,
|
|
5
|
+
ReactorTreeEntity
|
|
6
|
+
} from '@journeyapps-labs/reactor-mod';
|
|
7
|
+
import { SchemaModelDefinition } from '../core/SchemaModelDefinition';
|
|
8
|
+
import { SchemaModelOrderValue, SchemaModelOrderingPreference } from '../preferences/SchemaOrderingPreferences';
|
|
9
|
+
|
|
10
|
+
class SchemaModelTreePresenterContext extends CachedEntityTreePresenterContext<SchemaModelDefinition> {
|
|
11
|
+
getSortedEntities(entities: SchemaModelDefinition[]) {
|
|
12
|
+
if (SchemaModelOrderingPreference.getValue() === SchemaModelOrderValue.AS_DEFINED_IN_SCHEMA) {
|
|
13
|
+
return entities;
|
|
14
|
+
}
|
|
15
|
+
return super.getSortedEntities(entities);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected doGenerateTreeNode(entity: SchemaModelDefinition, options): ReactorTreeEntity {
|
|
19
|
+
return new EntityReactorNode({
|
|
20
|
+
entity,
|
|
21
|
+
definition: this.definition,
|
|
22
|
+
events: options?.events
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class SchemaModelTreePresenterComponent extends EntityTreePresenterComponent<SchemaModelDefinition> {
|
|
28
|
+
protected _generateContext() {
|
|
29
|
+
return new SchemaModelTreePresenterContext(this);
|
|
30
|
+
}
|
|
31
|
+
}
|