@journeyapps-labs/reactor-mod-data-browser 3.3.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/@types/actions/schema-model/ViewHasManyAction.d.ts +12 -0
  3. package/dist/@types/core/AbstractConnection.d.ts +1 -0
  4. package/dist/@types/core/SchemaModelDefinition.d.ts +32 -5
  5. package/dist/@types/core/query/StandardModelFields.d.ts +4 -0
  6. package/dist/@types/core/query/query-simple/SimpleQueryFilterState.d.ts +4 -6
  7. package/dist/@types/core/query/widgets/BelongsToDisplayWidget.d.ts +1 -0
  8. package/dist/@types/core/query/widgets/ColumnDisplayWidget.d.ts +1 -0
  9. package/dist/@types/core/query/widgets/IDCellDisplayWidget.d.ts +5 -0
  10. package/dist/@types/core/query/widgets/PeekRelationshipButton.d.ts +1 -0
  11. package/dist/@types/core/query/widgets/SmartBelongsToDisplayWidget.d.ts +2 -0
  12. package/dist/@types/core/query/widgets/SmartColumnWidget.d.ts +7 -2
  13. package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
  14. package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +2 -1
  15. package/dist/@types/entities/SchemaModelTreePresenterComponent.d.ts +10 -0
  16. package/dist/@types/forms/types/belongs-to-filter.d.ts +10 -0
  17. package/dist/@types/forms/types/shared/type-handler.d.ts +1 -0
  18. package/dist/@types/index.d.ts +1 -0
  19. package/dist/@types/preferences/QueryControlPreferences.d.ts +14 -2
  20. package/dist/@types/preferences/SchemaOrderingPreferences.d.ts +22 -0
  21. package/dist/DataBrowserModule.js +4 -0
  22. package/dist/DataBrowserModule.js.map +1 -1
  23. package/dist/actions/schema-model/ViewHasManyAction.js +112 -0
  24. package/dist/actions/schema-model/ViewHasManyAction.js.map +1 -0
  25. package/dist/core/AbstractConnection.js +11 -3
  26. package/dist/core/AbstractConnection.js.map +1 -1
  27. package/dist/core/SchemaModelDefinition.js +121 -7
  28. package/dist/core/SchemaModelDefinition.js.map +1 -1
  29. package/dist/core/query/StandardModelFields.js +3 -0
  30. package/dist/core/query/StandardModelFields.js.map +1 -1
  31. package/dist/core/query/query-simple/SimpleQueryColumns.js +74 -42
  32. package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
  33. package/dist/core/query/query-simple/SimpleQueryFilterState.js +35 -7
  34. package/dist/core/query/query-simple/SimpleQueryFilterState.js.map +1 -1
  35. package/dist/core/query/query-simple/SimpleQuerySortState.js +0 -1
  36. package/dist/core/query/query-simple/SimpleQuerySortState.js.map +1 -1
  37. package/dist/core/query/widgets/BelongsToDisplayWidget.js +1 -1
  38. package/dist/core/query/widgets/BelongsToDisplayWidget.js.map +1 -1
  39. package/dist/core/query/widgets/ColumnDisplayWidget.js +13 -2
  40. package/dist/core/query/widgets/ColumnDisplayWidget.js.map +1 -1
  41. package/dist/core/query/widgets/IDCellDisplayWidget.js +38 -0
  42. package/dist/core/query/widgets/IDCellDisplayWidget.js.map +1 -0
  43. package/dist/core/query/widgets/PeekRelationshipButton.js +23 -16
  44. package/dist/core/query/widgets/PeekRelationshipButton.js.map +1 -1
  45. package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js +1 -1
  46. package/dist/core/query/widgets/SmartBelongsToDisplayWidget.js.map +1 -1
  47. package/dist/core/query/widgets/SmartColumnWidget.js +3 -13
  48. package/dist/core/query/widgets/SmartColumnWidget.js.map +1 -1
  49. package/dist/core/query/widgets/SmartFilterWidget.js +10 -7
  50. package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
  51. package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -10
  52. package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
  53. package/dist/entities/SchemaModelObjectEntityDefinition.js +15 -14
  54. package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
  55. package/dist/entities/SchemaModelTreePresenterComponent.js +23 -0
  56. package/dist/entities/SchemaModelTreePresenterComponent.js.map +1 -0
  57. package/dist/forms/SchemaModelForm.js +31 -29
  58. package/dist/forms/SchemaModelForm.js.map +1 -1
  59. package/dist/forms/types/attachment-handler.js +1 -0
  60. package/dist/forms/types/attachment-handler.js.map +1 -1
  61. package/dist/forms/types/belongs-to-filter.js +57 -0
  62. package/dist/forms/types/belongs-to-filter.js.map +1 -0
  63. package/dist/forms/types/boolean-handler.js +34 -1
  64. package/dist/forms/types/boolean-handler.js.map +1 -1
  65. package/dist/forms/types/date-handler.js +1 -0
  66. package/dist/forms/types/date-handler.js.map +1 -1
  67. package/dist/forms/types/image-handler.js +1 -0
  68. package/dist/forms/types/image-handler.js.map +1 -1
  69. package/dist/forms/types/location-handler.js +1 -0
  70. package/dist/forms/types/location-handler.js.map +1 -1
  71. package/dist/forms/types/multiple-choice-handler.js +1 -0
  72. package/dist/forms/types/multiple-choice-handler.js.map +1 -1
  73. package/dist/forms/types/multiple-choice-integer-handler.js +1 -0
  74. package/dist/forms/types/multiple-choice-integer-handler.js.map +1 -1
  75. package/dist/forms/types/number-handler.js +3 -2
  76. package/dist/forms/types/number-handler.js.map +1 -1
  77. package/dist/forms/types/single-choice-handler.js +1 -0
  78. package/dist/forms/types/single-choice-handler.js.map +1 -1
  79. package/dist/forms/types/single-choice-integer-handler.js +1 -0
  80. package/dist/forms/types/single-choice-integer-handler.js.map +1 -1
  81. package/dist/forms/types/text-handler.js +1 -0
  82. package/dist/forms/types/text-handler.js.map +1 -1
  83. package/dist/index.js +1 -0
  84. package/dist/index.js.map +1 -1
  85. package/dist/panels/query/QueryPanelWidget.js +14 -9
  86. package/dist/panels/query/QueryPanelWidget.js.map +1 -1
  87. package/dist/panels/query/table-controls/FilterControlsWidget.js +1 -0
  88. package/dist/panels/query/table-controls/FilterControlsWidget.js.map +1 -1
  89. package/dist/preferences/QueryControlPreferences.js +45 -1
  90. package/dist/preferences/QueryControlPreferences.js.map +1 -1
  91. package/dist/preferences/SchemaOrderingPreferences.js +76 -0
  92. package/dist/preferences/SchemaOrderingPreferences.js.map +1 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/dist-module/bundle.js +51 -35
  95. package/dist-module/bundle.js.map +1 -1
  96. package/package.json +7 -6
  97. package/src/DataBrowserModule.ts +4 -0
  98. package/src/actions/schema-model/ViewHasManyAction.ts +114 -0
  99. package/src/core/AbstractConnection.ts +12 -3
  100. package/src/core/SchemaModelDefinition.ts +165 -9
  101. package/src/core/query/StandardModelFields.ts +8 -0
  102. package/src/core/query/query-simple/SimpleQueryColumns.tsx +103 -58
  103. package/src/core/query/query-simple/SimpleQueryFilterState.ts +42 -9
  104. package/src/core/query/query-simple/SimpleQuerySortState.ts +0 -1
  105. package/src/core/query/widgets/BelongsToDisplayWidget.tsx +2 -1
  106. package/src/core/query/widgets/ColumnDisplayWidget.tsx +17 -4
  107. package/src/core/query/widgets/IDCellDisplayWidget.tsx +59 -0
  108. package/src/core/query/widgets/PeekRelationshipButton.tsx +23 -16
  109. package/src/core/query/widgets/SmartBelongsToDisplayWidget.tsx +3 -0
  110. package/src/core/query/widgets/SmartColumnWidget.tsx +23 -20
  111. package/src/core/query/widgets/SmartFilterWidget.tsx +14 -5
  112. package/src/entities/SchemaModelDefinitionEntityDefinition.ts +3 -13
  113. package/src/entities/SchemaModelObjectEntityDefinition.ts +17 -15
  114. package/src/entities/SchemaModelTreePresenterComponent.ts +31 -0
  115. package/src/forms/SchemaModelForm.tsx +46 -41
  116. package/src/forms/types/attachment-handler.tsx +1 -0
  117. package/src/forms/types/belongs-to-filter.tsx +84 -0
  118. package/src/forms/types/boolean-handler.tsx +46 -2
  119. package/src/forms/types/date-handler.tsx +1 -0
  120. package/src/forms/types/image-handler.tsx +1 -0
  121. package/src/forms/types/location-handler.tsx +1 -0
  122. package/src/forms/types/multiple-choice-handler.tsx +1 -0
  123. package/src/forms/types/multiple-choice-integer-handler.tsx +1 -0
  124. package/src/forms/types/number-handler.tsx +3 -2
  125. package/src/forms/types/shared/type-handler.ts +1 -0
  126. package/src/forms/types/single-choice-handler.tsx +1 -0
  127. package/src/forms/types/single-choice-integer-handler.tsx +1 -0
  128. package/src/forms/types/text-handler.tsx +1 -0
  129. package/src/index.ts +1 -0
  130. package/src/panels/query/QueryPanelWidget.tsx +24 -22
  131. package/src/panels/query/table-controls/FilterControlsWidget.tsx +1 -0
  132. package/src/preferences/QueryControlPreferences.ts +51 -2
  133. package/src/preferences/SchemaOrderingPreferences.ts +82 -0
@@ -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(): { key: string; label: string }[] {
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.resolveAttribute(field);
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 = _.find(_.values(definition.definition.attributes), (attribute) => {
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.resolveAttribute(field);
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 variable = this.resolveAttribute(field);
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 resolveAttribute(field: string): Variable | undefined {
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.Label
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
- </S.Label>
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 Label = styled.div<{ minWidth?: number; clickable: boolean; nowrap: boolean }>`
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
- disabled: true,
93
- group: 'Object'
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
- key: 'copy',
119
- title: 'Copy ID',
120
- icon: 'copy',
121
- group: 'Actions',
122
- action: async () => {
123
- copyTextToClipboard(props.object.id);
124
- notifications.showNotification({
125
- title: 'Copied',
126
- description: 'Relationship ID copied to clipboard',
127
- type: NotificationType.SUCCESS
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 { ObjectType, Variable } from '@journeyapps/db';
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
- type?: ObjectType;
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
- {display}
36
- <SmartFilterWidget filter={props.filter} variable={props.variable} filterChanged={props.filterChanged} />
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 handler.setupFilter?.({
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
- InlineTreePresenterComponent,
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
+ }