@journeyapps-labs/reactor-mod-data-browser 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/@types/actions/schema-model/ViewSchemaModelAsJsonAction.d.ts +9 -0
- package/dist/@types/forms/TypeEngine.d.ts +13 -2
- package/dist/@types/forms/inputs/DirtyWrapperInput.d.ts +1 -0
- package/dist/@types/index.d.ts +2 -0
- package/dist/@types/panels/_shared/SharedModelPanelFactory.d.ts +22 -0
- package/dist/@types/panels/model/ModelPanelFactory.d.ts +4 -20
- package/dist/@types/panels/model-json/ModelJsonPanelFactory.d.ts +27 -0
- package/dist/@types/panels/model-json/ModelJsonPanelWidget.d.ts +6 -0
- package/dist/DataBrowserModule.js +4 -0
- package/dist/DataBrowserModule.js.map +1 -1
- package/dist/actions/schema-model/ViewSchemaModelAsJsonAction.js +46 -0
- package/dist/actions/schema-model/ViewSchemaModelAsJsonAction.js.map +1 -0
- package/dist/core/SchemaModelDefinition.js +1 -1
- package/dist/core/SchemaModelDefinition.js.map +1 -1
- package/dist/core/query/widgets/CellDisplayWidget.js +14 -81
- package/dist/core/query/widgets/CellDisplayWidget.js.map +1 -1
- package/dist/entities/ConnectionEntityDefinition.js +5 -0
- package/dist/entities/ConnectionEntityDefinition.js.map +1 -1
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js +3 -1
- package/dist/entities/SchemaModelDefinitionEntityDefinition.js.map +1 -1
- package/dist/forms/SchemaModelForm.js +1 -1
- package/dist/forms/SchemaModelForm.js.map +1 -1
- package/dist/forms/TypeEngine.js +223 -5
- package/dist/forms/TypeEngine.js.map +1 -1
- package/dist/forms/inputs/DirtyWrapperInput.js +14 -0
- package/dist/forms/inputs/DirtyWrapperInput.js.map +1 -1
- package/dist/forms/inputs/LocationInput.js +13 -7
- package/dist/forms/inputs/LocationInput.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/panels/_shared/SharedModelPanelFactory.js +77 -0
- package/dist/panels/_shared/SharedModelPanelFactory.js.map +1 -0
- package/dist/panels/model/ModelPanelFactory.js +7 -75
- package/dist/panels/model/ModelPanelFactory.js.map +1 -1
- package/dist/panels/model-json/ModelJsonPanelFactory.js +62 -0
- package/dist/panels/model-json/ModelJsonPanelFactory.js.map +1 -0
- package/dist/panels/model-json/ModelJsonPanelWidget.js +70 -0
- package/dist/panels/model-json/ModelJsonPanelWidget.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist-module/bundle.js +47 -26
- package/dist-module/bundle.js.map +1 -1
- package/package.json +9 -8
- package/src/DataBrowserModule.ts +4 -0
- package/src/actions/schema-model/ViewSchemaModelAsJsonAction.ts +33 -0
- package/src/core/SchemaModelDefinition.ts +1 -1
- package/src/core/query/widgets/CellDisplayWidget.tsx +15 -106
- package/src/entities/ConnectionEntityDefinition.tsx +5 -0
- package/src/entities/SchemaModelDefinitionEntityDefinition.ts +4 -0
- package/src/forms/SchemaModelForm.tsx +1 -1
- package/src/forms/TypeEngine.tsx +451 -0
- package/src/forms/inputs/DirtyWrapperInput.tsx +20 -0
- package/src/forms/inputs/LocationInput.tsx +14 -7
- package/src/index.ts +6 -0
- package/src/panels/_shared/SharedModelPanelFactory.tsx +54 -0
- package/src/panels/model/ModelPanelFactory.tsx +10 -51
- package/src/panels/model-json/ModelJsonPanelFactory.tsx +61 -0
- package/src/panels/model-json/ModelJsonPanelWidget.tsx +92 -0
- package/webpack.config.js +9 -2
- package/src/forms/TypeEngine.ts +0 -160
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Attachment,
|
|
3
|
+
AttachmentType,
|
|
4
|
+
BooleanType,
|
|
5
|
+
DatetimeType,
|
|
6
|
+
DateType,
|
|
7
|
+
Day,
|
|
8
|
+
Location,
|
|
9
|
+
LocationType,
|
|
10
|
+
MultipleChoiceIntegerType,
|
|
11
|
+
MultipleChoiceType,
|
|
12
|
+
NumberType,
|
|
13
|
+
PhotoType,
|
|
14
|
+
SignatureType,
|
|
15
|
+
SingleChoiceIntegerType,
|
|
16
|
+
SingleChoiceType,
|
|
17
|
+
TextType,
|
|
18
|
+
Type
|
|
19
|
+
} from '@journeyapps/db';
|
|
20
|
+
import {
|
|
21
|
+
AbstractMedia,
|
|
22
|
+
BooleanInput,
|
|
23
|
+
CheckboxWidget,
|
|
24
|
+
DateInput,
|
|
25
|
+
DateTimePickerType,
|
|
26
|
+
FileInput,
|
|
27
|
+
FormInput,
|
|
28
|
+
ImageInput,
|
|
29
|
+
ImageMedia,
|
|
30
|
+
inject,
|
|
31
|
+
MediaEngine,
|
|
32
|
+
MetadataWidget,
|
|
33
|
+
NumberInput,
|
|
34
|
+
PanelButtonWidget,
|
|
35
|
+
SelectInput,
|
|
36
|
+
SmartDateDisplayWidget,
|
|
37
|
+
styled,
|
|
38
|
+
TableButtonWidget,
|
|
39
|
+
TextAreaInput,
|
|
40
|
+
TextInput,
|
|
41
|
+
TextInputType,
|
|
42
|
+
MultiSelectInput,
|
|
43
|
+
WorkspaceStore
|
|
44
|
+
} from '@journeyapps-labs/reactor-mod';
|
|
45
|
+
import {} from '@journeyapps-labs/reactor-mod-editor';
|
|
46
|
+
import { LocationInput } from './inputs/LocationInput';
|
|
47
|
+
import * as React from 'react';
|
|
48
|
+
import { JSX } from 'react';
|
|
49
|
+
import { SchemaModelObject } from '../core/SchemaModelObject';
|
|
50
|
+
import * as _ from 'lodash';
|
|
51
|
+
import { ModelJsonPanelModel } from '../panels/model-json/ModelJsonPanelFactory';
|
|
52
|
+
|
|
53
|
+
const MAX_NUMBER_OF_ARR_ITEMS_TO_DISPLAY = 3;
|
|
54
|
+
|
|
55
|
+
export interface TypeHandler<T extends Type = Type, ENCODED = any, DECODED = any> {
|
|
56
|
+
matches: (type: Type) => boolean;
|
|
57
|
+
generateField: (event: { label: string; name: string; type: T }) => FormInput;
|
|
58
|
+
generateDisplay: (event: {
|
|
59
|
+
label: string;
|
|
60
|
+
name: string;
|
|
61
|
+
type: T;
|
|
62
|
+
value: ENCODED;
|
|
63
|
+
model: SchemaModelObject;
|
|
64
|
+
}) => JSX.Element | string;
|
|
65
|
+
decode: (value: ENCODED) => Promise<DECODED>;
|
|
66
|
+
encode: (value: DECODED) => Promise<ENCODED>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class TypeEngine {
|
|
70
|
+
handlers: Set<TypeHandler>;
|
|
71
|
+
|
|
72
|
+
@inject(MediaEngine)
|
|
73
|
+
accessor mediaEngine: MediaEngine;
|
|
74
|
+
|
|
75
|
+
@inject(WorkspaceStore)
|
|
76
|
+
accessor workspaceStore: WorkspaceStore;
|
|
77
|
+
|
|
78
|
+
private _mediaCache: Map<string, AbstractMedia>;
|
|
79
|
+
|
|
80
|
+
constructor() {
|
|
81
|
+
this.handlers = new Set();
|
|
82
|
+
this._mediaCache = new Map();
|
|
83
|
+
this.register({
|
|
84
|
+
matches: (type) => type instanceof DatetimeType || type instanceof DateType,
|
|
85
|
+
encode: async (value: Date) => new Day(value),
|
|
86
|
+
decode: async (value: Day | Date) => {
|
|
87
|
+
if (value instanceof Day) {
|
|
88
|
+
return value.toDate();
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
},
|
|
92
|
+
generateField: ({ label, name, type }) => {
|
|
93
|
+
return new DateInput({
|
|
94
|
+
name,
|
|
95
|
+
label,
|
|
96
|
+
type: type instanceof DatetimeType ? DateTimePickerType.DATETIME : DateTimePickerType.DATE
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
generateDisplay: ({ value }) => {
|
|
100
|
+
if (value instanceof Day) {
|
|
101
|
+
return <SmartDateDisplayWidget date={value.toDate()} />;
|
|
102
|
+
}
|
|
103
|
+
return <SmartDateDisplayWidget date={value} />;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.register({
|
|
108
|
+
matches: (type) => type instanceof SignatureType || type instanceof PhotoType,
|
|
109
|
+
encode: async (value: ImageMedia) => {
|
|
110
|
+
return Attachment.create({
|
|
111
|
+
data: await value.toArrayBuffer()
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
decode: async (value: Attachment) => {
|
|
115
|
+
if (this._mediaCache.has(value.id)) {
|
|
116
|
+
return this._mediaCache.get(value.id);
|
|
117
|
+
}
|
|
118
|
+
let media = this.mediaEngine.getMediaTypeForPath('.jpg').generateMedia({
|
|
119
|
+
content: await value.toArrayBuffer(),
|
|
120
|
+
name: value.id,
|
|
121
|
+
uid: value.id
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
this._mediaCache.set(value.id, media);
|
|
125
|
+
return media;
|
|
126
|
+
},
|
|
127
|
+
generateField: ({ label, name }) => {
|
|
128
|
+
return new ImageInput({
|
|
129
|
+
name,
|
|
130
|
+
label
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
generateDisplay: ({ value, type }) => {
|
|
134
|
+
if (value.uploaded()) {
|
|
135
|
+
return (
|
|
136
|
+
<S.Preview
|
|
137
|
+
onClick={() => {
|
|
138
|
+
this.getHandler(type)
|
|
139
|
+
.decode(value)
|
|
140
|
+
.then((media: ImageMedia) => {
|
|
141
|
+
if (media instanceof ImageMedia) {
|
|
142
|
+
media.open();
|
|
143
|
+
} else {
|
|
144
|
+
window.open(value.url(), '_blank');
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}}
|
|
148
|
+
src={value.urls['thumbnail']}
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return <S.Empty>Not uploaded</S.Empty>;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
this.register({
|
|
157
|
+
matches: (type) => type instanceof AttachmentType,
|
|
158
|
+
encode: async (value: File) => {
|
|
159
|
+
return Attachment.create({
|
|
160
|
+
data: await value.arrayBuffer(),
|
|
161
|
+
filename: value.name
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
decode: async (value: Attachment) => {
|
|
165
|
+
return new File([await value.toArrayBuffer()], value.id);
|
|
166
|
+
},
|
|
167
|
+
generateField: ({ label, name }) => {
|
|
168
|
+
return new FileInput({
|
|
169
|
+
name,
|
|
170
|
+
label
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
generateDisplay: ({ value }) => {
|
|
174
|
+
return (
|
|
175
|
+
<TableButtonWidget
|
|
176
|
+
icon="download"
|
|
177
|
+
action={() => {
|
|
178
|
+
window.open(value.url(), '_blank');
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
this.register({
|
|
185
|
+
matches: (type) => type instanceof BooleanType,
|
|
186
|
+
encode: async (value: boolean) => value,
|
|
187
|
+
decode: async (value: boolean) => value,
|
|
188
|
+
generateField: ({ label, name }) => {
|
|
189
|
+
return new BooleanInput({
|
|
190
|
+
name,
|
|
191
|
+
label
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
generateDisplay: ({ value, type, name, model }) => {
|
|
195
|
+
return (
|
|
196
|
+
<CheckboxWidget
|
|
197
|
+
checked={value}
|
|
198
|
+
onChange={(checked) => {
|
|
199
|
+
model.set(name, checked);
|
|
200
|
+
}}
|
|
201
|
+
/>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
this.register({
|
|
207
|
+
matches: (type) => type instanceof NumberType,
|
|
208
|
+
encode: async (value: number) => value,
|
|
209
|
+
decode: async (value: number) => value,
|
|
210
|
+
generateField: ({ label, name }) => {
|
|
211
|
+
return new NumberInput({
|
|
212
|
+
name,
|
|
213
|
+
label
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
generateDisplay: ({ value, type, name, model }) => {
|
|
217
|
+
return `${value}`;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
this.register<TextType, string, string>({
|
|
222
|
+
matches: (type) => type instanceof TextType,
|
|
223
|
+
encode: async (value: string) => value,
|
|
224
|
+
decode: async (value: string) => value,
|
|
225
|
+
generateField: ({ label, name, type }) => {
|
|
226
|
+
if (type.subType == 'paragraph') {
|
|
227
|
+
return new TextAreaInput({
|
|
228
|
+
name,
|
|
229
|
+
label
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (type.subType == 'password') {
|
|
234
|
+
return new TextInput({
|
|
235
|
+
name,
|
|
236
|
+
label,
|
|
237
|
+
inputType: TextInputType.PASSWORD
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return new TextInput({
|
|
242
|
+
name,
|
|
243
|
+
label
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
generateDisplay: ({ value, type, name, model }) => {
|
|
247
|
+
if (value.trim() === '') {
|
|
248
|
+
return <S.Empty>empty</S.Empty>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (type.subType == 'password') {
|
|
252
|
+
return '****';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (type.subType == 'paragraph') {
|
|
256
|
+
// could be JSON
|
|
257
|
+
if ((value.startsWith('[') && value.endsWith(']')) || (value.startsWith('{') && value.endsWith('}'))) {
|
|
258
|
+
try {
|
|
259
|
+
let parsed = JSON.parse(value);
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<TableButtonWidget
|
|
263
|
+
icon="code"
|
|
264
|
+
label="JSON"
|
|
265
|
+
action={() => {
|
|
266
|
+
this.workspaceStore.addModel(
|
|
267
|
+
new ModelJsonPanelModel({
|
|
268
|
+
definition: model.definition,
|
|
269
|
+
model: model,
|
|
270
|
+
field: name
|
|
271
|
+
})
|
|
272
|
+
);
|
|
273
|
+
}}
|
|
274
|
+
/>
|
|
275
|
+
);
|
|
276
|
+
} catch (ex) {}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (type.subType == 'url') {
|
|
281
|
+
return (
|
|
282
|
+
<S.Container>
|
|
283
|
+
{value}
|
|
284
|
+
<TableButtonWidget
|
|
285
|
+
icon="arrow-right"
|
|
286
|
+
action={() => {
|
|
287
|
+
window.open(value, '_blank');
|
|
288
|
+
}}
|
|
289
|
+
/>
|
|
290
|
+
</S.Container>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return <S.Max>{value}</S.Max>;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
this.register({
|
|
298
|
+
matches: (type) => type instanceof LocationType,
|
|
299
|
+
encode: async (value: Location) => value,
|
|
300
|
+
decode: async (value: Location) => value,
|
|
301
|
+
generateField: ({ label, name }) => {
|
|
302
|
+
return new LocationInput({
|
|
303
|
+
name,
|
|
304
|
+
label
|
|
305
|
+
});
|
|
306
|
+
},
|
|
307
|
+
generateDisplay: ({ value }) => {
|
|
308
|
+
return (
|
|
309
|
+
<>
|
|
310
|
+
<MetadataWidget label={'Lat'} value={`${value.latitude}`} />
|
|
311
|
+
<MetadataWidget label={'Long'} value={`${value.longitude}`} />
|
|
312
|
+
</>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
this.register({
|
|
318
|
+
matches: (type) => type instanceof SingleChoiceIntegerType,
|
|
319
|
+
encode: async (value: string) => parseInt(value),
|
|
320
|
+
decode: async (value: number) => `${value}`,
|
|
321
|
+
generateField: ({ label, name, type }) => {
|
|
322
|
+
return new SelectInput({
|
|
323
|
+
name,
|
|
324
|
+
label,
|
|
325
|
+
options: _.mapValues(type.options, (o) => `${o.value}`)
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
generateDisplay: ({ value, type, name, model, label }) => {
|
|
329
|
+
return `${value}`;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
this.register({
|
|
334
|
+
matches: (type) => type instanceof SingleChoiceType,
|
|
335
|
+
encode: async (value: string) => value,
|
|
336
|
+
decode: async (value: string) => value,
|
|
337
|
+
generateField: ({ label, name, type }) => {
|
|
338
|
+
return new SelectInput({
|
|
339
|
+
name,
|
|
340
|
+
label,
|
|
341
|
+
options: _.mapValues(type.options, (o) => `${o.value}`)
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
generateDisplay: ({ value }) => {
|
|
345
|
+
return value;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
this.register({
|
|
350
|
+
matches: (type) => type instanceof MultipleChoiceType,
|
|
351
|
+
encode: async (value: string[]) => value,
|
|
352
|
+
decode: async (value: string[]) => value,
|
|
353
|
+
generateField: ({ label, name, type }) => {
|
|
354
|
+
return new MultiSelectInput({
|
|
355
|
+
name,
|
|
356
|
+
label,
|
|
357
|
+
options: _.mapValues(type.options, (o) => `${o.value}`)
|
|
358
|
+
});
|
|
359
|
+
},
|
|
360
|
+
generateDisplay: ({ value }) => {
|
|
361
|
+
return this.displayArray(value);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
this.register({
|
|
366
|
+
matches: (type) => type instanceof MultipleChoiceIntegerType,
|
|
367
|
+
encode: async (value: string[]) => value.map((v) => parseInt(v)),
|
|
368
|
+
decode: async (value: number[]) => value.map((v) => `${v}`),
|
|
369
|
+
generateField: ({ label, name, type }) => {
|
|
370
|
+
return new MultiSelectInput({
|
|
371
|
+
name,
|
|
372
|
+
label,
|
|
373
|
+
options: _.mapValues(type.options, (o) => `${o.value}`)
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
generateDisplay: ({ value }) => {
|
|
377
|
+
return this.displayArray(value);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
displayArray(value: any[]) {
|
|
383
|
+
if (value.length === 0) {
|
|
384
|
+
return <S.Empty>empty array</S.Empty>;
|
|
385
|
+
}
|
|
386
|
+
let items = _.slice(value, 0, MAX_NUMBER_OF_ARR_ITEMS_TO_DISPLAY);
|
|
387
|
+
return (
|
|
388
|
+
<S.Pills>
|
|
389
|
+
{items.map((c) => {
|
|
390
|
+
return <S.pill key={c}>{c}</S.pill>;
|
|
391
|
+
})}
|
|
392
|
+
{items.length !== value.length ? '...' : null}
|
|
393
|
+
</S.Pills>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
getHandler(type: Type) {
|
|
398
|
+
for (let handler of this.handlers) {
|
|
399
|
+
if (handler.matches(type)) {
|
|
400
|
+
return handler;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
register<T extends Type = Type, ENCODED = any, DECODED = any>(handler: TypeHandler<T, ENCODED, DECODED>) {
|
|
407
|
+
this.handlers.add(handler);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
namespace S {
|
|
412
|
+
export const Preview = styled.img`
|
|
413
|
+
max-height: 40px;
|
|
414
|
+
max-width: 40px;
|
|
415
|
+
cursor: pointer;
|
|
416
|
+
`;
|
|
417
|
+
|
|
418
|
+
export const Empty = styled.div`
|
|
419
|
+
opacity: 0.2;
|
|
420
|
+
`;
|
|
421
|
+
|
|
422
|
+
export const Max = styled.div`
|
|
423
|
+
max-width: 500px;
|
|
424
|
+
white-space: pre;
|
|
425
|
+
display: inline;
|
|
426
|
+
overflow: hidden;
|
|
427
|
+
text-overflow: ellipsis;
|
|
428
|
+
`;
|
|
429
|
+
|
|
430
|
+
export const Container = styled.div`
|
|
431
|
+
display: flex;
|
|
432
|
+
flex-direction: row;
|
|
433
|
+
column-gap: 5px;
|
|
434
|
+
align-items: center;
|
|
435
|
+
justify-content: space-between;
|
|
436
|
+
flex-grow: 1;
|
|
437
|
+
`;
|
|
438
|
+
|
|
439
|
+
export const pill = styled.div`
|
|
440
|
+
padding: 2px 4px;
|
|
441
|
+
background: ${(p) => p.theme.table.pills};
|
|
442
|
+
border-radius: 3px;
|
|
443
|
+
font-size: 12px;
|
|
444
|
+
`;
|
|
445
|
+
|
|
446
|
+
export const Pills = styled.div`
|
|
447
|
+
display: flex;
|
|
448
|
+
column-gap: 2px;
|
|
449
|
+
row-gap: 2px;
|
|
450
|
+
`;
|
|
451
|
+
}
|
|
@@ -29,6 +29,12 @@ export class DirtyWrapperInput extends FormInput {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
clear() {
|
|
33
|
+
if (this.object) {
|
|
34
|
+
this.object.set(this.input.name, null);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
@computed get dirty() {
|
|
33
39
|
return this.object?.patch.has(this.input.name);
|
|
34
40
|
}
|
|
@@ -54,6 +60,14 @@ export const Wrapper: React.FC<React.PropsWithChildren<WrapperProps>> = observer
|
|
|
54
60
|
}}
|
|
55
61
|
/>
|
|
56
62
|
) : null}
|
|
63
|
+
{props.input.value != null ? (
|
|
64
|
+
<S.ClearButton
|
|
65
|
+
icon="close"
|
|
66
|
+
onClick={() => {
|
|
67
|
+
props.input.clear();
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
) : null}
|
|
57
71
|
</S.Container>
|
|
58
72
|
);
|
|
59
73
|
});
|
|
@@ -72,4 +86,10 @@ namespace S {
|
|
|
72
86
|
padding: 5px;
|
|
73
87
|
cursor: pointer;
|
|
74
88
|
`;
|
|
89
|
+
export const ClearButton = styled(FontAwesomeIcon)`
|
|
90
|
+
color: ${(p) => p.theme.text.secondary};
|
|
91
|
+
font-size: 12px;
|
|
92
|
+
padding: 5px;
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
`;
|
|
75
95
|
}
|
|
@@ -21,12 +21,12 @@ export class LocationInput extends FormInput<FormInputGenerics & { VALUE: Locati
|
|
|
21
21
|
this.latitude = new NumberInput({
|
|
22
22
|
name: 'latitude',
|
|
23
23
|
label: 'Latitude',
|
|
24
|
-
value: options.value?.latitude
|
|
24
|
+
value: options.value?.latitude || null
|
|
25
25
|
});
|
|
26
26
|
this.longitude = new NumberInput({
|
|
27
27
|
name: 'longitude',
|
|
28
28
|
label: 'Longitude',
|
|
29
|
-
value: options.value?.longitude
|
|
29
|
+
value: options.value?.longitude || null
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
this.update();
|
|
@@ -42,19 +42,26 @@ export class LocationInput extends FormInput<FormInputGenerics & { VALUE: Locati
|
|
|
42
42
|
|
|
43
43
|
setValue(value: Location) {
|
|
44
44
|
super.setValue(value);
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
let lat = value?.latitude || null;
|
|
47
|
+
let lon = value?.longitude || null;
|
|
48
|
+
|
|
49
|
+
if (this.latitude.value !== lat) {
|
|
50
|
+
this.latitude.setValue(lat);
|
|
47
51
|
}
|
|
48
|
-
if (this.longitude.value !==
|
|
49
|
-
this.longitude.setValue(
|
|
52
|
+
if (this.longitude.value !== lon) {
|
|
53
|
+
this.longitude.setValue(lon);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
update() {
|
|
54
58
|
let lat = this.latitude.value;
|
|
55
59
|
let long = this.longitude.value;
|
|
56
|
-
if (lat == null
|
|
60
|
+
if (lat == null && long === null) {
|
|
57
61
|
this.setValue(null);
|
|
62
|
+
this.setError(null);
|
|
63
|
+
} else if (lat == null || long === null) {
|
|
64
|
+
this.setError('Invalid location');
|
|
58
65
|
} else {
|
|
59
66
|
this.setValue(
|
|
60
67
|
new Location({
|
package/src/index.ts
CHANGED
|
@@ -10,18 +10,24 @@ export * from './core/query/AbstractQuery';
|
|
|
10
10
|
export * from './core/query/Page';
|
|
11
11
|
export * from './core/types/ManualConnectionFactory';
|
|
12
12
|
export * from './core/types/ManualConnection';
|
|
13
|
+
|
|
13
14
|
export * from './entities/QueryEntityDefinition';
|
|
14
15
|
export * from './entities/ConnectionEntityDefinition';
|
|
15
16
|
export * from './entities/ConnectionFactoryEntityDefinition';
|
|
16
17
|
export * from './entities/SchemaModelDefinitionEntityDefinition';
|
|
17
18
|
export * from './entities/SchemaModelObjectEntityDefinition';
|
|
19
|
+
|
|
18
20
|
export * from './panels/query/QueryPanelFactory';
|
|
19
21
|
export * from './panels/model/ModelPanelFactory';
|
|
22
|
+
export * from './panels/_shared/SharedModelPanelFactory';
|
|
23
|
+
|
|
20
24
|
export * from './stores/ConnectionStore';
|
|
25
|
+
|
|
21
26
|
export * from './actions/connections/AddConnectionAction';
|
|
22
27
|
export * from './actions/connections/RemoveConnectionAction';
|
|
23
28
|
export * from './actions/schema-definitions/CreateModelAction';
|
|
24
29
|
export * from './actions/schema-definitions/QuerySchemaModelAction';
|
|
25
30
|
export * from './actions/schema-model/EditSchemaModelAction';
|
|
31
|
+
export * from './actions/schema-model/EditSchemaModelAction';
|
|
26
32
|
|
|
27
33
|
export default DataBrowserModule;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
|
|
2
|
+
import { ConnectionStore } from '../../stores/ConnectionStore';
|
|
3
|
+
import { observable } from 'mobx';
|
|
4
|
+
import { SchemaModelDefinition } from '../../core/SchemaModelDefinition';
|
|
5
|
+
import { SchemaModelObject } from '../../core/SchemaModelObject';
|
|
6
|
+
|
|
7
|
+
export interface SharedModelPanelModelOptions {
|
|
8
|
+
definition: SchemaModelDefinition;
|
|
9
|
+
model: SchemaModelObject;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class SharedModelPanelModel extends ReactorPanelModel {
|
|
13
|
+
@inject(ConnectionStore)
|
|
14
|
+
accessor connStore: ConnectionStore;
|
|
15
|
+
|
|
16
|
+
@observable
|
|
17
|
+
accessor definition: SchemaModelDefinition;
|
|
18
|
+
|
|
19
|
+
@observable
|
|
20
|
+
accessor model: SchemaModelObject;
|
|
21
|
+
|
|
22
|
+
constructor(type: string, options?: SharedModelPanelModelOptions) {
|
|
23
|
+
super(type);
|
|
24
|
+
this.setExpand(false, true);
|
|
25
|
+
this.definition = options?.definition;
|
|
26
|
+
this.model = options?.model;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
encodeEntities() {
|
|
30
|
+
return {
|
|
31
|
+
definition: this.definition,
|
|
32
|
+
model: this.model?.model ? this.model : null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async decodeEntities(data: ReturnType<this['encodeEntities']>) {
|
|
37
|
+
this.definition = data.definition;
|
|
38
|
+
this.model = data.model || (await data.definition.generateNewModelObject());
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export abstract class SharedModelPanelFactory<T extends SharedModelPanelModel> extends ReactorPanelFactory<T> {
|
|
43
|
+
getSimpleName(model: T) {
|
|
44
|
+
let _model = model.model;
|
|
45
|
+
let _definition = model.definition;
|
|
46
|
+
if (!_definition) {
|
|
47
|
+
return super.getSimpleName(model);
|
|
48
|
+
}
|
|
49
|
+
if (_model) {
|
|
50
|
+
return `${_definition.definition.label}: ${_model.data?.display || '(new object)'}`;
|
|
51
|
+
}
|
|
52
|
+
return `${_definition.definition.label}`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,48 +1,19 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { inject, ReactorPanelFactory, ReactorPanelModel } from '@journeyapps-labs/reactor-mod';
|
|
3
2
|
import { ModelPanelWidget } from './ModelPanelWidget';
|
|
4
|
-
import { ConnectionStore } from '../../stores/ConnectionStore';
|
|
5
|
-
import { observable } from 'mobx';
|
|
6
3
|
import { WorkspaceModelFactoryEvent } from '@projectstorm/react-workspaces-core';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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?.model ? this.model : null
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async decodeEntities(data: ReturnType<this['encodeEntities']>) {
|
|
40
|
-
this.definition = data.definition;
|
|
41
|
-
this.model = data.model || (await data.definition.generateNewModelObject());
|
|
4
|
+
import {
|
|
5
|
+
SharedModelPanelFactory,
|
|
6
|
+
SharedModelPanelModel,
|
|
7
|
+
SharedModelPanelModelOptions
|
|
8
|
+
} from '../_shared/SharedModelPanelFactory';
|
|
9
|
+
|
|
10
|
+
export class ModelPanelModel extends SharedModelPanelModel {
|
|
11
|
+
constructor(options?: SharedModelPanelModelOptions) {
|
|
12
|
+
super(ModelPanelFactory.TYPE, options);
|
|
42
13
|
}
|
|
43
14
|
}
|
|
44
15
|
|
|
45
|
-
export class ModelPanelFactory extends
|
|
16
|
+
export class ModelPanelFactory extends SharedModelPanelFactory<ModelPanelModel> {
|
|
46
17
|
static TYPE = 'databrowser/model';
|
|
47
18
|
|
|
48
19
|
constructor() {
|
|
@@ -58,18 +29,6 @@ export class ModelPanelFactory extends ReactorPanelFactory<ModelPanelModel> {
|
|
|
58
29
|
});
|
|
59
30
|
}
|
|
60
31
|
|
|
61
|
-
getSimpleName(model: ModelPanelModel) {
|
|
62
|
-
let _model = model.model;
|
|
63
|
-
let _definition = model.definition;
|
|
64
|
-
if (!_definition) {
|
|
65
|
-
return super.getSimpleName(model);
|
|
66
|
-
}
|
|
67
|
-
if (_model) {
|
|
68
|
-
return `${_definition.definition.label}: ${_model.data?.display || '(new object)'}`;
|
|
69
|
-
}
|
|
70
|
-
return `${_definition.definition.label}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
32
|
_generateModel(): ModelPanelModel {
|
|
74
33
|
return new ModelPanelModel(null);
|
|
75
34
|
}
|