@journeyapps-labs/reactor-mod-data-browser 3.0.1 → 3.1.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 (256) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/@types/actions/connections/SetConnectionColorAction.d.ts +11 -0
  3. package/dist/@types/actions/saved-queries/OpenSavedQueryAction.d.ts +10 -0
  4. package/dist/@types/actions/saved-queries/RemoveSavedQueryAction.d.ts +9 -0
  5. package/dist/@types/core/AbstractConnection.d.ts +2 -0
  6. package/dist/@types/core/SchemaModelDefinition.d.ts +5 -0
  7. package/dist/@types/core/connection-colors.d.ts +10 -0
  8. package/dist/@types/core/query/StandardModelFields.d.ts +5 -0
  9. package/dist/@types/core/query/filters.d.ts +46 -5
  10. package/dist/@types/core/query/query-simple/SimplePage.d.ts +2 -0
  11. package/dist/@types/core/query/query-simple/SimpleQuery.d.ts +12 -3
  12. package/dist/@types/core/query/query-simple/SimpleQueryColumns.d.ts +12 -0
  13. package/dist/@types/core/query/query-simple/SimpleQueryFilterState.d.ts +37 -0
  14. package/dist/@types/core/query/query-simple/SimpleQueryPlanner.d.ts +4 -0
  15. package/dist/@types/core/query/query-simple/SimpleQuerySortState.d.ts +23 -0
  16. package/dist/@types/core/query/query-simple/SimpleQueryTypes.d.ts +24 -0
  17. package/dist/@types/core/query/widgets/ColumnDisplayWidget.d.ts +1 -0
  18. package/dist/@types/core/query/widgets/PeekRelationshipButton.d.ts +7 -0
  19. package/dist/@types/core/query/widgets/SmartColumnWidget.d.ts +3 -0
  20. package/dist/@types/core/query/widgets/SmartFilterWidget.d.ts +6 -0
  21. package/dist/@types/entities/ConnectionEntityDefinition.d.ts +2 -0
  22. package/dist/@types/entities/SavedQueryEntityDefinition.d.ts +8 -0
  23. package/dist/@types/entities.d.ts +2 -1
  24. package/dist/@types/forms/APIConnectionForm.d.ts +1 -0
  25. package/dist/@types/forms/TypeEngine.d.ts +3 -21
  26. package/dist/@types/forms/types/attachment-handler.d.ts +2 -0
  27. package/dist/@types/forms/types/boolean-handler.d.ts +2 -0
  28. package/dist/@types/forms/types/date-handler.d.ts +2 -0
  29. package/dist/@types/forms/types/filters/ClearableFilterFormDialogDirective.d.ts +10 -0
  30. package/dist/@types/forms/types/filters/ConditionalFilterForm.d.ts +23 -0
  31. package/dist/@types/forms/types/image-handler.d.ts +2 -0
  32. package/dist/@types/forms/types/location-handler.d.ts +2 -0
  33. package/dist/@types/forms/types/multiple-choice-handler.d.ts +2 -0
  34. package/dist/@types/forms/types/multiple-choice-integer-handler.d.ts +2 -0
  35. package/dist/@types/forms/types/number-handler.d.ts +2 -0
  36. package/dist/@types/forms/types/shared/type-handler.d.ts +37 -0
  37. package/dist/@types/forms/types/shared/ui.d.ts +768 -0
  38. package/dist/@types/forms/types/single-choice-handler.d.ts +2 -0
  39. package/dist/@types/forms/types/single-choice-integer-handler.d.ts +2 -0
  40. package/dist/@types/forms/types/text-handler.d.ts +3 -0
  41. package/dist/@types/index.d.ts +1 -0
  42. package/dist/@types/panels/_shared/SharedConnectionPanelFactory.d.ts +19 -0
  43. package/dist/@types/panels/_shared/SharedModelPanelFactory.d.ts +5 -2
  44. package/dist/@types/panels/query/QueryPanelFactory.d.ts +6 -2
  45. package/dist/@types/panels/query/TableControlsWidget.d.ts +2 -0
  46. package/dist/@types/panels/query/table-controls/ChangesControlsWidget.d.ts +8 -0
  47. package/dist/@types/panels/query/table-controls/FilterControlsWidget.d.ts +7 -0
  48. package/dist/@types/panels/query/table-controls/PageControlsWidget.d.ts +9 -0
  49. package/dist/@types/panels/query/table-controls/QueryControlsWidget.d.ts +11 -0
  50. package/dist/@types/panels/query/table-controls/SortChipWidget.d.ts +10 -0
  51. package/dist/@types/panels/query/table-controls/SortControlsWidget.d.ts +7 -0
  52. package/dist/@types/preferences/QueryControlPreferences.d.ts +7 -0
  53. package/dist/@types/stores/SavedQueryStore.d.ts +34 -0
  54. package/dist/@types/widgets/EmptyValueWidget.d.ts +7 -0
  55. package/dist/DataBrowserModule.js +21 -7
  56. package/dist/DataBrowserModule.js.map +1 -1
  57. package/dist/actions/connections/AddConnectionAction.js +2 -2
  58. package/dist/actions/connections/AddConnectionAction.js.map +1 -1
  59. package/dist/actions/connections/RemoveConnectionAction.js +2 -2
  60. package/dist/actions/connections/RemoveConnectionAction.js.map +1 -1
  61. package/dist/actions/connections/SetConnectionColorAction.js +63 -0
  62. package/dist/actions/connections/SetConnectionColorAction.js.map +1 -0
  63. package/dist/actions/saved-queries/OpenSavedQueryAction.js +58 -0
  64. package/dist/actions/saved-queries/OpenSavedQueryAction.js.map +1 -0
  65. package/dist/actions/saved-queries/RemoveSavedQueryAction.js +43 -0
  66. package/dist/actions/saved-queries/RemoveSavedQueryAction.js.map +1 -0
  67. package/dist/actions/schema-definitions/CreateModelAction.js +2 -2
  68. package/dist/actions/schema-definitions/CreateModelAction.js.map +1 -1
  69. package/dist/actions/schema-definitions/QuerySchemaModelAction.js +2 -2
  70. package/dist/actions/schema-definitions/QuerySchemaModelAction.js.map +1 -1
  71. package/dist/actions/schema-model/EditSchemaModelAction.js +2 -2
  72. package/dist/actions/schema-model/EditSchemaModelAction.js.map +1 -1
  73. package/dist/actions/schema-model/ViewSchemaModelAsJsonAction.js +2 -2
  74. package/dist/actions/schema-model/ViewSchemaModelAsJsonAction.js.map +1 -1
  75. package/dist/core/AbstractConnection.js +116 -90
  76. package/dist/core/AbstractConnection.js.map +1 -1
  77. package/dist/core/SchemaModelDefinition.js +14 -0
  78. package/dist/core/SchemaModelDefinition.js.map +1 -1
  79. package/dist/core/connection-colors.js +36 -0
  80. package/dist/core/connection-colors.js.map +1 -0
  81. package/dist/core/query/StandardModelFields.js +10 -0
  82. package/dist/core/query/StandardModelFields.js.map +1 -0
  83. package/dist/core/query/filters.js +86 -4
  84. package/dist/core/query/filters.js.map +1 -1
  85. package/dist/core/query/query-simple/SimplePage.js +2 -4
  86. package/dist/core/query/query-simple/SimplePage.js.map +1 -1
  87. package/dist/core/query/query-simple/SimpleQuery.js +64 -68
  88. package/dist/core/query/query-simple/SimpleQuery.js.map +1 -1
  89. package/dist/core/query/query-simple/SimpleQueryColumns.js +88 -0
  90. package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -0
  91. package/dist/core/query/query-simple/SimpleQueryFilterState.js +136 -0
  92. package/dist/core/query/query-simple/SimpleQueryFilterState.js.map +1 -0
  93. package/dist/core/query/query-simple/SimpleQueryPlanner.js +14 -0
  94. package/dist/core/query/query-simple/SimpleQueryPlanner.js.map +1 -0
  95. package/dist/core/query/query-simple/SimpleQuerySortState.js +140 -0
  96. package/dist/core/query/query-simple/SimpleQuerySortState.js.map +1 -0
  97. package/dist/core/query/query-simple/SimpleQueryTypes.js +44 -0
  98. package/dist/core/query/query-simple/SimpleQueryTypes.js.map +1 -0
  99. package/dist/core/query/widgets/BelongsToDisplayWidget.js +14 -7
  100. package/dist/core/query/widgets/BelongsToDisplayWidget.js.map +1 -1
  101. package/dist/core/query/widgets/CellDisplayWidget.js +5 -9
  102. package/dist/core/query/widgets/CellDisplayWidget.js.map +1 -1
  103. package/dist/core/query/widgets/ColumnDisplayWidget.js +13 -12
  104. package/dist/core/query/widgets/ColumnDisplayWidget.js.map +1 -1
  105. package/dist/core/query/widgets/PeekRelationshipButton.js +128 -0
  106. package/dist/core/query/widgets/PeekRelationshipButton.js.map +1 -0
  107. package/dist/core/query/widgets/SmartColumnWidget.js +18 -3
  108. package/dist/core/query/widgets/SmartColumnWidget.js.map +1 -1
  109. package/dist/core/query/widgets/SmartFilterWidget.js +88 -51
  110. package/dist/core/query/widgets/SmartFilterWidget.js.map +1 -1
  111. package/dist/entities/ConnectionEntityDefinition.js +32 -7
  112. package/dist/entities/ConnectionEntityDefinition.js.map +1 -1
  113. package/dist/entities/SavedQueryEntityDefinition.js +68 -0
  114. package/dist/entities/SavedQueryEntityDefinition.js.map +1 -0
  115. package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -1
  116. package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
  117. package/dist/entities.js +1 -0
  118. package/dist/entities.js.map +1 -1
  119. package/dist/forms/APIConnectionForm.js +11 -2
  120. package/dist/forms/APIConnectionForm.js.map +1 -1
  121. package/dist/forms/TypeEngine.js +30 -306
  122. package/dist/forms/TypeEngine.js.map +1 -1
  123. package/dist/forms/types/attachment-handler.js +29 -0
  124. package/dist/forms/types/attachment-handler.js.map +1 -0
  125. package/dist/forms/types/boolean-handler.js +22 -0
  126. package/dist/forms/types/boolean-handler.js.map +1 -0
  127. package/dist/forms/types/date-handler.js +97 -0
  128. package/dist/forms/types/date-handler.js.map +1 -0
  129. package/dist/forms/types/filters/ClearableFilterFormDialogDirective.js +25 -0
  130. package/dist/forms/types/filters/ClearableFilterFormDialogDirective.js.map +1 -0
  131. package/dist/forms/types/filters/ConditionalFilterForm.js +87 -0
  132. package/dist/forms/types/filters/ConditionalFilterForm.js.map +1 -0
  133. package/dist/forms/types/image-handler.js +82 -0
  134. package/dist/forms/types/image-handler.js.map +1 -0
  135. package/dist/forms/types/location-handler.js +49 -0
  136. package/dist/forms/types/location-handler.js.map +1 -0
  137. package/dist/forms/types/multiple-choice-handler.js +37 -0
  138. package/dist/forms/types/multiple-choice-handler.js.map +1 -0
  139. package/dist/forms/types/multiple-choice-integer-handler.js +37 -0
  140. package/dist/forms/types/multiple-choice-integer-handler.js.map +1 -0
  141. package/dist/forms/types/number-handler.js +79 -0
  142. package/dist/forms/types/number-handler.js.map +1 -0
  143. package/dist/forms/types/shared/type-handler.js +2 -0
  144. package/dist/forms/types/shared/type-handler.js.map +1 -0
  145. package/dist/forms/types/shared/ui.js +33 -0
  146. package/dist/forms/types/shared/ui.js.map +1 -0
  147. package/dist/forms/types/single-choice-handler.js +41 -0
  148. package/dist/forms/types/single-choice-handler.js.map +1 -0
  149. package/dist/forms/types/single-choice-integer-handler.js +41 -0
  150. package/dist/forms/types/single-choice-integer-handler.js.map +1 -0
  151. package/dist/forms/types/text-handler.js +170 -0
  152. package/dist/forms/types/text-handler.js.map +1 -0
  153. package/dist/index.js +1 -0
  154. package/dist/index.js.map +1 -1
  155. package/dist/panels/_shared/SharedConnectionPanelFactory.js +48 -0
  156. package/dist/panels/_shared/SharedConnectionPanelFactory.js.map +1 -0
  157. package/dist/panels/_shared/SharedModelPanelFactory.js +7 -2
  158. package/dist/panels/_shared/SharedModelPanelFactory.js.map +1 -1
  159. package/dist/panels/query/PageResultsWidget.js +28 -11
  160. package/dist/panels/query/PageResultsWidget.js.map +1 -1
  161. package/dist/panels/query/QueryPanelFactory.js +17 -2
  162. package/dist/panels/query/QueryPanelFactory.js.map +1 -1
  163. package/dist/panels/query/QueryPanelWidget.js +55 -9
  164. package/dist/panels/query/QueryPanelWidget.js.map +1 -1
  165. package/dist/panels/query/TableControlsWidget.js +29 -67
  166. package/dist/panels/query/TableControlsWidget.js.map +1 -1
  167. package/dist/panels/query/table-controls/ChangesControlsWidget.js +36 -0
  168. package/dist/panels/query/table-controls/ChangesControlsWidget.js.map +1 -0
  169. package/dist/panels/query/table-controls/FilterControlsWidget.js +106 -0
  170. package/dist/panels/query/table-controls/FilterControlsWidget.js.map +1 -0
  171. package/dist/panels/query/table-controls/PageControlsWidget.js +65 -0
  172. package/dist/panels/query/table-controls/PageControlsWidget.js.map +1 -0
  173. package/dist/panels/query/table-controls/QueryControlsWidget.js +85 -0
  174. package/dist/panels/query/table-controls/QueryControlsWidget.js.map +1 -0
  175. package/dist/panels/query/table-controls/SortChipWidget.js +75 -0
  176. package/dist/panels/query/table-controls/SortChipWidget.js.map +1 -0
  177. package/dist/panels/query/table-controls/SortControlsWidget.js +65 -0
  178. package/dist/panels/query/table-controls/SortControlsWidget.js.map +1 -0
  179. package/dist/preferences/QueryControlPreferences.js +28 -0
  180. package/dist/preferences/QueryControlPreferences.js.map +1 -0
  181. package/dist/stores/ConnectionStore.js +2 -0
  182. package/dist/stores/ConnectionStore.js.map +1 -1
  183. package/dist/stores/SavedQueryStore.js +131 -0
  184. package/dist/stores/SavedQueryStore.js.map +1 -0
  185. package/dist/tsconfig.tsbuildinfo +1 -1
  186. package/dist/widgets/EmptyValueWidget.js +15 -0
  187. package/dist/widgets/EmptyValueWidget.js.map +1 -0
  188. package/dist-module/bundle.js +181 -51
  189. package/dist-module/bundle.js.map +1 -1
  190. package/package.json +13 -13
  191. package/src/DataBrowserModule.ts +21 -7
  192. package/src/actions/connections/AddConnectionAction.tsx +2 -2
  193. package/src/actions/connections/RemoveConnectionAction.tsx +2 -2
  194. package/src/actions/connections/SetConnectionColorAction.ts +52 -0
  195. package/src/actions/saved-queries/OpenSavedQueryAction.ts +43 -0
  196. package/src/actions/saved-queries/RemoveSavedQueryAction.ts +27 -0
  197. package/src/actions/schema-definitions/CreateModelAction.ts +9 -2
  198. package/src/actions/schema-definitions/QuerySchemaModelAction.ts +9 -2
  199. package/src/actions/schema-model/EditSchemaModelAction.ts +9 -2
  200. package/src/actions/schema-model/ViewSchemaModelAsJsonAction.ts +9 -2
  201. package/src/core/AbstractConnection.ts +7 -1
  202. package/src/core/SchemaModelDefinition.ts +16 -0
  203. package/src/core/connection-colors.ts +49 -0
  204. package/src/core/query/StandardModelFields.ts +9 -0
  205. package/src/core/query/filters.ts +121 -6
  206. package/src/core/query/query-simple/SimplePage.ts +4 -5
  207. package/src/core/query/query-simple/SimpleQuery.tsx +83 -86
  208. package/src/core/query/query-simple/SimpleQueryColumns.tsx +126 -0
  209. package/src/core/query/query-simple/SimpleQueryFilterState.ts +160 -0
  210. package/src/core/query/query-simple/SimpleQueryPlanner.ts +18 -0
  211. package/src/core/query/query-simple/SimpleQuerySortState.ts +133 -0
  212. package/src/core/query/query-simple/SimpleQueryTypes.ts +61 -0
  213. package/src/core/query/widgets/BelongsToDisplayWidget.tsx +19 -11
  214. package/src/core/query/widgets/CellDisplayWidget.tsx +5 -10
  215. package/src/core/query/widgets/ColumnDisplayWidget.tsx +24 -20
  216. package/src/core/query/widgets/PeekRelationshipButton.tsx +161 -0
  217. package/src/core/query/widgets/SmartColumnWidget.tsx +26 -4
  218. package/src/core/query/widgets/SmartFilterWidget.tsx +119 -69
  219. package/src/entities/ConnectionEntityDefinition.tsx +33 -4
  220. package/src/entities/SavedQueryEntityDefinition.ts +72 -0
  221. package/src/entities/SchemaModelDefinitionEntityDefinition.ts +5 -2
  222. package/src/entities.ts +2 -1
  223. package/src/forms/APIConnectionForm.tsx +15 -2
  224. package/src/forms/TypeEngine.tsx +35 -421
  225. package/src/forms/types/attachment-handler.tsx +35 -0
  226. package/src/forms/types/boolean-handler.tsx +28 -0
  227. package/src/forms/types/date-handler.tsx +125 -0
  228. package/src/forms/types/filters/ClearableFilterFormDialogDirective.ts +32 -0
  229. package/src/forms/types/filters/ConditionalFilterForm.tsx +109 -0
  230. package/src/forms/types/image-handler.tsx +90 -0
  231. package/src/forms/types/location-handler.tsx +53 -0
  232. package/src/forms/types/multiple-choice-handler.tsx +37 -0
  233. package/src/forms/types/multiple-choice-integer-handler.tsx +37 -0
  234. package/src/forms/types/number-handler.tsx +100 -0
  235. package/src/forms/types/shared/type-handler.ts +36 -0
  236. package/src/forms/types/shared/ui.tsx +40 -0
  237. package/src/forms/types/single-choice-handler.tsx +47 -0
  238. package/src/forms/types/single-choice-integer-handler.tsx +47 -0
  239. package/src/forms/types/text-handler.tsx +247 -0
  240. package/src/index.ts +1 -0
  241. package/src/panels/_shared/SharedConnectionPanelFactory.tsx +55 -0
  242. package/src/panels/_shared/SharedModelPanelFactory.tsx +8 -2
  243. package/src/panels/query/PageResultsWidget.tsx +40 -28
  244. package/src/panels/query/QueryPanelFactory.tsx +19 -2
  245. package/src/panels/query/QueryPanelWidget.tsx +64 -9
  246. package/src/panels/query/TableControlsWidget.tsx +42 -120
  247. package/src/panels/query/table-controls/ChangesControlsWidget.tsx +72 -0
  248. package/src/panels/query/table-controls/FilterControlsWidget.tsx +145 -0
  249. package/src/panels/query/table-controls/PageControlsWidget.tsx +97 -0
  250. package/src/panels/query/table-controls/QueryControlsWidget.tsx +127 -0
  251. package/src/panels/query/table-controls/SortChipWidget.tsx +119 -0
  252. package/src/panels/query/table-controls/SortControlsWidget.tsx +95 -0
  253. package/src/preferences/QueryControlPreferences.ts +34 -0
  254. package/src/stores/ConnectionStore.ts +2 -0
  255. package/src/stores/SavedQueryStore.ts +121 -0
  256. package/src/widgets/EmptyValueWidget.tsx +20 -0
@@ -0,0 +1,40 @@
1
+ import * as React from 'react';
2
+ import { styled } from '@journeyapps-labs/reactor-mod';
3
+ import * as _ from 'lodash';
4
+ import { EmptyValueWidget } from '../../../widgets/EmptyValueWidget';
5
+
6
+ export const MAX_NUMBER_OF_ARR_ITEMS_TO_DISPLAY = 3;
7
+
8
+ namespace S {
9
+ export const Empty = styled(EmptyValueWidget)``;
10
+
11
+ export const Pills = styled.div`
12
+ display: flex;
13
+ column-gap: 2px;
14
+ row-gap: 2px;
15
+ `;
16
+
17
+ export const Pill = styled.div`
18
+ padding: 2px 4px;
19
+ background: ${(p) => p.theme.table.pills};
20
+ border-radius: 3px;
21
+ font-size: 12px;
22
+ `;
23
+ }
24
+
25
+ export const TypeUI = S;
26
+
27
+ export function displayArray(value: any[]) {
28
+ if (value.length === 0) {
29
+ return <S.Empty>empty array</S.Empty>;
30
+ }
31
+ const items = _.slice(value, 0, MAX_NUMBER_OF_ARR_ITEMS_TO_DISPLAY);
32
+ return (
33
+ <S.Pills>
34
+ {items.map((c) => {
35
+ return <S.Pill key={c}>{c}</S.Pill>;
36
+ })}
37
+ {items.length !== value.length ? '...' : null}
38
+ </S.Pills>
39
+ );
40
+ }
@@ -0,0 +1,47 @@
1
+ import { SingleChoiceType } from '@journeyapps/db';
2
+ import { ComboBoxStore, ioc, SelectInput } from '@journeyapps-labs/reactor-mod';
3
+ import * as _ from 'lodash';
4
+ import { TypeHandler } from './shared/type-handler';
5
+ import { Condition, SimpleFilter, Statement } from '../../core/query/filters';
6
+
7
+ export const singleChoiceHandler: TypeHandler = {
8
+ matches: (type) => type instanceof SingleChoiceType,
9
+ encode: async (value: string) => value,
10
+ decode: async (value: string) => value,
11
+ encodeToScalar: async (value: string) => value,
12
+ decodeFromScalar: async (value) => (value == null ? '' : `${value}`),
13
+ generateField: ({ label, name, type }) => {
14
+ return new SelectInput({
15
+ name,
16
+ label,
17
+ options: _.mapValues(type.options, (o) => `${o.value}`)
18
+ });
19
+ },
20
+ generateDisplay: ({ value }) => {
21
+ return value;
22
+ },
23
+ setupFilter: async ({ variable, filter, position }) => {
24
+ if (!(variable.type instanceof SingleChoiceType)) {
25
+ return null;
26
+ }
27
+ const results = await ioc.get(ComboBoxStore).showMultiSelectComboBox(
28
+ _.map(variable.type.options, (option) => {
29
+ return {
30
+ title: `${option.value}`,
31
+ key: `${option.value}`,
32
+ checked: !!filter?.statements?.find((s) => s.arg === `${option.value}`)
33
+ };
34
+ }),
35
+ position as any
36
+ );
37
+ if (results.length === 0) {
38
+ return null;
39
+ }
40
+ return new SimpleFilter(
41
+ variable,
42
+ results.map((r) => {
43
+ return new Statement(Condition.EQUALS, r.key);
44
+ })
45
+ );
46
+ }
47
+ };
@@ -0,0 +1,47 @@
1
+ import { SingleChoiceIntegerType } from '@journeyapps/db';
2
+ import { ComboBoxStore, ioc, SelectInput } from '@journeyapps-labs/reactor-mod';
3
+ import * as _ from 'lodash';
4
+ import { TypeHandler } from './shared/type-handler';
5
+ import { Condition, SimpleFilter, Statement } from '../../core/query/filters';
6
+
7
+ export const singleChoiceIntegerHandler: TypeHandler = {
8
+ matches: (type) => type instanceof SingleChoiceIntegerType,
9
+ encode: async (value: string) => parseInt(value),
10
+ decode: async (value: number) => `${value}`,
11
+ encodeToScalar: async (value: string) => value,
12
+ decodeFromScalar: async (value) => (value == null ? '' : `${value}`),
13
+ generateField: ({ label, name, type }) => {
14
+ return new SelectInput({
15
+ name,
16
+ label,
17
+ options: _.mapValues(type.options, (o) => `${o.value}`)
18
+ });
19
+ },
20
+ generateDisplay: ({ value }) => {
21
+ return `${value}`;
22
+ },
23
+ setupFilter: async ({ variable, filter, position }) => {
24
+ if (!(variable.type instanceof SingleChoiceIntegerType)) {
25
+ return null;
26
+ }
27
+ const results = await ioc.get(ComboBoxStore).showMultiSelectComboBox(
28
+ _.map(variable.type.options, (option) => {
29
+ return {
30
+ title: `${option.value}`,
31
+ key: `${option.value}`,
32
+ checked: !!filter?.statements?.find((s) => s.arg === `${option.value}`)
33
+ };
34
+ }),
35
+ position as any
36
+ );
37
+ if (results.length === 0) {
38
+ return null;
39
+ }
40
+ return new SimpleFilter(
41
+ variable,
42
+ results.map((r) => {
43
+ return new Statement(Condition.EQUALS, r.key);
44
+ })
45
+ );
46
+ }
47
+ };
@@ -0,0 +1,247 @@
1
+ import { TextType, Variable } from '@journeyapps/db';
2
+ import {
3
+ DialogStore2,
4
+ FormInput,
5
+ FormInputRenderOptions,
6
+ TableButtonWidget,
7
+ TextArea,
8
+ TextAreaInput,
9
+ TextInput,
10
+ TextInputType,
11
+ ioc,
12
+ styled
13
+ } from '@journeyapps-labs/reactor-mod';
14
+ import * as React from 'react';
15
+ import { ModelJsonPanelModel } from '../../panels/model-json/ModelJsonPanelFactory';
16
+ import { TypeHandler, TypeHandlerContext } from './shared/type-handler';
17
+ import { TypeUI } from './shared/ui';
18
+ import { Condition, SimpleFilter, Statement, StatementMatch } from '../../core/query/filters';
19
+ import {
20
+ ConditionalFilterForm,
21
+ ConditionalFilterFormOptions,
22
+ ConditionalFilterFormValue,
23
+ ConditionalStatementValue
24
+ } from './filters/ConditionalFilterForm';
25
+ import { ClearableFilterFormDialogDirective } from './filters/ClearableFilterFormDialogDirective';
26
+
27
+ interface TextFilterFormValue extends ConditionalFilterFormValue<string> {
28
+ statements: ConditionalStatementValue<string>[];
29
+ }
30
+
31
+ interface TextFilterFormOptions extends ConditionalFilterFormOptions<string> {
32
+ type: TextType;
33
+ statements?: ConditionalStatementValue<string>[];
34
+ }
35
+
36
+ const getRowsFromValue = (value?: string | null): number => {
37
+ const lines = `${value || ''}`.split(/\r?\n/).length || 1;
38
+ return Math.max(2, Math.min(12, lines));
39
+ };
40
+
41
+ class AutoRowsTextAreaInput extends TextAreaInput {
42
+ renderControl(options: FormInputRenderOptions): React.JSX.Element {
43
+ return (
44
+ <TextArea
45
+ data-1p-ignore="true"
46
+ autoComplete="off"
47
+ name={this.name}
48
+ rows={getRowsFromValue(this.value)}
49
+ value={this.value || ''}
50
+ onChange={(event) => {
51
+ this.setValue(event.target.value);
52
+ }}
53
+ />
54
+ );
55
+ }
56
+ }
57
+
58
+ const generateTextField = ({
59
+ label,
60
+ name,
61
+ type,
62
+ value
63
+ }: {
64
+ label: string;
65
+ name: string;
66
+ type: TextType;
67
+ value?: string;
68
+ }): FormInput => {
69
+ if (type.subType == 'paragraph') {
70
+ return new AutoRowsTextAreaInput({
71
+ name,
72
+ label,
73
+ value
74
+ });
75
+ }
76
+
77
+ if (type.subType == 'password') {
78
+ return new TextInput({
79
+ name,
80
+ label,
81
+ inputType: TextInputType.PASSWORD
82
+ });
83
+ }
84
+
85
+ return new TextInput({
86
+ name,
87
+ label
88
+ });
89
+ };
90
+
91
+ class TextFilterForm extends ConditionalFilterForm<string> {
92
+ constructor(protected options2: TextFilterFormOptions) {
93
+ super(options2);
94
+ }
95
+
96
+ static fromFilter(filter: SimpleFilter | undefined, type: TextType): TextFilterFormOptions {
97
+ return {
98
+ type,
99
+ match: filter?.match || StatementMatch.ALL,
100
+ statements: (filter?.statements || [])
101
+ .map((statement) => ({
102
+ condition: statement.condition || Condition.EQUALS,
103
+ value: statement.arg == null ? '' : `${statement.arg}`
104
+ }))
105
+ .filter((statement) => statement.value.trim() !== '')
106
+ };
107
+ }
108
+
109
+ toFilter(variable: Variable): SimpleFilter | null {
110
+ const formValue = this.value() as TextFilterFormValue;
111
+ const statements = (formValue.statements || [])
112
+ .map((statement) => ({
113
+ condition: statement?.condition || Condition.EQUALS,
114
+ arg: statement?.value == null ? '' : `${statement.value}`.trim()
115
+ }))
116
+ .filter((statement) => statement.arg !== '')
117
+ .map((statement) => new Statement(statement.condition, statement.arg));
118
+ if (statements.length === 0) {
119
+ return null;
120
+ }
121
+ return new SimpleFilter(variable, statements, formValue.match || StatementMatch.ALL);
122
+ }
123
+
124
+ protected generateValueInput(): FormInput {
125
+ return generateTextField({
126
+ name: 'value',
127
+ label: 'Value',
128
+ type: this.options2.type,
129
+ value: this.getDefaultValue()
130
+ });
131
+ }
132
+
133
+ protected getConditionOptions(): Record<string, string> {
134
+ return {
135
+ [Condition.EQUALS]: '=',
136
+ [Condition.STARTS_WITH]: 'Starts with',
137
+ [Condition.CONTAINS]: 'Contains'
138
+ };
139
+ }
140
+
141
+ protected getDefaultCondition(): Condition {
142
+ return Condition.CONTAINS;
143
+ }
144
+
145
+ protected getDefaultValue(): string {
146
+ return '';
147
+ }
148
+ }
149
+
150
+ export const textHandler = (context: TypeHandlerContext): TypeHandler<TextType, string, string> => {
151
+ return {
152
+ matches: (type) => type instanceof TextType,
153
+ encode: async (value: string) => value,
154
+ decode: async (value: string) => value,
155
+ encodeToScalar: async (value: string) => value,
156
+ decodeFromScalar: async (value) => (value == null ? '' : `${value}`),
157
+ generateField: ({ label, name, type }) => {
158
+ return generateTextField({ label, name, type });
159
+ },
160
+ generateDisplay: ({ value, type, name, model }) => {
161
+ if (value.trim() === '') {
162
+ return <TypeUI.Empty>empty</TypeUI.Empty>;
163
+ }
164
+
165
+ if (type.subType == 'password') {
166
+ return '****';
167
+ }
168
+
169
+ if (type.subType == 'paragraph') {
170
+ if ((value.startsWith('[') && value.endsWith(']')) || (value.startsWith('{') && value.endsWith('}'))) {
171
+ try {
172
+ JSON.parse(value);
173
+ return (
174
+ <TableButtonWidget
175
+ icon="code"
176
+ label="JSON"
177
+ action={() => {
178
+ context.workspaceStore.addModel(
179
+ new ModelJsonPanelModel({
180
+ definition: model.definition,
181
+ model: model,
182
+ field: name
183
+ })
184
+ );
185
+ }}
186
+ />
187
+ );
188
+ } catch (ex) {}
189
+ }
190
+ }
191
+
192
+ if (type.subType == 'url') {
193
+ return (
194
+ <S.Container>
195
+ {value}
196
+ <TableButtonWidget
197
+ icon="arrow-right"
198
+ action={() => {
199
+ window.open(value, '_blank');
200
+ }}
201
+ />
202
+ </S.Container>
203
+ );
204
+ }
205
+
206
+ return <S.Max>{value}</S.Max>;
207
+ },
208
+ setupFilter: async ({ variable, filter }) => {
209
+ if (!(variable.type instanceof TextType)) {
210
+ return null;
211
+ }
212
+
213
+ const form = new TextFilterForm(TextFilterForm.fromFilter(filter, variable.type));
214
+ const result = await ioc.get(DialogStore2).showDialog(
215
+ new ClearableFilterFormDialogDirective({
216
+ title: `Filter ${variable.label || variable.name}`,
217
+ form,
218
+ filter,
219
+ handler: async () => {}
220
+ })
221
+ );
222
+ if (!result) {
223
+ return null;
224
+ }
225
+ return form.toFilter(variable);
226
+ }
227
+ };
228
+ };
229
+
230
+ namespace S {
231
+ export const Max = styled.div`
232
+ max-width: 500px;
233
+ white-space: pre;
234
+ display: inline-block;
235
+ overflow: hidden;
236
+ text-overflow: ellipsis;
237
+ `;
238
+
239
+ export const Container = styled.div`
240
+ display: flex;
241
+ flex-direction: row;
242
+ column-gap: 5px;
243
+ align-items: center;
244
+ justify-content: space-between;
245
+ flex-grow: 1;
246
+ `;
247
+ }
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ export * from './entities/SchemaModelObjectEntityDefinition';
20
20
  export * from './panels/query/QueryPanelFactory';
21
21
  export * from './panels/model/ModelPanelFactory';
22
22
  export * from './panels/_shared/SharedModelPanelFactory';
23
+ export * from './panels/_shared/SharedConnectionPanelFactory';
23
24
 
24
25
  export * from './stores/ConnectionStore';
25
26
 
@@ -0,0 +1,55 @@
1
+ import { AbstractConnection } from '../../core/AbstractConnection';
2
+ import { observable } from 'mobx';
3
+ import { ReactorPanelFactory, ReactorPanelModel, TabWidget } from '@journeyapps-labs/reactor-mod';
4
+ import { TabRendererEvent } from '@projectstorm/react-workspaces-model-tabs';
5
+ import React from 'react';
6
+
7
+ export interface SharedConnectionPanelModelOptions {
8
+ connection?: AbstractConnection;
9
+ }
10
+
11
+ export class SharedConnectionPanelModel extends ReactorPanelModel {
12
+ @observable
13
+ accessor connection: AbstractConnection;
14
+
15
+ constructor(type: string, options?: SharedConnectionPanelModelOptions) {
16
+ super(type);
17
+ this.connection = options?.connection || null;
18
+ }
19
+
20
+ encodeEntities() {
21
+ return {
22
+ ...super.encodeEntities(),
23
+ connection: this.connection
24
+ };
25
+ }
26
+
27
+ decodeEntities(entities: ReturnType<this['encodeEntities']>) {
28
+ this.connection = entities.connection;
29
+ }
30
+ }
31
+
32
+ export abstract class SharedConnectionPanelFactory<T extends ReactorPanelModel> extends ReactorPanelFactory<T> {
33
+ protected abstract getConnection(model: T): AbstractConnection | null;
34
+
35
+ protected generatePanelTabInternal(event: TabRendererEvent<T>) {
36
+ const connection = this.getConnection(event.model);
37
+ return (
38
+ <TabWidget
39
+ icon={this.getTabIcon(event)}
40
+ factory={this}
41
+ engine={event.engine}
42
+ model={event.model}
43
+ selected={event.selected}
44
+ title={this.getSimpleName(event.model)}
45
+ indicator={
46
+ connection?.color
47
+ ? {
48
+ color: connection.color
49
+ }
50
+ : undefined
51
+ }
52
+ />
53
+ );
54
+ }
55
+ }
@@ -1,8 +1,10 @@
1
- import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
1
+ import { inject, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
2
2
  import { ConnectionStore } from '../../stores/ConnectionStore';
3
3
  import { observable } from 'mobx';
4
4
  import { SchemaModelDefinition } from '../../core/SchemaModelDefinition';
5
5
  import { SchemaModelObject } from '../../core/SchemaModelObject';
6
+ import { SharedConnectionPanelFactory } from './SharedConnectionPanelFactory';
7
+ import { AbstractConnection } from '../../core/AbstractConnection';
6
8
 
7
9
  export interface SharedModelPanelModelOptions {
8
10
  definition: SchemaModelDefinition;
@@ -39,7 +41,11 @@ export class SharedModelPanelModel extends ReactorPanelModel {
39
41
  }
40
42
  }
41
43
 
42
- export abstract class SharedModelPanelFactory<T extends SharedModelPanelModel> extends ReactorPanelFactory<T> {
44
+ export abstract class SharedModelPanelFactory<T extends SharedModelPanelModel> extends SharedConnectionPanelFactory<T> {
45
+ protected getConnection(model: T): AbstractConnection | null {
46
+ return model.definition?.connection || null;
47
+ }
48
+
43
49
  getSimpleName(model: T) {
44
50
  let _model = model.model;
45
51
  let _definition = model.definition;
@@ -1,16 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { Page } from '../../core/query/Page';
3
- import {
4
- ActionSource,
5
- ioc,
6
- LoadingPanelWidget,
7
- ScrollableDivCss,
8
- System,
9
- TableWidget
10
- } from '@journeyapps-labs/reactor-mod';
3
+ import { themed, ioc, ScrollableDivCss, System, TableWidget, LoadingPanelWidget } from '@journeyapps-labs/reactor-mod';
11
4
  import { AbstractQuery } from '../../core/query/AbstractQuery';
12
5
  import { observer } from 'mobx-react';
13
- import styled from '@emotion/styled';
14
6
  import { DataBrowserEntities } from '../../entities';
15
7
  import { SchemaModelObject } from '../../core/SchemaModelObject';
16
8
 
@@ -21,32 +13,52 @@ export interface PageResultsWidgetProps {
21
13
 
22
14
  export const PageResultsWidget: React.FC<PageResultsWidgetProps> = observer((props) => {
23
15
  const system = ioc.get(System);
16
+ const rows = props.page.loading ? [] : props.page.asRows();
24
17
 
25
18
  return (
26
- <LoadingPanelWidget
27
- loading={props.page.loading}
28
- children={() => {
29
- return (
30
- <S.Container>
31
- <TableWidget
32
- onContextMenu={(event, row) => {
33
- system
34
- .getDefinition<SchemaModelObject>(DataBrowserEntities.SCHEMA_MODEL_OBJECT)
35
- .showContextMenuForEntity(row.model, event);
36
- }}
37
- rows={props.page.asRows()}
38
- columns={props.query.getColumns()}
39
- />
40
- </S.Container>
41
- );
42
- }}
43
- />
19
+ <S.Container>
20
+ <TableWidget
21
+ onContextMenu={(event, row) => {
22
+ system
23
+ .getDefinition<SchemaModelObject>(DataBrowserEntities.SCHEMA_MODEL_OBJECT)
24
+ .showContextMenuForEntity(row.model, event);
25
+ }}
26
+ rows={rows}
27
+ columns={props.query.getColumns()}
28
+ />
29
+ {props.page.loading ? (
30
+ <S.RowsLoading>
31
+ <LoadingPanelWidget loading={true}>{() => null}</LoadingPanelWidget>
32
+ </S.RowsLoading>
33
+ ) : rows.length === 0 ? (
34
+ <S.EmptyState>No results for this query</S.EmptyState>
35
+ ) : null}
36
+ </S.Container>
44
37
  );
45
38
  });
46
39
 
47
40
  namespace S {
48
- export const Container = styled.div`
41
+ export const Container = themed.div`
42
+ position: relative;
49
43
  overflow: auto;
44
+ height: 100%;
50
45
  ${ScrollableDivCss};
51
46
  `;
47
+
48
+ export const EmptyState = themed.div`
49
+ display: flex;
50
+ justify-content: center;
51
+ align-items: center;
52
+ min-height: 180px;
53
+ color: ${(p) => p.theme.text.secondary};
54
+ font-size: 14px;
55
+ font-weight: 500;
56
+ `;
57
+
58
+ export const RowsLoading = themed.div`
59
+ display: flex;
60
+ justify-content: center;
61
+ align-items: center;
62
+ min-height: 180px;
63
+ `;
52
64
  }
@@ -1,11 +1,14 @@
1
1
  import * as React from 'react';
2
- import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
2
+ import { inject, ioc, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
3
3
  import { QueryPanelWidget } from './QueryPanelWidget';
4
4
  import { AbstractQuery } from '../../core/query/AbstractQuery';
5
5
  import { ConnectionStore } from '../../stores/ConnectionStore';
6
6
  import { observable } from 'mobx';
7
7
  import { WorkspaceModelFactoryEvent } from '@projectstorm/react-workspaces-core';
8
8
  import { AbstractSerializableQuery } from '../../core/query/AbstractSerializableQuery';
9
+ import { SavedQueryStore } from '../../stores/SavedQueryStore';
10
+ import { AbstractConnection } from '../../core/AbstractConnection';
11
+ import { SharedConnectionPanelFactory } from '../_shared/SharedConnectionPanelFactory';
9
12
 
10
13
  export class QueryPanelModel extends ReactorPanelModel {
11
14
  @inject(ConnectionStore)
@@ -49,9 +52,19 @@ export class QueryPanelModel extends ReactorPanelModel {
49
52
  decodeEntities(data: ReturnType<this['encodeEntities']>) {
50
53
  this.query = data.query;
51
54
  }
55
+
56
+ async loadSavedQuery(id: string): Promise<void> {
57
+ const query = await ioc.get(SavedQueryStore).loadSavedQuery(id);
58
+ if (!query) {
59
+ return;
60
+ }
61
+ this.current_page = 0;
62
+ this.query = query;
63
+ await query.load();
64
+ }
52
65
  }
53
66
 
54
- export class QueryPanelFactory extends ReactorPanelFactory<QueryPanelModel> {
67
+ export class QueryPanelFactory extends SharedConnectionPanelFactory<QueryPanelModel> {
55
68
  static TYPE = 'query';
56
69
 
57
70
  constructor() {
@@ -71,6 +84,10 @@ export class QueryPanelFactory extends ReactorPanelFactory<QueryPanelModel> {
71
84
  return model.query?.getSimpleName();
72
85
  }
73
86
 
87
+ protected getConnection(model: QueryPanelModel): AbstractConnection | null {
88
+ return model.query?.connection || null;
89
+ }
90
+
74
91
  _generateModel(): QueryPanelModel {
75
92
  return new QueryPanelModel(null);
76
93
  }