@journeyapps-labs/reactor-mod-data-browser 0.0.0-dev-20250825225306

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 (138) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +3 -0
  3. package/dist/@types/DataBrowserModule.d.ts +7 -0
  4. package/dist/@types/actions/connections/AddConnectionAction.d.ts +10 -0
  5. package/dist/@types/actions/connections/RemoveConnectionAction.d.ts +10 -0
  6. package/dist/@types/actions/schema-definitions/CreateModelAction.d.ts +9 -0
  7. package/dist/@types/actions/schema-definitions/QuerySchemaModelAction.d.ts +9 -0
  8. package/dist/@types/actions/schema-model/EditSchemaModelAction.d.ts +9 -0
  9. package/dist/@types/core/AbstractConnection.d.ts +34 -0
  10. package/dist/@types/core/AbstractConnectionFactory.d.ts +11 -0
  11. package/dist/@types/core/SchemaModelDefinition.d.ts +20 -0
  12. package/dist/@types/core/SchemaModelObject.d.ts +16 -0
  13. package/dist/@types/core/query/AbstractQuery.d.ts +22 -0
  14. package/dist/@types/core/query/Page.d.ts +24 -0
  15. package/dist/@types/core/query/SimpleQuery.d.ts +37 -0
  16. package/dist/@types/core/types/ManualConnection.d.ts +15 -0
  17. package/dist/@types/core/types/ManualConnectionFactory.d.ts +9 -0
  18. package/dist/@types/entities/ConnectionEntityDefinition.d.ts +9 -0
  19. package/dist/@types/entities/ConnectionFactoryEntityDefinition.d.ts +9 -0
  20. package/dist/@types/entities/QueryEntityDefinition.d.ts +9 -0
  21. package/dist/@types/entities/SchemaModelDefinitionEntityDefinition.d.ts +13 -0
  22. package/dist/@types/entities/SchemaModelObjectEntityDefinition.d.ts +14 -0
  23. package/dist/@types/entities.d.ts +7 -0
  24. package/dist/@types/forms/APIConnectionForm.d.ts +12 -0
  25. package/dist/@types/forms/SchemaModelForm.d.ts +11 -0
  26. package/dist/@types/forms/inputs/LocationInput.d.ts +13 -0
  27. package/dist/@types/index.d.ts +25 -0
  28. package/dist/@types/panels/model/ModelPanelFactory.d.ts +28 -0
  29. package/dist/@types/panels/model/ModelPanelWidget.d.ts +6 -0
  30. package/dist/@types/panels/query/PageResultsWidget.d.ts +8 -0
  31. package/dist/@types/panels/query/QueryPanelFactory.d.ts +33 -0
  32. package/dist/@types/panels/query/QueryPanelWidget.d.ts +6 -0
  33. package/dist/@types/panels/query/TableControlsWidget.d.ts +10 -0
  34. package/dist/@types/stores/ConnectionStore.d.ts +20 -0
  35. package/dist/DataBrowserModule.js +45 -0
  36. package/dist/DataBrowserModule.js.map +1 -0
  37. package/dist/actions/connections/AddConnectionAction.js +48 -0
  38. package/dist/actions/connections/AddConnectionAction.js.map +1 -0
  39. package/dist/actions/connections/RemoveConnectionAction.js +43 -0
  40. package/dist/actions/connections/RemoveConnectionAction.js.map +1 -0
  41. package/dist/actions/schema-definitions/CreateModelAction.js +45 -0
  42. package/dist/actions/schema-definitions/CreateModelAction.js.map +1 -0
  43. package/dist/actions/schema-definitions/QuerySchemaModelAction.js +47 -0
  44. package/dist/actions/schema-definitions/QuerySchemaModelAction.js.map +1 -0
  45. package/dist/actions/schema-model/EditSchemaModelAction.js +46 -0
  46. package/dist/actions/schema-model/EditSchemaModelAction.js.map +1 -0
  47. package/dist/core/AbstractConnection.js +71 -0
  48. package/dist/core/AbstractConnection.js.map +1 -0
  49. package/dist/core/AbstractConnectionFactory.js +6 -0
  50. package/dist/core/AbstractConnectionFactory.js.map +1 -0
  51. package/dist/core/SchemaModelDefinition.js +31 -0
  52. package/dist/core/SchemaModelDefinition.js.map +1 -0
  53. package/dist/core/SchemaModelObject.js +51 -0
  54. package/dist/core/SchemaModelObject.js.map +1 -0
  55. package/dist/core/query/AbstractQuery.js +18 -0
  56. package/dist/core/query/AbstractQuery.js.map +1 -0
  57. package/dist/core/query/Page.js +65 -0
  58. package/dist/core/query/Page.js.map +1 -0
  59. package/dist/core/query/SimpleQuery.js +197 -0
  60. package/dist/core/query/SimpleQuery.js.map +1 -0
  61. package/dist/core/types/ManualConnection.js +23 -0
  62. package/dist/core/types/ManualConnection.js.map +1 -0
  63. package/dist/core/types/ManualConnectionFactory.js +50 -0
  64. package/dist/core/types/ManualConnectionFactory.js.map +1 -0
  65. package/dist/entities/ConnectionEntityDefinition.js +75 -0
  66. package/dist/entities/ConnectionEntityDefinition.js.map +1 -0
  67. package/dist/entities/ConnectionFactoryEntityDefinition.js +60 -0
  68. package/dist/entities/ConnectionFactoryEntityDefinition.js.map +1 -0
  69. package/dist/entities/QueryEntityDefinition.js +60 -0
  70. package/dist/entities/QueryEntityDefinition.js.map +1 -0
  71. package/dist/entities/SchemaModelDefinitionEntityDefinition.js +76 -0
  72. package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -0
  73. package/dist/entities/SchemaModelObjectEntityDefinition.js +76 -0
  74. package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -0
  75. package/dist/entities.js +9 -0
  76. package/dist/entities.js.map +1 -0
  77. package/dist/forms/APIConnectionForm.js +31 -0
  78. package/dist/forms/APIConnectionForm.js.map +1 -0
  79. package/dist/forms/SchemaModelForm.js +87 -0
  80. package/dist/forms/SchemaModelForm.js.map +1 -0
  81. package/dist/forms/inputs/LocationInput.js +74 -0
  82. package/dist/forms/inputs/LocationInput.js.map +1 -0
  83. package/dist/index.js +26 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/panels/model/ModelPanelFactory.js +94 -0
  86. package/dist/panels/model/ModelPanelFactory.js.map +1 -0
  87. package/dist/panels/model/ModelPanelWidget.js +46 -0
  88. package/dist/panels/model/ModelPanelWidget.js.map +1 -0
  89. package/dist/panels/query/PageResultsWidget.js +24 -0
  90. package/dist/panels/query/PageResultsWidget.js.map +1 -0
  91. package/dist/panels/query/QueryPanelFactory.js +94 -0
  92. package/dist/panels/query/QueryPanelFactory.js.map +1 -0
  93. package/dist/panels/query/QueryPanelWidget.js +41 -0
  94. package/dist/panels/query/QueryPanelWidget.js.map +1 -0
  95. package/dist/panels/query/TableControlsWidget.js +52 -0
  96. package/dist/panels/query/TableControlsWidget.js.map +1 -0
  97. package/dist/stores/ConnectionStore.js +93 -0
  98. package/dist/stores/ConnectionStore.js.map +1 -0
  99. package/dist/tsconfig.tsbuildinfo +1 -0
  100. package/dist-module/bundle.js +49 -0
  101. package/dist-module/bundle.js.LICENSE.txt +16 -0
  102. package/dist-module/bundle.js.map +1 -0
  103. package/package.json +41 -0
  104. package/reactor.config.json +4 -0
  105. package/src/DataBrowserModule.ts +54 -0
  106. package/src/actions/connections/AddConnectionAction.tsx +33 -0
  107. package/src/actions/connections/RemoveConnectionAction.tsx +28 -0
  108. package/src/actions/schema-definitions/CreateModelAction.ts +32 -0
  109. package/src/actions/schema-definitions/QuerySchemaModelAction.ts +36 -0
  110. package/src/actions/schema-model/EditSchemaModelAction.ts +33 -0
  111. package/src/core/AbstractConnection.ts +104 -0
  112. package/src/core/AbstractConnectionFactory.ts +14 -0
  113. package/src/core/SchemaModelDefinition.ts +44 -0
  114. package/src/core/SchemaModelObject.ts +46 -0
  115. package/src/core/query/AbstractQuery.ts +43 -0
  116. package/src/core/query/Page.ts +59 -0
  117. package/src/core/query/SimpleQuery.tsx +218 -0
  118. package/src/core/types/ManualConnection.ts +35 -0
  119. package/src/core/types/ManualConnectionFactory.tsx +36 -0
  120. package/src/entities/ConnectionEntityDefinition.tsx +79 -0
  121. package/src/entities/ConnectionFactoryEntityDefinition.tsx +54 -0
  122. package/src/entities/QueryEntityDefinition.ts +46 -0
  123. package/src/entities/SchemaModelDefinitionEntityDefinition.ts +82 -0
  124. package/src/entities/SchemaModelObjectEntityDefinition.ts +78 -0
  125. package/src/entities.ts +7 -0
  126. package/src/forms/APIConnectionForm.tsx +48 -0
  127. package/src/forms/SchemaModelForm.tsx +116 -0
  128. package/src/forms/inputs/LocationInput.tsx +104 -0
  129. package/src/index.ts +27 -0
  130. package/src/panels/model/ModelPanelFactory.tsx +78 -0
  131. package/src/panels/model/ModelPanelWidget.tsx +76 -0
  132. package/src/panels/query/PageResultsWidget.tsx +52 -0
  133. package/src/panels/query/QueryPanelFactory.tsx +76 -0
  134. package/src/panels/query/QueryPanelWidget.tsx +72 -0
  135. package/src/panels/query/TableControlsWidget.tsx +85 -0
  136. package/src/stores/ConnectionStore.ts +87 -0
  137. package/tsconfig.json +14 -0
  138. package/webpack.config.js +9 -0
@@ -0,0 +1,116 @@
1
+ import {
2
+ BooleanInput,
3
+ DateInput,
4
+ DateTimePickerType,
5
+ FileInput,
6
+ FormModel,
7
+ ImageInput,
8
+ ImageMedia,
9
+ SelectInput,
10
+ TextInput
11
+ } from '@journeyapps-labs/reactor-mod';
12
+ import { SchemaModelDefinition } from '../core/SchemaModelDefinition';
13
+ import { SchemaModelObject } from '../core/SchemaModelObject';
14
+ import * as _ from 'lodash';
15
+ import {
16
+ AttachmentType,
17
+ BooleanType,
18
+ DatetimeType,
19
+ DateType,
20
+ LocationType,
21
+ MultipleChoiceType,
22
+ PhotoType,
23
+ SignatureType,
24
+ SingleChoiceIntegerType,
25
+ SingleChoiceType,
26
+ TextType
27
+ } from '@journeyapps/db';
28
+ import { LocationInput } from './inputs/LocationInput';
29
+
30
+ export interface SchemaModelFormOptions {
31
+ definition: SchemaModelDefinition;
32
+ object?: SchemaModelObject;
33
+ }
34
+
35
+ export class SchemaModelForm extends FormModel {
36
+ constructor(protected options: SchemaModelFormOptions) {
37
+ super();
38
+
39
+ _.map(options.definition.definition.attributes, (attribute) => {
40
+ if (attribute.type instanceof DatetimeType) {
41
+ return new DateInput({
42
+ name: attribute.name,
43
+ label: attribute.label,
44
+ value: options.object?.model[attribute.name] || null,
45
+ type: DateTimePickerType.DATETIME
46
+ });
47
+ }
48
+ if (attribute.type instanceof DateType) {
49
+ return new DateInput({
50
+ name: attribute.name,
51
+ label: attribute.label,
52
+ value: options.object?.model[attribute.name] || null,
53
+ type: DateTimePickerType.DATE
54
+ });
55
+ }
56
+ if (attribute.type instanceof SignatureType || attribute.type instanceof PhotoType) {
57
+ let media = new ImageInput({
58
+ name: attribute.name,
59
+ label: attribute.label
60
+ });
61
+
62
+ if (options.object) {
63
+ options.object.getMedia(attribute.name).then((m) => {
64
+ media.setValue(m as ImageMedia);
65
+ });
66
+ }
67
+ return media;
68
+ }
69
+ if (attribute.type instanceof AttachmentType) {
70
+ return new FileInput({
71
+ name: attribute.name,
72
+ label: attribute.label,
73
+ value: options.object?.model[attribute.name] || null
74
+ });
75
+ }
76
+ if (attribute.type instanceof BooleanType) {
77
+ return new BooleanInput({
78
+ name: attribute.name,
79
+ label: attribute.label,
80
+ value: options.object?.model[attribute.name]
81
+ });
82
+ }
83
+ if (attribute.type instanceof LocationType) {
84
+ return new LocationInput({
85
+ name: attribute.name,
86
+ label: attribute.label,
87
+ value: options.object?.model[attribute.name]
88
+ });
89
+ }
90
+ if (attribute.type instanceof SingleChoiceIntegerType || attribute.type instanceof SingleChoiceType) {
91
+ return new SelectInput({
92
+ name: attribute.name,
93
+ label: attribute.label,
94
+ value: options.object?.model[attribute.name],
95
+ options: _.mapValues(attribute.type.options, (option) => {
96
+ return `${option.value}`;
97
+ })
98
+ });
99
+ }
100
+ if (attribute.type instanceof MultipleChoiceType) {
101
+ }
102
+ if (attribute.type instanceof TextType) {
103
+ return new TextInput({
104
+ name: attribute.name,
105
+ label: attribute.label,
106
+ value: options.object?.model[attribute.name]
107
+ });
108
+ }
109
+ return null;
110
+ })
111
+ .filter((f) => !!f)
112
+ .forEach((a) => {
113
+ this.addInput(a);
114
+ });
115
+ }
116
+ }
@@ -0,0 +1,104 @@
1
+ import {
2
+ FormInput,
3
+ FormInputGenerics,
4
+ FormInputOptions,
5
+ FormInputRenderOptions,
6
+ InputContainerWidget,
7
+ NumberInput,
8
+ PanelButtonMode,
9
+ PanelButtonWidget
10
+ } from '@journeyapps-labs/reactor-mod';
11
+ import * as React from 'react';
12
+ import { Location } from '@journeyapps/db';
13
+ import styled from '@emotion/styled';
14
+
15
+ export class LocationInput extends FormInput<FormInputGenerics & { VALUE: Location }> {
16
+ latitude: NumberInput;
17
+ longitude: NumberInput;
18
+
19
+ constructor(options: FormInputOptions<Location>) {
20
+ super(options);
21
+ this.latitude = new NumberInput({
22
+ name: 'latitude',
23
+ label: 'Latitude',
24
+ value: options.value?.latitude
25
+ });
26
+ this.longitude = new NumberInput({
27
+ name: 'longitude',
28
+ label: 'Longitude',
29
+ value: options.value?.longitude
30
+ });
31
+
32
+ this.update();
33
+
34
+ [this.latitude, this.longitude].forEach((l) => {
35
+ l.registerListener({
36
+ valueChanged: () => {
37
+ this.update();
38
+ }
39
+ });
40
+ });
41
+ }
42
+
43
+ setValue(value: Location) {
44
+ super.setValue(value);
45
+ if (this.latitude.value !== value?.latitude) {
46
+ this.latitude.setValue(value?.latitude);
47
+ }
48
+ if (this.longitude.value !== value?.longitude) {
49
+ this.longitude.setValue(value?.longitude);
50
+ }
51
+ }
52
+
53
+ update() {
54
+ let lat = this.latitude.value;
55
+ let long = this.longitude.value;
56
+ if (lat == null || long === null) {
57
+ this.setValue(null);
58
+ } else {
59
+ this.setValue(
60
+ new Location({
61
+ latitude: lat,
62
+ longitude: long,
63
+ horizontal_accuracy: (this.value as Location)?.horizontal_accuracy,
64
+ vertical_accuracy: (this.value as Location)?.vertical_accuracy,
65
+ altitude: (this.value as Location)?.altitude,
66
+ timestamp: new Date()
67
+ })
68
+ );
69
+ }
70
+ }
71
+
72
+ renderControl(options: FormInputRenderOptions): React.JSX.Element {
73
+ return (
74
+ <S.Container>
75
+ <InputContainerWidget error={this.latitude.error} label={this.latitude.label} inline={true}>
76
+ {this.latitude.renderControl({ inline: true })}
77
+ </InputContainerWidget>
78
+ <InputContainerWidget error={this.longitude.error} label={this.longitude.label} inline={true}>
79
+ {this.longitude.renderControl({ inline: true })}
80
+ </InputContainerWidget>
81
+ {this.value ? (
82
+ <PanelButtonWidget
83
+ mode={PanelButtonMode.LINK}
84
+ label="Open in maps"
85
+ icon="map"
86
+ action={() => {
87
+ window.open(`https://www.google.com/maps/?q=${this.latitude.value},${this.longitude.value}`, '_blank');
88
+ }}
89
+ />
90
+ ) : null}
91
+ </S.Container>
92
+ );
93
+ }
94
+ }
95
+
96
+ namespace S {
97
+ export const Container = styled.div`
98
+ display: flex;
99
+ flex-direction: column;
100
+ row-gap: 2px;
101
+ max-width: 250px;
102
+ align-items: flex-start;
103
+ `;
104
+ }
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { DataBrowserModule } from './DataBrowserModule';
2
+
3
+ export * from './entities';
4
+ export * from './core/SchemaModelDefinition';
5
+ export * from './core/SchemaModelObject';
6
+ export * from './core/AbstractConnection';
7
+ export * from './core/AbstractConnectionFactory';
8
+ export * from './core/query/SimpleQuery';
9
+ export * from './core/query/AbstractQuery';
10
+ export * from './core/query/Page';
11
+ export * from './core/types/ManualConnectionFactory';
12
+ export * from './core/types/ManualConnection';
13
+ export * from './entities/QueryEntityDefinition';
14
+ export * from './entities/ConnectionEntityDefinition';
15
+ export * from './entities/ConnectionFactoryEntityDefinition';
16
+ export * from './entities/SchemaModelDefinitionEntityDefinition';
17
+ export * from './entities/SchemaModelObjectEntityDefinition';
18
+ export * from './panels/query/QueryPanelFactory';
19
+ export * from './panels/model/ModelPanelFactory';
20
+ export * from './stores/ConnectionStore';
21
+ export * from './actions/connections/AddConnectionAction';
22
+ export * from './actions/connections/RemoveConnectionAction';
23
+ export * from './actions/schema-definitions/CreateModelAction';
24
+ export * from './actions/schema-definitions/QuerySchemaModelAction';
25
+ export * from './actions/schema-model/EditSchemaModelAction';
26
+
27
+ export default DataBrowserModule;
@@ -0,0 +1,78 @@
1
+ import * as React from 'react';
2
+ import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
3
+ import { ModelPanelWidget } from './ModelPanelWidget';
4
+ import { ConnectionStore } from '../../stores/ConnectionStore';
5
+ import { computed, observable } from 'mobx';
6
+ import { WorkspaceModelFactoryEvent } from '@projectstorm/react-workspaces-core';
7
+ import { SchemaModelDefinition } from '../../core/SchemaModelDefinition';
8
+ import { SchemaModelObject } from '../../core/SchemaModelObject';
9
+
10
+ export interface ModelPanelModelOptions {
11
+ definition: SchemaModelDefinition;
12
+ model?: SchemaModelObject;
13
+ }
14
+
15
+ export class ModelPanelModel extends ReactorPanelModel {
16
+ @inject(ConnectionStore)
17
+ accessor connStore: ConnectionStore;
18
+
19
+ @observable
20
+ accessor definition: SchemaModelDefinition;
21
+
22
+ @observable
23
+ accessor model: SchemaModelObject;
24
+
25
+ constructor(options?: ModelPanelModelOptions) {
26
+ super(ModelPanelFactory.TYPE);
27
+ this.setExpand(false, true);
28
+ this.definition = options?.definition;
29
+ this.model = options?.model;
30
+ }
31
+
32
+ encodeEntities() {
33
+ return {
34
+ definition: this.definition,
35
+ model: this.model
36
+ };
37
+ }
38
+
39
+ decodeEntities(data: ReturnType<this['encodeEntities']>) {
40
+ this.definition = data.definition;
41
+ this.model = data.model;
42
+ }
43
+ }
44
+
45
+ export class ModelPanelFactory extends ReactorPanelFactory<ModelPanelModel> {
46
+ static TYPE = 'databrowser/model';
47
+
48
+ constructor() {
49
+ super({
50
+ icon: 'cube',
51
+ color: 'mediumpurple',
52
+ name: 'Model',
53
+ allowManualCreation: false,
54
+ isMultiple: true,
55
+ fullscreen: false,
56
+ type: ModelPanelFactory.TYPE,
57
+ category: 'Databrowser'
58
+ });
59
+ }
60
+
61
+ getSimpleName(model: ModelPanelModel) {
62
+ if (!model.definition) {
63
+ return super.getSimpleName(model);
64
+ }
65
+ if (model.model) {
66
+ return `${model.definition.definition.label}: ${model.model.model.toString()}`;
67
+ }
68
+ return `${model.definition.definition.label}`;
69
+ }
70
+
71
+ _generateModel(): ModelPanelModel {
72
+ return new ModelPanelModel(null);
73
+ }
74
+
75
+ generatePanelContent(event: WorkspaceModelFactoryEvent<ModelPanelModel>): React.JSX.Element {
76
+ return <ModelPanelWidget key={event.model.id} model={event.model} />;
77
+ }
78
+ }
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import { useEffect, useState } from 'react';
3
+ import { observer } from 'mobx-react';
4
+ import styled from '@emotion/styled';
5
+ import {
6
+ BorderLayoutWidget,
7
+ LoadingPanelWidget,
8
+ PANEL_CONTENT_PADDING,
9
+ PanelToolbarWidget,
10
+ ScrollableDivCss
11
+ } from '@journeyapps-labs/reactor-mod';
12
+
13
+ import { SchemaModelForm } from '../../forms/SchemaModelForm';
14
+ import { ModelPanelModel } from './ModelPanelFactory';
15
+
16
+ export interface QueryPanelWidgetProps {
17
+ model: ModelPanelModel;
18
+ }
19
+
20
+ namespace S {
21
+ export const Container = styled.div`
22
+ overflow: auto;
23
+ padding: ${PANEL_CONTENT_PADDING}px;
24
+ ${ScrollableDivCss};
25
+ `;
26
+ }
27
+
28
+ export const ModelPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props) => {
29
+ const [form, setForm] = useState<SchemaModelForm>(null);
30
+
31
+ useEffect(() => {
32
+ if (!props.model.definition) {
33
+ return;
34
+ }
35
+ setForm(
36
+ new SchemaModelForm({
37
+ object: props.model.model,
38
+ definition: props.model.definition
39
+ })
40
+ );
41
+ }, [props.model.model, props.model.definition]);
42
+
43
+ let top = null;
44
+ if (props.model.model) {
45
+ top = (
46
+ <PanelToolbarWidget
47
+ btns={
48
+ [
49
+ // {
50
+ // label: 'Delete object',
51
+ // action: () => {}
52
+ // }
53
+ ]
54
+ }
55
+ meta={[
56
+ {
57
+ label: 'ID',
58
+ value: props.model?.id
59
+ }
60
+ ]}
61
+ />
62
+ );
63
+ }
64
+
65
+ return (
66
+ <LoadingPanelWidget loading={!form}>
67
+ {() => {
68
+ return (
69
+ <BorderLayoutWidget top={top}>
70
+ <S.Container>{form.render()}</S.Container>
71
+ </BorderLayoutWidget>
72
+ );
73
+ }}
74
+ </LoadingPanelWidget>
75
+ );
76
+ });
@@ -0,0 +1,52 @@
1
+ import * as React from 'react';
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';
11
+ import { AbstractQuery } from '../../core/query/AbstractQuery';
12
+ import { observer } from 'mobx-react';
13
+ import styled from '@emotion/styled';
14
+ import { DataBrowserEntities } from '../../entities';
15
+ import { SchemaModelObject } from '../../core/SchemaModelObject';
16
+
17
+ export interface PageResultsWidgetProps {
18
+ page: Page;
19
+ query: AbstractQuery;
20
+ }
21
+
22
+ export const PageResultsWidget: React.FC<PageResultsWidgetProps> = observer((props) => {
23
+ const system = ioc.get(System);
24
+
25
+ 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
+ />
44
+ );
45
+ });
46
+
47
+ namespace S {
48
+ export const Container = styled.div`
49
+ overflow: auto;
50
+ ${ScrollableDivCss};
51
+ `;
52
+ }
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
3
+ import { QueryPanelWidget } from './QueryPanelWidget';
4
+ import { AbstractQuery } from '../../core/query/AbstractQuery';
5
+ import { ConnectionStore } from '../../stores/ConnectionStore';
6
+ import { observable } from 'mobx';
7
+ import { WorkspaceModelFactoryEvent } from '@projectstorm/react-workspaces-core';
8
+
9
+ export class QueryPanelModel extends ReactorPanelModel {
10
+ @inject(ConnectionStore)
11
+ accessor connStore: ConnectionStore;
12
+
13
+ @observable
14
+ accessor query: AbstractQuery;
15
+
16
+ @observable
17
+ accessor current_page: number;
18
+
19
+ constructor(query: AbstractQuery) {
20
+ super(QueryPanelFactory.TYPE);
21
+ this.setExpand(true, true);
22
+ this.query = query;
23
+ this.current_page = 0;
24
+ }
25
+
26
+ toArray() {
27
+ return {
28
+ ...super.toArray(),
29
+ current_page: this.current_page
30
+ };
31
+ }
32
+
33
+ fromArray(data: ReturnType<this['toArray']>, engine) {
34
+ super.fromArray(data, engine);
35
+ this.current_page = data.current_page || 0;
36
+ }
37
+
38
+ encodeEntities() {
39
+ return {
40
+ query: this.query
41
+ };
42
+ }
43
+
44
+ decodeEntities(data: ReturnType<this['encodeEntities']>) {
45
+ this.query = data.query;
46
+ }
47
+ }
48
+
49
+ export class QueryPanelFactory extends ReactorPanelFactory<QueryPanelModel> {
50
+ static TYPE = 'query';
51
+
52
+ constructor() {
53
+ super({
54
+ icon: 'table',
55
+ color: 'rgb(0,192,255)',
56
+ name: 'Query',
57
+ allowManualCreation: false,
58
+ isMultiple: true,
59
+ fullscreen: false,
60
+ type: QueryPanelFactory.TYPE,
61
+ category: 'Databrowser'
62
+ });
63
+ }
64
+
65
+ getSimpleName(model: QueryPanelModel): string {
66
+ return model.query?.getSimpleName();
67
+ }
68
+
69
+ _generateModel(): QueryPanelModel {
70
+ return new QueryPanelModel(null);
71
+ }
72
+
73
+ generatePanelContent(event: WorkspaceModelFactoryEvent<QueryPanelModel>): React.JSX.Element {
74
+ return <QueryPanelWidget key={event.model.id} model={event.model} />;
75
+ }
76
+ }
@@ -0,0 +1,72 @@
1
+ import * as React from 'react';
2
+ import { useEffect, useState } from 'react';
3
+ import { QueryPanelModel } from './QueryPanelFactory';
4
+ import { observer } from 'mobx-react';
5
+ import styled from '@emotion/styled';
6
+ import { BorderLayoutWidget, LoadingPanelWidget } from '@journeyapps-labs/reactor-mod';
7
+ import { Page } from '../../core/query/Page';
8
+ import { PageResultsWidget } from './PageResultsWidget';
9
+ import { TableControlsWidget } from './TableControlsWidget';
10
+
11
+ export interface QueryPanelWidgetProps {
12
+ model: QueryPanelModel;
13
+ }
14
+
15
+ namespace S {
16
+ export const Container = styled.div`
17
+ position: absolute;
18
+ width: 100%;
19
+ height: 100%;
20
+ `;
21
+ }
22
+
23
+ export const QueryPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props) => {
24
+ const [page, setPage] = useState<Page>(null);
25
+ useEffect(() => {
26
+ if (!props.model.query) {
27
+ return;
28
+ }
29
+ props.model.query.load();
30
+ }, [props.model.query]);
31
+
32
+ useEffect(() => {
33
+ if (props.model.query) {
34
+ setPage(props.model.query.getPage(props.model.current_page));
35
+ }
36
+ }, [props.model.query]);
37
+
38
+ return (
39
+ <LoadingPanelWidget loading={!props.model.query || !page}>
40
+ {() => {
41
+ return (
42
+ <S.Container>
43
+ <BorderLayoutWidget
44
+ top={
45
+ <TableControlsWidget
46
+ query={props.model.query}
47
+ current_page={page}
48
+ goToPage={(index) => {
49
+ setPage(props.model.query.getPage(index));
50
+ props.model.current_page = index;
51
+ }}
52
+ />
53
+ }
54
+ bottom={
55
+ <TableControlsWidget
56
+ query={props.model.query}
57
+ current_page={page}
58
+ goToPage={(index) => {
59
+ setPage(props.model.query.getPage(index));
60
+ props.model.current_page = index;
61
+ }}
62
+ />
63
+ }
64
+ >
65
+ <PageResultsWidget query={props.model.query} page={page} />
66
+ </BorderLayoutWidget>
67
+ </S.Container>
68
+ );
69
+ }}
70
+ </LoadingPanelWidget>
71
+ );
72
+ });
@@ -0,0 +1,85 @@
1
+ import * as React from 'react';
2
+ import { ComboBoxItem, PanelButtonWidget, PanelDropdownWidget, styled } from '@journeyapps-labs/reactor-mod';
3
+ import { AbstractQuery } from '../../core/query/AbstractQuery';
4
+ import { observer } from 'mobx-react';
5
+ import * as _ from 'lodash';
6
+ import { Page } from '../../core/query/Page';
7
+
8
+ export interface TableControlsWidgetProps {
9
+ current_page: Page;
10
+ goToPage?: (index: number) => any;
11
+ className?: any;
12
+ query: AbstractQuery;
13
+ }
14
+
15
+ export const TableControlsWidget: React.FC<TableControlsWidgetProps> = observer((props) => {
16
+ return (
17
+ <S.Container className={props.className}>
18
+ <PanelButtonWidget
19
+ disabled={props.current_page?.index === 0}
20
+ label="Prev"
21
+ action={() => {
22
+ props.goToPage(props.current_page.index - 1);
23
+ }}
24
+ />
25
+ <S.PageSelector>
26
+ <PanelDropdownWidget
27
+ onChange={({ key }) => {
28
+ props.goToPage(parseInt(key));
29
+ }}
30
+ selected={`${props.current_page.index}`}
31
+ items={_.range(0, props.query.totalPages).map((r) => {
32
+ return {
33
+ title: `${r + 1}`,
34
+ key: `${r}`
35
+ } as ComboBoxItem;
36
+ })}
37
+ />
38
+ <S.TotalPages>/ {props.query.totalPages}</S.TotalPages>
39
+ </S.PageSelector>
40
+ <PanelButtonWidget
41
+ disabled={props.query.totalPages == props.current_page.index + 1}
42
+ label="Next"
43
+ action={() => {
44
+ props.goToPage(props.current_page.index + 1);
45
+ }}
46
+ />
47
+ <PanelButtonWidget
48
+ label="Page"
49
+ tooltip="Reload page"
50
+ icon="refresh"
51
+ action={() => {
52
+ props.current_page.load();
53
+ }}
54
+ />
55
+ <PanelButtonWidget
56
+ label="Query"
57
+ tooltip="Reload Query"
58
+ icon="refresh"
59
+ action={async (event, loading) => {
60
+ await props.query.load();
61
+ }}
62
+ />
63
+ </S.Container>
64
+ );
65
+ });
66
+ namespace S {
67
+ export const Container = styled.div`
68
+ display: flex;
69
+ flex-direction: row;
70
+ column-gap: 5px;
71
+ padding: 5px 5px;
72
+ align-items: center;
73
+ `;
74
+
75
+ export const PageSelector = styled.div`
76
+ display: flex;
77
+ flex-direction: row;
78
+ align-items: center;
79
+ `;
80
+
81
+ export const TotalPages = styled.div`
82
+ color: ${(p) => p.theme.text.primary};
83
+ padding-left: 5px;
84
+ `;
85
+ }