@jupytergis/base 0.1.1

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 (108) hide show
  1. package/lib/commands.d.ts +11 -0
  2. package/lib/commands.js +809 -0
  3. package/lib/console/consoleview.d.ts +24 -0
  4. package/lib/console/consoleview.js +55 -0
  5. package/lib/console/index.d.ts +1 -0
  6. package/lib/console/index.js +1 -0
  7. package/lib/constants.d.ts +57 -0
  8. package/lib/constants.js +89 -0
  9. package/lib/dialogs/components/symbology/BandRendering.d.ts +4 -0
  10. package/lib/dialogs/components/symbology/BandRendering.js +29 -0
  11. package/lib/dialogs/components/symbology/BandRow.d.ts +10 -0
  12. package/lib/dialogs/components/symbology/BandRow.js +43 -0
  13. package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +20 -0
  14. package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +281 -0
  15. package/lib/dialogs/components/symbology/StopRow.d.ts +11 -0
  16. package/lib/dialogs/components/symbology/StopRow.js +58 -0
  17. package/lib/dialogs/formdialog.d.ts +31 -0
  18. package/lib/dialogs/formdialog.js +68 -0
  19. package/lib/dialogs/layerBrowserDialog.d.ts +25 -0
  20. package/lib/dialogs/layerBrowserDialog.js +141 -0
  21. package/lib/dialogs/symbologyDialog.d.ts +23 -0
  22. package/lib/dialogs/symbologyDialog.js +68 -0
  23. package/lib/dialogs/terrainDialog.d.ts +21 -0
  24. package/lib/dialogs/terrainDialog.js +60 -0
  25. package/lib/formbuilder/creationform.d.ts +56 -0
  26. package/lib/formbuilder/creationform.js +117 -0
  27. package/lib/formbuilder/editform.d.ts +24 -0
  28. package/lib/formbuilder/editform.js +60 -0
  29. package/lib/formbuilder/formselectors.d.ts +5 -0
  30. package/lib/formbuilder/formselectors.js +38 -0
  31. package/lib/formbuilder/index.d.ts +6 -0
  32. package/lib/formbuilder/index.js +6 -0
  33. package/lib/formbuilder/objectform/baseform.d.ts +79 -0
  34. package/lib/formbuilder/objectform/baseform.js +167 -0
  35. package/lib/formbuilder/objectform/geojsonsource.d.ts +19 -0
  36. package/lib/formbuilder/objectform/geojsonsource.js +80 -0
  37. package/lib/formbuilder/objectform/hillshadeLayerForm.d.ts +8 -0
  38. package/lib/formbuilder/objectform/hillshadeLayerForm.js +12 -0
  39. package/lib/formbuilder/objectform/layerform.d.ts +19 -0
  40. package/lib/formbuilder/objectform/layerform.js +17 -0
  41. package/lib/formbuilder/objectform/tilesourceform.d.ts +7 -0
  42. package/lib/formbuilder/objectform/tilesourceform.js +60 -0
  43. package/lib/formbuilder/objectform/vectorlayerform.d.ts +15 -0
  44. package/lib/formbuilder/objectform/vectorlayerform.js +88 -0
  45. package/lib/formbuilder/objectform/webGlLayerForm.d.ts +8 -0
  46. package/lib/formbuilder/objectform/webGlLayerForm.js +10 -0
  47. package/lib/icons.d.ts +6 -0
  48. package/lib/icons.js +31 -0
  49. package/lib/index.d.ts +10 -0
  50. package/lib/index.js +10 -0
  51. package/lib/mainview/index.d.ts +3 -0
  52. package/lib/mainview/index.js +3 -0
  53. package/lib/mainview/mainView.d.ts +113 -0
  54. package/lib/mainview/mainView.js +743 -0
  55. package/lib/mainview/mainviewmodel.d.ts +24 -0
  56. package/lib/mainview/mainviewmodel.js +34 -0
  57. package/lib/mainview/mainviewwidget.d.ts +14 -0
  58. package/lib/mainview/mainviewwidget.js +18 -0
  59. package/lib/mainview/spinner.d.ts +6 -0
  60. package/lib/mainview/spinner.js +5 -0
  61. package/lib/panelview/components/filter-panel/Filter.d.ts +19 -0
  62. package/lib/panelview/components/filter-panel/Filter.js +223 -0
  63. package/lib/panelview/components/filter-panel/FilterRow.d.ts +9 -0
  64. package/lib/panelview/components/filter-panel/FilterRow.js +61 -0
  65. package/lib/panelview/components/layers.d.ts +13 -0
  66. package/lib/panelview/components/layers.js +275 -0
  67. package/lib/panelview/components/sources.d.ts +10 -0
  68. package/lib/panelview/components/sources.js +147 -0
  69. package/lib/panelview/header.d.ts +11 -0
  70. package/lib/panelview/header.js +20 -0
  71. package/lib/panelview/index.d.ts +5 -0
  72. package/lib/panelview/index.js +5 -0
  73. package/lib/panelview/leftpanel.d.ts +51 -0
  74. package/lib/panelview/leftpanel.js +125 -0
  75. package/lib/panelview/model.d.ts +19 -0
  76. package/lib/panelview/model.js +30 -0
  77. package/lib/panelview/objectproperties.d.ts +17 -0
  78. package/lib/panelview/objectproperties.js +92 -0
  79. package/lib/panelview/rightpanel.d.ts +19 -0
  80. package/lib/panelview/rightpanel.js +45 -0
  81. package/lib/toolbar/index.d.ts +2 -0
  82. package/lib/toolbar/index.js +2 -0
  83. package/lib/toolbar/usertoolbaritem.d.ts +19 -0
  84. package/lib/toolbar/usertoolbaritem.js +57 -0
  85. package/lib/toolbar/widget.d.ts +22 -0
  86. package/lib/toolbar/widget.js +104 -0
  87. package/lib/tools.d.ts +25 -0
  88. package/lib/tools.js +215 -0
  89. package/lib/types.d.ts +11 -0
  90. package/lib/types.js +1 -0
  91. package/lib/widget.d.ts +49 -0
  92. package/lib/widget.js +144 -0
  93. package/package.json +95 -0
  94. package/style/base.css +55 -0
  95. package/style/colorExpression.css +36 -0
  96. package/style/dialog.css +8 -0
  97. package/style/filterPanel.css +70 -0
  98. package/style/icons/geojson.svg +12 -0
  99. package/style/icons/mound.svg +9 -0
  100. package/style/icons/nonvisibility.svg +8 -0
  101. package/style/icons/raster.svg +5 -0
  102. package/style/icons/visibility.svg +7 -0
  103. package/style/index.css +6 -0
  104. package/style/index.js +6 -0
  105. package/style/layerBrowser.css +256 -0
  106. package/style/leftPanel.css +150 -0
  107. package/style/symbologyDialog.css +86 -0
  108. package/style/terrainDialog.css +14 -0
@@ -0,0 +1,117 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { deepCopy } from '../tools';
13
+ import { PromiseDelegate, UUID } from '@lumino/coreutils';
14
+ import { Signal } from '@lumino/signaling';
15
+ import * as React from 'react';
16
+ import { getLayerTypeForm, getSourceTypeForm } from './formselectors';
17
+ /**
18
+ * Form for creating a source, a layer or both at the same time
19
+ */
20
+ export class CreationForm extends React.Component {
21
+ constructor(props) {
22
+ super(props);
23
+ this.sourceFormChangedSignal = new Signal(this);
24
+ this.filePath = props.context.path;
25
+ this.jGISModel = props.context.model;
26
+ }
27
+ render() {
28
+ var _a;
29
+ const sourceId = UUID.uuid4();
30
+ let layerSchema = undefined;
31
+ const LayerForm = getLayerTypeForm(this.props.layerType || 'RasterLayer');
32
+ const layerData = deepCopy(this.props.layerData || {});
33
+ if (this.props.createLayer) {
34
+ if (!this.props.layerType) {
35
+ console.error('Cannot create a layer without specifying its type');
36
+ return;
37
+ }
38
+ layerSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(this.props.layerType));
39
+ if (!layerSchema) {
40
+ console.error(`Cannot find schema for ${this.props.layerType}`);
41
+ return;
42
+ }
43
+ // If a source is created as part of this form, remove the source selection from the layer form
44
+ if (this.props.createSource) {
45
+ (_a = layerSchema.properties) === null || _a === void 0 ? true : delete _a.source;
46
+ layerData.source = sourceId;
47
+ }
48
+ layerSchema['required'] = ['name', ...layerSchema['required']];
49
+ layerSchema['properties'] = Object.assign({ name: { type: 'string', description: 'The name of the layer' } }, layerSchema['properties']);
50
+ }
51
+ let sourceSchema = undefined;
52
+ const SourceForm = getSourceTypeForm(this.props.sourceType || 'RasterSource');
53
+ if (this.props.sourceType) {
54
+ sourceSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(this.props.sourceType));
55
+ if (!sourceSchema) {
56
+ console.error(`Cannot find schema for ${this.props.sourceType}`);
57
+ return;
58
+ }
59
+ if (!this.props.createLayer) {
60
+ sourceSchema['required'] = ['name', ...sourceSchema['required']];
61
+ sourceSchema['properties'] = Object.assign({ name: { type: 'string', description: 'The name of the source' } }, sourceSchema['properties']);
62
+ }
63
+ }
64
+ const creationPromises = [];
65
+ let layerCreationPromise;
66
+ let sourceCreationPromise;
67
+ if (this.props.createLayer) {
68
+ layerCreationPromise = new PromiseDelegate();
69
+ creationPromises.push(layerCreationPromise.promise);
70
+ }
71
+ if (this.props.createSource) {
72
+ sourceCreationPromise = new PromiseDelegate();
73
+ creationPromises.push(sourceCreationPromise.promise);
74
+ }
75
+ // Perform the layer/source creation
76
+ Promise.all(creationPromises).then(async () => {
77
+ if (this.props.createSource) {
78
+ let actualName = '';
79
+ const _a = (await (sourceCreationPromise === null || sourceCreationPromise === void 0 ? void 0 : sourceCreationPromise.promise)), { name } = _a, sourceData = __rest(_a, ["name"]);
80
+ actualName =
81
+ name ||
82
+ (await (layerCreationPromise === null || layerCreationPromise === void 0 ? void 0 : layerCreationPromise.promise)).name + ' Source';
83
+ const sourceModel = {
84
+ type: this.props.sourceType || 'RasterSource',
85
+ name: actualName,
86
+ parameters: sourceData
87
+ };
88
+ this.jGISModel.sharedModel.addSource(sourceId, sourceModel);
89
+ }
90
+ if (this.props.createLayer) {
91
+ let actualName = '';
92
+ const _b = (await (layerCreationPromise === null || layerCreationPromise === void 0 ? void 0 : layerCreationPromise.promise)), { name } = _b, layerData = __rest(_b, ["name"]);
93
+ actualName =
94
+ name ||
95
+ (await (layerCreationPromise === null || layerCreationPromise === void 0 ? void 0 : layerCreationPromise.promise)).name + ' Layer';
96
+ const layerModel = {
97
+ type: this.props.layerType || 'RasterLayer',
98
+ parameters: layerData,
99
+ visible: true,
100
+ name: actualName
101
+ };
102
+ this.jGISModel.addLayer(UUID.uuid4(), layerModel);
103
+ }
104
+ });
105
+ return (React.createElement("div", null,
106
+ this.props.createSource && (React.createElement("div", null,
107
+ React.createElement("h3", null, "Source Properties"),
108
+ React.createElement(SourceForm, { formContext: "create", model: this.jGISModel, filePath: `${this.filePath}::panel`, schema: sourceSchema, sourceData: this.props.sourceData, syncData: (properties) => {
109
+ sourceCreationPromise === null || sourceCreationPromise === void 0 ? void 0 : sourceCreationPromise.resolve(properties);
110
+ }, ok: this.props.ok, cancel: this.props.cancel, formChangedSignal: this.sourceFormChangedSignal, formErrorSignal: this.props.formErrorSignal }))),
111
+ this.props.createLayer && (React.createElement("div", null,
112
+ React.createElement("h3", null, "Layer Properties"),
113
+ React.createElement(LayerForm, { formContext: "create", sourceType: this.props.sourceType, model: this.jGISModel, filePath: `${this.filePath}::panel`, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
114
+ layerCreationPromise === null || layerCreationPromise === void 0 ? void 0 : layerCreationPromise.resolve(properties);
115
+ }, ok: this.props.ok, cancel: this.props.cancel, sourceFormChangedSignal: this.sourceFormChangedSignal, formErrorSignal: this.props.formErrorSignal })))));
116
+ }
117
+ }
@@ -0,0 +1,24 @@
1
+ import { DocumentRegistry } from '@jupyterlab/docregistry';
2
+ import { IJGISFormSchemaRegistry, IJupyterGISModel } from '@jupytergis/schema';
3
+ import * as React from 'react';
4
+ export interface IEditFormProps {
5
+ /**
6
+ * The layer to edit
7
+ */
8
+ layer: string | undefined;
9
+ /**
10
+ * The source to edit
11
+ */
12
+ source: string | undefined;
13
+ formSchemaRegistry: IJGISFormSchemaRegistry;
14
+ context: DocumentRegistry.IContext<IJupyterGISModel>;
15
+ }
16
+ /**
17
+ * Form for editing a source, a layer or both at the same time
18
+ */
19
+ export declare class EditForm extends React.Component<IEditFormProps, any> {
20
+ syncObjectProperties(id: string | undefined, properties: {
21
+ [key: string]: any;
22
+ }): Promise<void>;
23
+ render(): React.JSX.Element | undefined;
24
+ }
@@ -0,0 +1,60 @@
1
+ import { deepCopy } from '../tools';
2
+ import * as React from 'react';
3
+ import { getLayerTypeForm, getSourceTypeForm } from './formselectors';
4
+ /**
5
+ * Form for editing a source, a layer or both at the same time
6
+ */
7
+ export class EditForm extends React.Component {
8
+ async syncObjectProperties(id, properties) {
9
+ if (!id) {
10
+ return;
11
+ }
12
+ this.props.context.model.sharedModel.updateObjectParameters(id, properties);
13
+ }
14
+ render() {
15
+ let layerSchema = undefined;
16
+ let LayerForm = undefined;
17
+ let layerData = undefined;
18
+ if (this.props.layer) {
19
+ const layer = this.props.context.model.getLayer(this.props.layer);
20
+ if (!layer) {
21
+ return;
22
+ }
23
+ LayerForm = getLayerTypeForm((layer === null || layer === void 0 ? void 0 : layer.type) || 'RasterLayer');
24
+ layerData = deepCopy((layer === null || layer === void 0 ? void 0 : layer.parameters) || {});
25
+ layerSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(layer.type));
26
+ if (!layerSchema) {
27
+ console.error(`Cannot find schema for ${layer.type}`);
28
+ return;
29
+ }
30
+ }
31
+ let sourceSchema = undefined;
32
+ let SourceForm = undefined;
33
+ let sourceData = undefined;
34
+ let source = undefined;
35
+ if (this.props.source) {
36
+ source = this.props.context.model.getSource(this.props.source);
37
+ if (!source) {
38
+ return;
39
+ }
40
+ SourceForm = getSourceTypeForm((source === null || source === void 0 ? void 0 : source.type) || 'RasterSource');
41
+ sourceData = deepCopy((source === null || source === void 0 ? void 0 : source.parameters) || {});
42
+ sourceSchema = deepCopy(this.props.formSchemaRegistry.getSchemas().get(source.type));
43
+ if (!sourceSchema) {
44
+ console.error(`Cannot find schema for ${source.type}`);
45
+ return;
46
+ }
47
+ }
48
+ return (React.createElement("div", null,
49
+ this.props.layer && LayerForm && (React.createElement("div", null,
50
+ React.createElement("h3", null, "Layer Properties"),
51
+ React.createElement(LayerForm, { formContext: "create", sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', model: this.props.context.model, filePath: `${this.props.context.path}::panel`, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
52
+ this.syncObjectProperties(this.props.layer, properties);
53
+ } }))),
54
+ this.props.source && SourceForm && (React.createElement("div", null,
55
+ React.createElement("h3", null, "Source Properties"),
56
+ React.createElement(SourceForm, { formContext: "create", model: this.props.context.model, filePath: `${this.props.context.path}::panel`, schema: sourceSchema, sourceData: sourceData, syncData: (properties) => {
57
+ this.syncObjectProperties(this.props.source, properties);
58
+ } })))));
59
+ }
60
+ }
@@ -0,0 +1,5 @@
1
+ import { LayerType, SourceType } from '@jupytergis/schema';
2
+ import { BaseForm } from './objectform/baseform';
3
+ import { LayerPropertiesForm } from './objectform/layerform';
4
+ export declare function getLayerTypeForm(layerType: LayerType): typeof LayerPropertiesForm;
5
+ export declare function getSourceTypeForm(sourceType: SourceType): typeof BaseForm;
@@ -0,0 +1,38 @@
1
+ import { BaseForm } from './objectform/baseform';
2
+ import { GeoJSONSourcePropertiesForm } from './objectform/geojsonsource';
3
+ import { HillshadeLayerPropertiesForm } from './objectform/hillshadeLayerForm';
4
+ import { LayerPropertiesForm } from './objectform/layerform';
5
+ import { TileSourcePropertiesForm } from './objectform/tilesourceform';
6
+ import { VectorLayerPropertiesForm } from './objectform/vectorlayerform';
7
+ import { WebGlLayerPropertiesForm } from './objectform/webGlLayerForm';
8
+ export function getLayerTypeForm(layerType) {
9
+ let LayerForm = LayerPropertiesForm;
10
+ switch (layerType) {
11
+ case 'VectorTileLayer':
12
+ case 'VectorLayer':
13
+ LayerForm = VectorLayerPropertiesForm;
14
+ break;
15
+ case 'HillshadeLayer':
16
+ LayerForm = HillshadeLayerPropertiesForm;
17
+ break;
18
+ case 'WebGlLayer':
19
+ LayerForm = WebGlLayerPropertiesForm;
20
+ break;
21
+ // ADD MORE FORM TYPES HERE
22
+ }
23
+ return LayerForm;
24
+ }
25
+ export function getSourceTypeForm(sourceType) {
26
+ let SourceForm = BaseForm;
27
+ switch (sourceType) {
28
+ case 'GeoJSONSource':
29
+ SourceForm = GeoJSONSourcePropertiesForm;
30
+ break;
31
+ case 'RasterSource':
32
+ case 'VectorTileSource':
33
+ SourceForm = TileSourcePropertiesForm;
34
+ break;
35
+ // ADD MORE FORM TYPES HERE
36
+ }
37
+ return SourceForm;
38
+ }
@@ -0,0 +1,6 @@
1
+ export * from './objectform/baseform';
2
+ export * from './objectform/geojsonsource';
3
+ export * from './objectform/layerform';
4
+ export * from './objectform/tilesourceform';
5
+ export * from './objectform/vectorlayerform';
6
+ export * from './creationform';
@@ -0,0 +1,6 @@
1
+ export * from './objectform/baseform';
2
+ export * from './objectform/geojsonsource';
3
+ export * from './objectform/layerform';
4
+ export * from './objectform/tilesourceform';
5
+ export * from './objectform/vectorlayerform';
6
+ export * from './creationform';
@@ -0,0 +1,79 @@
1
+ import { IChangeEvent, ISubmitEvent } from '@rjsf/core';
2
+ import * as React from 'react';
3
+ import { IJupyterGISModel } from '@jupytergis/schema';
4
+ import { Dialog } from '@jupyterlab/apputils';
5
+ import { Signal } from '@lumino/signaling';
6
+ import { IDict } from '../../types';
7
+ export interface IBaseFormStates {
8
+ schema?: IDict;
9
+ extraErrors?: any;
10
+ }
11
+ export interface IBaseFormProps {
12
+ /**
13
+ * The context of the form, whether it's for creating an object or updating its properties. This will have the effect of showing or not inputs for readonly properties.
14
+ */
15
+ formContext: 'update' | 'create';
16
+ /**
17
+ * The source data for filling the form
18
+ */
19
+ sourceData: IDict | undefined;
20
+ /**
21
+ * Path to the file
22
+ */
23
+ filePath?: string;
24
+ /**
25
+ * Current GIS model
26
+ */
27
+ model: IJupyterGISModel;
28
+ /**
29
+ * callback for syncing back the data into the model upon form submit
30
+ * @param properties
31
+ */
32
+ syncData: (properties: IDict) => void;
33
+ /**
34
+ * The schema for the rjsf formk
35
+ */
36
+ schema?: IDict;
37
+ /**
38
+ * Ok signal. This is the signal sent by the parent dialog upon "Ok" button click. No ok button will be displayed if defined.
39
+ */
40
+ ok?: Signal<Dialog<any>, number>;
41
+ /**
42
+ * Cancel callback
43
+ */
44
+ cancel?: () => void;
45
+ /**
46
+ * A signal emitting when the form changed
47
+ */
48
+ formChangedSignal?: Signal<any, IDict<any>>;
49
+ /**
50
+ * A signal emitting when the form has extra errors, with a boolean whether there are some
51
+ * extra errors or not.
52
+ */
53
+ formErrorSignal?: Signal<Dialog<any>, boolean>;
54
+ }
55
+ export declare const LuminoSchemaForm: (props: React.PropsWithChildren<any>) => JSX.Element;
56
+ /**
57
+ * Generate a form to edit a layer/source type. This class is meant to be sub-classed to create more refined forms for specific layers/sources.
58
+ *
59
+ * It will be up to the user of this class to actually perform the creation/edit using syncdata.
60
+ */
61
+ export declare class BaseForm extends React.Component<IBaseFormProps, IBaseFormStates> {
62
+ constructor(props: IBaseFormProps);
63
+ componentDidUpdate(prevProps: IBaseFormProps, prevState: IBaseFormStates): void;
64
+ protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
65
+ /**
66
+ * Remove a specific entry from the form. Can be used in subclasses if needed while under processSchema.
67
+ * @param entry The entry name
68
+ * @param data The form data
69
+ * @param schema The form schema
70
+ * @param uiSchema The form uiSchema
71
+ */
72
+ protected removeFormEntry(entry: string, data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
73
+ protected syncData(properties: IDict<any> | undefined): void;
74
+ protected onFormChange(e: IChangeEvent): void;
75
+ protected onFormBlur(id: string, value: any): void;
76
+ protected onFormSubmit(e: ISubmitEvent<any>): void;
77
+ render(): React.ReactNode;
78
+ protected currentFormData: IDict<any> | undefined;
79
+ }
@@ -0,0 +1,167 @@
1
+ import { SchemaForm } from '@deathbeds/jupyterlab-rjsf';
2
+ import { MessageLoop } from '@lumino/messaging';
3
+ import { Widget } from '@lumino/widgets';
4
+ import * as React from 'react';
5
+ import { deepCopy } from '../../tools';
6
+ // Reusing the datalayer/jupyter-react component:
7
+ // https://github.com/datalayer/jupyter-react/blob/main/packages/react/src/jupyter/lumino/Lumino.tsx
8
+ export const LuminoSchemaForm = (props) => {
9
+ const ref = React.useRef(null);
10
+ const { children } = props;
11
+ React.useEffect(() => {
12
+ const widget = children;
13
+ try {
14
+ MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
15
+ ref.current.insertBefore(widget.node, null);
16
+ MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
17
+ }
18
+ catch (e) {
19
+ console.warn('Exception while attaching Lumino widget.', e);
20
+ }
21
+ return () => {
22
+ try {
23
+ if (widget.isAttached || widget.node.isConnected) {
24
+ Widget.detach(widget);
25
+ }
26
+ }
27
+ catch (e) {
28
+ console.warn('Exception while detaching Lumino widget.', e);
29
+ }
30
+ };
31
+ }, [children]);
32
+ return React.createElement("div", { ref: ref });
33
+ };
34
+ /**
35
+ * Generate a form to edit a layer/source type. This class is meant to be sub-classed to create more refined forms for specific layers/sources.
36
+ *
37
+ * It will be up to the user of this class to actually perform the creation/edit using syncdata.
38
+ */
39
+ export class BaseForm extends React.Component {
40
+ constructor(props) {
41
+ super(props);
42
+ this.currentFormData = deepCopy(this.props.sourceData);
43
+ this.state = {
44
+ schema: props.schema,
45
+ extraErrors: {}
46
+ };
47
+ }
48
+ componentDidUpdate(prevProps, prevState) {
49
+ if (prevProps.sourceData !== this.props.sourceData) {
50
+ this.currentFormData = deepCopy(this.props.sourceData);
51
+ const schema = deepCopy(this.props.schema);
52
+ this.setState(old => (Object.assign(Object.assign({}, old), { schema })));
53
+ }
54
+ }
55
+ processSchema(data, schema, uiSchema) {
56
+ if (!schema['properties']) {
57
+ return;
58
+ }
59
+ Object.entries(schema['properties']).forEach(([k, v]) => {
60
+ uiSchema[k] = {};
61
+ if (v['type'] === 'array') {
62
+ // Remove array buttons
63
+ uiSchema[k] = Object.assign({ 'ui:options': {
64
+ orderable: false,
65
+ removable: false,
66
+ addable: false
67
+ } }, uiSchema[k]);
68
+ if (v['items']['type'] === 'array') {
69
+ uiSchema[k] = Object.assign({ items: Object.assign({ 'ui:options': {
70
+ orderable: false,
71
+ removable: false,
72
+ addable: false
73
+ } }, uiSchema[k]['items']) }, uiSchema[k]);
74
+ }
75
+ }
76
+ if (v['type'] === 'object') {
77
+ this.processSchema(data, v, uiSchema[k]);
78
+ }
79
+ // Don't show readOnly properties when it's a form for updating an object
80
+ if (v['readOnly']) {
81
+ if (this.props.formContext === 'create') {
82
+ delete v['readOnly'];
83
+ }
84
+ if (this.props.formContext === 'update') {
85
+ this.removeFormEntry(k, data, schema, uiSchema);
86
+ }
87
+ }
88
+ });
89
+ }
90
+ /**
91
+ * Remove a specific entry from the form. Can be used in subclasses if needed while under processSchema.
92
+ * @param entry The entry name
93
+ * @param data The form data
94
+ * @param schema The form schema
95
+ * @param uiSchema The form uiSchema
96
+ */
97
+ removeFormEntry(entry, data, schema, uiSchema) {
98
+ if (data) {
99
+ delete data[entry];
100
+ }
101
+ delete schema.properties[entry];
102
+ delete uiSchema[entry];
103
+ if (schema.required && schema.required.includes(entry)) {
104
+ schema.required.splice(schema.required.indexOf(entry), 1);
105
+ }
106
+ }
107
+ syncData(properties) {
108
+ if (!properties) {
109
+ return;
110
+ }
111
+ this.props.syncData(properties);
112
+ }
113
+ onFormChange(e) {
114
+ this.currentFormData = e.formData;
115
+ if (this.props.formChangedSignal) {
116
+ this.props.formChangedSignal.emit(this.currentFormData || {});
117
+ }
118
+ if (this.props.formErrorSignal) {
119
+ const extraErrors = Object.keys(this.state.extraErrors).length > 0;
120
+ this.props.formErrorSignal.emit(extraErrors);
121
+ }
122
+ }
123
+ onFormBlur(id, value) {
124
+ // This is a no-op here
125
+ }
126
+ onFormSubmit(e) {
127
+ this.currentFormData = e.formData;
128
+ this.syncData(this.currentFormData);
129
+ this.props.cancel && this.props.cancel();
130
+ }
131
+ render() {
132
+ var _a, _b;
133
+ if (this.props.schema) {
134
+ const schema = Object.assign(Object.assign({}, this.state.schema), { additionalProperties: true });
135
+ const formData = this.currentFormData;
136
+ const uiSchema = {
137
+ additionalProperties: {
138
+ 'ui:label': false,
139
+ classNames: 'jGIS-hidden-field'
140
+ }
141
+ };
142
+ this.processSchema(formData, schema, uiSchema);
143
+ const submitRef = React.createRef();
144
+ // When the parent "ok" button gets clicked, submit
145
+ (_a = this.props.ok) === null || _a === void 0 ? void 0 : _a.connect(() => {
146
+ var _a;
147
+ (_a = submitRef.current) === null || _a === void 0 ? void 0 : _a.click();
148
+ });
149
+ const formSchema = new SchemaForm(schema, {
150
+ liveValidate: true,
151
+ formData,
152
+ onChange: this.onFormChange.bind(this),
153
+ onSubmit: this.onFormSubmit.bind(this),
154
+ onBlur: this.onFormBlur.bind(this),
155
+ uiSchema,
156
+ children: (React.createElement("button", { ref: submitRef, type: "submit", style: { display: 'none' } })),
157
+ extraErrors: this.state.extraErrors
158
+ });
159
+ return (React.createElement("div", { className: "jGIS-property-panel", "data-path": (_b = this.props.filePath) !== null && _b !== void 0 ? _b : '' },
160
+ React.createElement("div", { className: "jGIS-property-outer" },
161
+ React.createElement(LuminoSchemaForm, null, formSchema)),
162
+ !this.props.ok && (React.createElement("div", { className: "jGIS-property-buttons" },
163
+ React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: () => { var _a; return (_a = submitRef.current) === null || _a === void 0 ? void 0 : _a.click(); } },
164
+ React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Ok"))))));
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,19 @@
1
+ import { IDict } from '@jupytergis/schema';
2
+ import { ISubmitEvent } from '@rjsf/core';
3
+ import { BaseForm, IBaseFormProps } from './baseform';
4
+ /**
5
+ * The form to modify a GeoJSON source.
6
+ */
7
+ export declare class GeoJSONSourcePropertiesForm extends BaseForm {
8
+ constructor(props: IBaseFormProps);
9
+ protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
10
+ protected onFormBlur(id: string, value: any): void;
11
+ protected onFormSubmit(e: ISubmitEvent<any>): void;
12
+ /**
13
+ * Validate the path, to avoid invalid path or invalid GeoJSON.
14
+ *
15
+ * @param path - the path to validate.
16
+ */
17
+ private _validatePath;
18
+ private _validate;
19
+ }
@@ -0,0 +1,80 @@
1
+ import { showErrorMessage } from '@jupyterlab/apputils';
2
+ import { Ajv } from 'ajv';
3
+ import * as geojson from 'geojson-schema/GeoJSON.json';
4
+ import { BaseForm } from './baseform';
5
+ /**
6
+ * The form to modify a GeoJSON source.
7
+ */
8
+ export class GeoJSONSourcePropertiesForm extends BaseForm {
9
+ constructor(props) {
10
+ var _a, _b;
11
+ super(props);
12
+ const ajv = new Ajv();
13
+ this._validate = ajv.compile(geojson);
14
+ this._validatePath((_b = (_a = props.sourceData) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '');
15
+ }
16
+ processSchema(data, schema, uiSchema) {
17
+ if ((data === null || data === void 0 ? void 0 : data.path) !== '') {
18
+ this.removeFormEntry('data', data, schema, uiSchema);
19
+ }
20
+ super.processSchema(data, schema, uiSchema);
21
+ if (!schema.properties || !data) {
22
+ return;
23
+ }
24
+ // This is not user-editable
25
+ delete schema.properties.valid;
26
+ }
27
+ onFormBlur(id, value) {
28
+ // Is there a better way to spot the path text entry?
29
+ if (!id.endsWith('_path')) {
30
+ return;
31
+ }
32
+ this._validatePath(value);
33
+ }
34
+ onFormSubmit(e) {
35
+ var _a, _b, _c;
36
+ if (((_c = (_b = (_a = this.state.extraErrors) === null || _a === void 0 ? void 0 : _a.path) === null || _b === void 0 ? void 0 : _b.__errors) === null || _c === void 0 ? void 0 : _c.length) >= 1) {
37
+ showErrorMessage('Invalid JSON file', this.state.extraErrors.path.__errors[0]);
38
+ return;
39
+ }
40
+ super.onFormSubmit(e);
41
+ }
42
+ /**
43
+ * Validate the path, to avoid invalid path or invalid GeoJSON.
44
+ *
45
+ * @param path - the path to validate.
46
+ */
47
+ async _validatePath(path) {
48
+ const extraErrors = {
49
+ path: {
50
+ __errors: []
51
+ }
52
+ };
53
+ this.props.model
54
+ .readGeoJSON(path)
55
+ .then(async (geoJSONData) => {
56
+ var _a;
57
+ const valid = this._validate(geoJSONData);
58
+ if (!valid) {
59
+ extraErrors.path.__errors = [`"${path}" is not a valid GeoJSON file`];
60
+ (_a = this._validate.errors) === null || _a === void 0 ? void 0 : _a.reverse().forEach(error => {
61
+ extraErrors.path.__errors.push(error.message);
62
+ });
63
+ }
64
+ else {
65
+ delete extraErrors.path;
66
+ }
67
+ this.setState({ extraErrors });
68
+ if (this.props.formErrorSignal) {
69
+ this.props.formErrorSignal.emit(!valid);
70
+ }
71
+ })
72
+ .catch(e => {
73
+ extraErrors.path.__errors = [`Cannot read "${path}"`];
74
+ this.setState({ extraErrors });
75
+ if (this.props.formErrorSignal) {
76
+ this.props.formErrorSignal.emit(true);
77
+ }
78
+ });
79
+ }
80
+ }
@@ -0,0 +1,8 @@
1
+ import { IDict } from '@jupytergis/schema';
2
+ import { LayerPropertiesForm } from './layerform';
3
+ /**
4
+ * The form to modify a hillshade layer.
5
+ */
6
+ export declare class HillshadeLayerPropertiesForm extends LayerPropertiesForm {
7
+ protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
8
+ }
@@ -0,0 +1,12 @@
1
+ import { LayerPropertiesForm } from './layerform';
2
+ /**
3
+ * The form to modify a hillshade layer.
4
+ */
5
+ export class HillshadeLayerPropertiesForm extends LayerPropertiesForm {
6
+ processSchema(data, schema, uiSchema) {
7
+ super.processSchema(data, schema, uiSchema);
8
+ uiSchema['shadowColor'] = {
9
+ 'ui:widget': 'color'
10
+ };
11
+ }
12
+ }
@@ -0,0 +1,19 @@
1
+ import { IDict, SourceType } from '@jupytergis/schema';
2
+ import { BaseForm, IBaseFormProps } from './baseform';
3
+ import { Signal } from '@lumino/signaling';
4
+ export interface ILayerProps extends IBaseFormProps {
5
+ /**
6
+ * The source type for the layer
7
+ */
8
+ sourceType: SourceType;
9
+ /**
10
+ * The signal emitted when the attached source form has changed, if it exists
11
+ */
12
+ sourceFormChangedSignal?: Signal<any, IDict<any>>;
13
+ }
14
+ export declare class LayerPropertiesForm extends BaseForm {
15
+ props: ILayerProps;
16
+ protected sourceFormChangedSignal: Signal<any, IDict<any>> | undefined;
17
+ constructor(props: ILayerProps);
18
+ protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
19
+ }