From 0eed7920c7ebf0ba69f01d7b87ee9aa4ac33f925 Mon Sep 17 00:00:00 2001 From: elifsu Date: Wed, 4 Jun 2025 10:29:51 +0200 Subject: [PATCH 01/17] Fix GISDocument not applying projection argument --- packages/base/src/mainview/mainView.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index a0f9d9332..5c0aeeb23 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -323,6 +323,14 @@ export class MainView extends React.Component { ...updatedOptions }); + this.setState(old => ({ + viewProjection: { + ...old.viewProjection, + code: projection.getCode(), + units: projection.getUnits() + } + })); + // Calculate scale if (resolution) { // DPI and inches per meter values taken from OpenLayers @@ -1572,6 +1580,9 @@ export class MainView extends React.Component { } } + view.setRotation(bearing || 0); + this._Map.setView(view); + // Use the extent only if explicitly requested (QGIS files). if (useExtent && extent) { view.fit(extent); @@ -1589,10 +1600,6 @@ export class MainView extends React.Component { this._model.setOptions(options); } } - - view.setRotation(bearing || 0); - - this._Map.setView(view); } private _onViewChanged( From 0276d03685794c0eb430adc84f4655d7e9596264 Mon Sep 17 00:00:00 2001 From: Matt Fisher <3608264+mfisher87@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:12:02 -0600 Subject: [PATCH 02/17] Support importing from path alias `@` (#728) * Attempt support for path alias "@" Co-authored-by: Arjun Verma Co-authored-by: Yao-Ting Yao <94820616+YaoTingYao@users.noreply.github.com> Co-authored-by: Jon Marokhovsky * Support absolute paths with typescript-transform-paths and ts-patch Requires using `tspc` as compiler instead of `tsc`. Would be better to switch to the "use NX" approach of typescript-transform-paths, but I wasn't able to get that to work. Co-authored-by: martinRenou * Revert "Attempt support for path alias "@"" This reverts commit 5f9255b1941b358f3c95b93be9221f9cab1ea6c1. * Remove baseUrl from tsconfig -- it is equivalent to the default value * Lint :bell: * Update all imports which include `../` I skipped updating sibling imports (`import ... from './foo'`) because often sibling imports reflect that the code is tightly coupled. We can always replace those with absolute imports if we feel it's necessary as we continue along. * Lint :bell: --------- Co-authored-by: Arjun Verma Co-authored-by: Yao-Ting Yao <94820616+YaoTingYao@users.noreply.github.com> Co-authored-by: Jon Marokhovsky Co-authored-by: martinRenou --- packages/base/package.json | 10 +- .../src/annotations/components/Annotation.tsx | 2 +- packages/base/src/console/consoleview.ts | 2 +- .../base/src/dialogs/ProcessingFormDialog.tsx | 7 +- .../src/dialogs/layerCreationFormDialog.tsx | 2 +- .../components/color_stops/StopContainer.tsx | 2 +- .../components/color_stops/StopRow.tsx | 2 +- .../dialogs/symbology/hooks/useGetBandInfo.ts | 2 +- .../symbology/hooks/useGetProperties.ts | 2 +- .../symbology/tiff_layer/TiffRendering.tsx | 2 +- .../tiff_layer/components/BandRow.tsx | 2 +- .../tiff_layer/types/MultibandColor.tsx | 8 +- .../types/SingleBandPseudoColor.tsx | 23 +- .../vector_layer/VectorRendering.tsx | 6 +- .../vector_layer/types/Canonical.tsx | 8 +- .../vector_layer/types/Categorized.tsx | 17 +- .../vector_layer/types/Graduated.tsx | 19 +- .../symbology/vector_layer/types/Heatmap.tsx | 4 +- .../vector_layer/types/SimpleSymbol.tsx | 4 +- .../base/src/formbuilder/creationform.tsx | 2 +- packages/base/src/formbuilder/editform.tsx | 2 +- .../src/formbuilder/objectform/baseform.tsx | 4 +- .../objectform/fileselectorwidget.tsx | 2 +- .../objectform/layer/heatmapLayerForm.ts | 2 +- .../formbuilder/objectform/layer/layerform.ts | 5 +- .../process/dissolveProcessForm.tsx | 8 +- .../objectform/source/geojsonsource.ts | 2 +- .../objectform/source/geotiffsource.ts | 4 +- .../objectform/source/pathbasedsource.ts | 4 +- .../objectform/source/sourceform.ts | 5 +- packages/base/src/mainview/TemporalSlider.tsx | 2 +- packages/base/src/mainview/mainView.tsx | 8 +- .../base/src/panelview/annotationPanel.tsx | 4 +- .../components/filter-panel/Filter.tsx | 4 +- .../identify-panel/IdentifyPanel.tsx | 2 +- .../base/src/panelview/components/layers.tsx | 11 +- packages/base/src/panelview/leftpanel.tsx | 4 +- packages/base/src/panelview/model.ts | 2 +- .../base/src/panelview/objectproperties.tsx | 4 +- packages/base/src/panelview/rightpanel.tsx | 2 +- packages/base/src/statusbar/StatusBar.tsx | 2 +- packages/base/src/toolbar/widget.tsx | 6 +- packages/base/src/tools.ts | 4 +- packages/base/tsconfig.json | 9 +- yarn.lock | 206 ++++++++++++------ 45 files changed, 266 insertions(+), 168 deletions(-) diff --git a/packages/base/package.json b/packages/base/package.json index 658c0a4aa..8600705a0 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -27,15 +27,15 @@ "url": "https://github.com/geojupyter/jupytergis.git" }, "scripts": { - "build": "tsc -b && jlpm run cp:gdal", + "build": "tspc -b && jlpm run cp:gdal", "build:gallery": "python rasterlayer_gallery_generator.py", "cp:gdal": "cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.data lib && cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.wasm lib", "build:prod": "jlpm run clean && jlpm run build", - "build:dev": "tsc -b && jlpm run cp:gdal", + "build:dev": "tspc -b && jlpm run cp:gdal", "clean": "rimraf tsconfig.tsbuildinfo", "clean:lib": "rimraf lib tsconfig.tsbuildinfo", "clean:all": "jlpm run clean:lib", - "watch": "tsc -w" + "watch": "tspc -w" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", @@ -95,7 +95,9 @@ "@types/shpjs": "^3.4.7", "@types/uuid": "^10.0.0", "rimraf": "^3.0.2", - "typescript": "^5" + "ts-patch": "^3.3.0", + "typescript": "^5", + "typescript-transform-paths": "^3.5.5" }, "sideEffects": [ "style/*.css", diff --git a/packages/base/src/annotations/components/Annotation.tsx b/packages/base/src/annotations/components/Annotation.tsx index 11b3780be..17889e450 100644 --- a/packages/base/src/annotations/components/Annotation.tsx +++ b/packages/base/src/annotations/components/Annotation.tsx @@ -9,7 +9,7 @@ import { showDialog, Dialog } from '@jupyterlab/apputils'; import { Button } from '@jupyterlab/ui-components'; import React, { useMemo, useState } from 'react'; import { Message } from './Message'; -import { IControlPanelModel } from '../../types'; +import { IControlPanelModel } from '@/src/types'; export interface IAnnotationProps { itemId: string; diff --git a/packages/base/src/console/consoleview.ts b/packages/base/src/console/consoleview.ts index f20840c36..096005a85 100644 --- a/packages/base/src/console/consoleview.ts +++ b/packages/base/src/console/consoleview.ts @@ -3,7 +3,7 @@ import { ServiceManager } from '@jupyterlab/services'; import { BoxPanel, Widget } from '@lumino/widgets'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { IEditorMimeTypeService } from '@jupyterlab/codeeditor'; -import { debounce } from '../tools'; +import { debounce } from '@/src/tools'; import { closeIcon, CommandToolbarButton, diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 238613c30..19a762892 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -1,8 +1,11 @@ import { IDict, IJupyterGISModel } from '@jupytergis/schema'; import { Dialog } from '@jupyterlab/apputils'; import * as React from 'react'; -import { BaseForm, IBaseFormProps } from '../formbuilder/objectform/baseform'; -import { DissolveForm } from '../formbuilder/objectform/process'; +import { + BaseForm, + IBaseFormProps +} from '@/src/formbuilder/objectform/baseform'; +import { DissolveForm } from '@/src/formbuilder/objectform/process'; import { Signal } from '@lumino/signaling'; import { PromiseDelegate } from '@lumino/coreutils'; diff --git a/packages/base/src/dialogs/layerCreationFormDialog.tsx b/packages/base/src/dialogs/layerCreationFormDialog.tsx index a86655ce6..bc40d050d 100644 --- a/packages/base/src/dialogs/layerCreationFormDialog.tsx +++ b/packages/base/src/dialogs/layerCreationFormDialog.tsx @@ -2,7 +2,7 @@ import { IDict } from '@jupytergis/schema'; import { Dialog } from '@jupyterlab/apputils'; import * as React from 'react'; -import { CreationForm, ICreationFormProps } from '../formbuilder'; +import { CreationForm, ICreationFormProps } from '@/src/formbuilder'; import { Signal } from '@lumino/signaling'; import { PromiseDelegate } from '@lumino/coreutils'; diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx index 660a7d9ec..82414af36 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Button } from '@jupyterlab/ui-components'; -import { IStopRow } from '../../symbologyDialog'; +import { IStopRow } from '@/src/dialogs/symbology/symbologyDialog'; import StopRow from './StopRow'; interface IStopContainerProps { diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx index 956e849c4..5d05d3247 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx @@ -2,7 +2,7 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button } from '@jupyterlab/ui-components'; import React, { useEffect, useRef } from 'react'; -import { IStopRow } from '../../symbologyDialog'; +import { IStopRow } from '@/src/dialogs/symbology/symbologyDialog'; const StopRow = ({ index, diff --git a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts index 8205bbe2a..711ca4fd4 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts @@ -1,7 +1,7 @@ import { IJGISLayer, IJupyterGISModel } from '@jupytergis/schema'; import { useEffect, useState } from 'react'; import { fromUrl, fromBlob } from 'geotiff'; -import { loadFile } from '../../../tools'; +import { loadFile } from '@/src/tools'; export interface IBandHistogram { buckets: number[]; diff --git a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts index a7ea81e59..5a192611f 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts @@ -2,7 +2,7 @@ import { GeoJSONFeature1, IJupyterGISModel } from '@jupytergis/schema'; import { useEffect, useState } from 'react'; -import { loadFile } from '../../../tools'; +import { loadFile } from '@/src/tools'; interface IUseGetPropertiesProps { layerId?: string; diff --git a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx index 1d872f583..5bdb65d3e 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { ISymbologyDialogProps } from '../symbologyDialog'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; import SingleBandPseudoColor from './types/SingleBandPseudoColor'; import MultibandColor from './types/MultibandColor'; diff --git a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx index a1470e187..bf52b5562 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { IBandRow } from '../../hooks/useGetBandInfo'; +import { IBandRow } from '@/src/dialogs/symbology/hooks/useGetBandInfo'; interface IBandRowProps { label: string; diff --git a/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx b/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx index 4d85e3f37..f2e97a65c 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx @@ -1,10 +1,10 @@ import { IWebGlLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { Spinner } from '../../../../mainview/spinner'; -import useGetBandInfo from '../../hooks/useGetBandInfo'; -import { ISymbologyDialogProps } from '../../symbologyDialog'; -import BandRow from '../components/BandRow'; +import { Spinner } from '@/src/mainview/spinner'; +import useGetBandInfo from '@/src/dialogs/symbology/hooks/useGetBandInfo'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; +import BandRow from '@/src/dialogs/symbology/tiff_layer/components/BandRow'; interface ISelectedBands { red: number; diff --git a/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx b/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx index 46e56cfd7..2abe6d098 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx @@ -3,17 +3,22 @@ import { Button } from '@jupyterlab/ui-components'; import { ReadonlyJSONObject } from '@lumino/coreutils'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { Spinner } from '../../../../mainview/spinner'; -import { GlobalStateDbManager } from '../../../../store'; -import { GeoTiffClassifications } from '../../classificationModes'; +import { Spinner } from '@/src/mainview/spinner'; +import { GlobalStateDbManager } from '@/src/store'; +import { GeoTiffClassifications } from '@/src/dialogs/symbology/classificationModes'; import ColorRamp, { ColorRampOptions -} from '../../components/color_ramp/ColorRamp'; -import StopRow from '../../components/color_stops/StopRow'; -import useGetBandInfo, { IBandRow } from '../../hooks/useGetBandInfo'; -import { IStopRow, ISymbologyDialogProps } from '../../symbologyDialog'; -import { Utils } from '../../symbologyUtils'; -import BandRow from '../components/BandRow'; +} from '@/src/dialogs/symbology/components/color_ramp/ColorRamp'; +import StopRow from '@/src/dialogs/symbology/components/color_stops/StopRow'; +import useGetBandInfo, { + IBandRow +} from '@/src/dialogs/symbology/hooks/useGetBandInfo'; +import { + IStopRow, + ISymbologyDialogProps +} from '@/src/dialogs/symbology/symbologyDialog'; +import { Utils } from '@/src/dialogs/symbology/symbologyUtils'; +import BandRow from '@/src/dialogs/symbology/tiff_layer/components/BandRow'; export type InterpolationType = 'discrete' | 'linear' | 'exact'; diff --git a/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx b/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx index 73686f0fd..f333869b9 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx @@ -1,15 +1,15 @@ import React, { useEffect, useState } from 'react'; -import { ISymbologyDialogProps } from '../symbologyDialog'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; import Canonical from './types/Canonical'; import Categorized from './types/Categorized'; import Graduated from './types/Graduated'; import Heatmap from './types/Heatmap'; import SimpleSymbol from './types/SimpleSymbol'; -import { useGetProperties } from '../hooks/useGetProperties'; +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; import { getColorCodeFeatureAttributes, getNumericFeatureAttributes -} from '../../../tools'; +} from '@/src/tools'; const VectorRendering = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx index 3b5ef999a..428ec1080 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx @@ -1,10 +1,10 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getColorCodeFeatureAttributes } from '../../../../tools'; -import { useGetProperties } from '../../hooks/useGetProperties'; -import { ISymbologyDialogProps } from '../../symbologyDialog'; -import ValueSelect from '../components/ValueSelect'; +import { getColorCodeFeatureAttributes } from '@/src/tools'; +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; +import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; const Canonical = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx index fd7415e68..cbe041c80 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx @@ -2,13 +2,16 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ReadonlyJSONObject } from '@lumino/coreutils'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getNumericFeatureAttributes } from '../../../../tools'; -import ColorRamp from '../../components/color_ramp/ColorRamp'; -import StopContainer from '../../components/color_stops/StopContainer'; -import { useGetProperties } from '../../hooks/useGetProperties'; -import { IStopRow, ISymbologyDialogProps } from '../../symbologyDialog'; -import { Utils, VectorUtils } from '../../symbologyUtils'; -import ValueSelect from '../components/ValueSelect'; +import { getNumericFeatureAttributes } from '@/src/tools'; +import ColorRamp from '@/src/dialogs/symbology/components/color_ramp/ColorRamp'; +import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopContainer'; +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; +import { + IStopRow, + ISymbologyDialogProps +} from '@/src/dialogs/symbology/symbologyDialog'; +import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; +import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; const Categorized = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx index 1636c0eb4..7666de85d 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx @@ -1,16 +1,19 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getNumericFeatureAttributes } from '../../../../tools'; -import { VectorClassifications } from '../../classificationModes'; +import { getNumericFeatureAttributes } from '@/src/tools'; +import { VectorClassifications } from '@/src/dialogs/symbology/classificationModes'; import ColorRamp, { ColorRampOptions -} from '../../components/color_ramp/ColorRamp'; -import StopContainer from '../../components/color_stops/StopContainer'; -import { useGetProperties } from '../../hooks/useGetProperties'; -import { IStopRow, ISymbologyDialogProps } from '../../symbologyDialog'; -import { Utils, VectorUtils } from '../../symbologyUtils'; -import ValueSelect from '../components/ValueSelect'; +} from '@/src/dialogs/symbology/components/color_ramp/ColorRamp'; +import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopContainer'; +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; +import { + IStopRow, + ISymbologyDialogProps +} from '@/src/dialogs/symbology/symbologyDialog'; +import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; +import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; const Graduated = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx index 101f087ca..1b590b758 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx @@ -1,7 +1,7 @@ import colormap from 'colormap'; import React, { useEffect, useRef, useState } from 'react'; -import CanvasSelectComponent from '../../components/color_ramp/CanvasSelectComponent'; -import { ISymbologyDialogProps } from '../../symbologyDialog'; +import CanvasSelectComponent from '@/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; const Heatmap = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx index c36557cf7..e996c7aed 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx @@ -1,7 +1,7 @@ import { FlatStyle } from 'ol/style/flat'; import React, { useEffect, useRef, useState } from 'react'; -import { IParsedStyle, parseColor } from '../../../../tools'; -import { ISymbologyDialogProps } from '../../symbologyDialog'; +import { IParsedStyle, parseColor } from '@/src/tools'; +import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; const SimpleSymbol = ({ model, diff --git a/packages/base/src/formbuilder/creationform.tsx b/packages/base/src/formbuilder/creationform.tsx index 646b13dcc..09dbb37d5 100644 --- a/packages/base/src/formbuilder/creationform.tsx +++ b/packages/base/src/formbuilder/creationform.tsx @@ -8,7 +8,7 @@ import { SourceType } from '@jupytergis/schema'; -import { deepCopy } from '../tools'; +import { deepCopy } from '@/src/tools'; import { Dialog } from '@jupyterlab/apputils'; import { PromiseDelegate, UUID } from '@lumino/coreutils'; diff --git a/packages/base/src/formbuilder/editform.tsx b/packages/base/src/formbuilder/editform.tsx index 85dde8e85..9d1fff649 100644 --- a/packages/base/src/formbuilder/editform.tsx +++ b/packages/base/src/formbuilder/editform.tsx @@ -7,7 +7,7 @@ import { import { Signal } from '@lumino/signaling'; import * as React from 'react'; -import { deepCopy } from '../tools'; +import { deepCopy } from '@/src/tools'; import { getLayerTypeForm, getSourceTypeForm } from './formselectors'; import { LayerPropertiesForm } from './objectform/layer'; import { SourcePropertiesForm } from './objectform/source'; diff --git a/packages/base/src/formbuilder/objectform/baseform.tsx b/packages/base/src/formbuilder/objectform/baseform.tsx index b34fd36ae..fc2e94ff4 100644 --- a/packages/base/src/formbuilder/objectform/baseform.tsx +++ b/packages/base/src/formbuilder/objectform/baseform.tsx @@ -6,8 +6,8 @@ import { Signal } from '@lumino/signaling'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; import validatorAjv8 from '@rjsf/validator-ajv8'; import * as React from 'react'; -import { deepCopy } from '../../tools'; -import { IDict } from '../../types'; +import { deepCopy } from '@/src/tools'; +import { IDict } from '@/src/types'; export interface IBaseFormStates { schema?: IDict; diff --git a/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx b/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx index b2d119ad2..b9f813b3b 100644 --- a/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx +++ b/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { FileDialog } from '@jupyterlab/filebrowser'; import { Dialog } from '@jupyterlab/apputils'; -import { LayerCreationFormDialog } from '../../dialogs/layerCreationFormDialog'; +import { LayerCreationFormDialog } from '@/src/dialogs/layerCreationFormDialog'; import { PathExt } from '@jupyterlab/coreutils'; export const FileSelectorWidget = (props: any) => { diff --git a/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts b/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts index cf288b698..2ca557436 100644 --- a/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts +++ b/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts @@ -1,6 +1,6 @@ import { IDict, IGeoJSONSource, IHeatmapLayer } from '@jupytergis/schema'; import { IChangeEvent } from '@rjsf/core'; -import { loadFile } from '../../../tools'; +import { loadFile } from '@/src/tools'; import { ILayerProps, LayerPropertiesForm } from './layerform'; export class HeatmapLayerPropertiesForm extends LayerPropertiesForm { diff --git a/packages/base/src/formbuilder/objectform/layer/layerform.ts b/packages/base/src/formbuilder/objectform/layer/layerform.ts index 9f1625117..bbc40556d 100644 --- a/packages/base/src/formbuilder/objectform/layer/layerform.ts +++ b/packages/base/src/formbuilder/objectform/layer/layerform.ts @@ -1,5 +1,8 @@ import { IDict, SourceType } from '@jupytergis/schema'; -import { BaseForm, IBaseFormProps } from '../baseform'; +import { + BaseForm, + IBaseFormProps +} from '@/src/formbuilder/objectform/baseform'; import { Signal } from '@lumino/signaling'; import { IChangeEvent } from '@rjsf/core'; diff --git a/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx b/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx index 83f7ff3c0..d63ddb7d3 100644 --- a/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx +++ b/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx @@ -1,7 +1,11 @@ -import { BaseForm, IBaseFormProps, IBaseFormStates } from '../baseform'; // Ensure BaseForm imports states +import { + BaseForm, + IBaseFormProps, + IBaseFormStates +} from '@/src/formbuilder/objectform/baseform'; // Ensure BaseForm imports states import { IDict, IJupyterGISModel, IGeoJSONSource } from '@jupytergis/schema'; import { IChangeEvent } from '@rjsf/core'; -import { loadFile } from '../../../tools'; +import { loadFile } from '@/src/tools'; interface IDissolveFormOptions extends IBaseFormProps { schema: IDict; diff --git a/packages/base/src/formbuilder/objectform/source/geojsonsource.ts b/packages/base/src/formbuilder/objectform/source/geojsonsource.ts index be90290ed..bc96a8792 100644 --- a/packages/base/src/formbuilder/objectform/source/geojsonsource.ts +++ b/packages/base/src/formbuilder/objectform/source/geojsonsource.ts @@ -3,7 +3,7 @@ import { Ajv, ValidateFunction } from 'ajv'; import * as geojson from '@jupytergis/schema/src/schema/geojson.json'; import { PathBasedSourcePropertiesForm } from './pathbasedsource'; -import { loadFile } from '../../../tools'; +import { loadFile } from '@/src/tools'; import { ISourceFormProps } from './sourceform'; /** diff --git a/packages/base/src/formbuilder/objectform/source/geotiffsource.ts b/packages/base/src/formbuilder/objectform/source/geotiffsource.ts index 9098b7a2a..47b127c0e 100644 --- a/packages/base/src/formbuilder/objectform/source/geotiffsource.ts +++ b/packages/base/src/formbuilder/objectform/source/geotiffsource.ts @@ -2,9 +2,9 @@ import { IDict } from '@jupytergis/schema'; import { showErrorMessage } from '@jupyterlab/apputils'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; -import { getMimeType } from '../../../tools'; +import { getMimeType } from '@/src/tools'; import { ISourceFormProps, SourcePropertiesForm } from './sourceform'; -import { FileSelectorWidget } from '../fileselectorwidget'; +import { FileSelectorWidget } from '@/src/formbuilder/objectform/fileselectorwidget'; /** * The form to modify a GeoTiff source. diff --git a/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts b/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts index 1a844ac09..12a05f41d 100644 --- a/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts +++ b/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts @@ -2,8 +2,8 @@ import { IDict } from '@jupytergis/schema'; import { showErrorMessage } from '@jupyterlab/apputils'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; -import { loadFile } from '../../../tools'; -import { FileSelectorWidget } from '../fileselectorwidget'; +import { loadFile } from '@/src/tools'; +import { FileSelectorWidget } from '@/src/formbuilder/objectform/fileselectorwidget'; import { ISourceFormProps, SourcePropertiesForm } from './sourceform'; /** diff --git a/packages/base/src/formbuilder/objectform/source/sourceform.ts b/packages/base/src/formbuilder/objectform/source/sourceform.ts index c22fd0a19..8ee59b082 100644 --- a/packages/base/src/formbuilder/objectform/source/sourceform.ts +++ b/packages/base/src/formbuilder/objectform/source/sourceform.ts @@ -1,5 +1,8 @@ import { IDict, SourceType } from '@jupytergis/schema'; -import { BaseForm, IBaseFormProps } from '../baseform'; +import { + BaseForm, + IBaseFormProps +} from '@/src/formbuilder/objectform/baseform'; import { Signal } from '@lumino/signaling'; import { IChangeEvent } from '@rjsf/core'; diff --git a/packages/base/src/mainview/TemporalSlider.tsx b/packages/base/src/mainview/TemporalSlider.tsx index 96eaa9f12..1e127213a 100644 --- a/packages/base/src/mainview/TemporalSlider.tsx +++ b/packages/base/src/mainview/TemporalSlider.tsx @@ -19,7 +19,7 @@ import { minutesInMonth } from 'date-fns/constants'; import React, { useEffect, useRef, useState } from 'react'; -import { useGetProperties } from '../dialogs/symbology/hooks/useGetProperties'; +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; interface ITemporalSliderProps { model: IJupyterGISModel; diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index 5c0aeeb23..31344382a 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -76,10 +76,10 @@ import { Rule } from 'ol/style/flat'; import proj4 from 'proj4'; import proj4list from 'proj4-list'; import * as React from 'react'; -import AnnotationFloater from '../annotations/components/AnnotationFloater'; -import { CommandIDs } from '../constants'; -import StatusBar from '../statusbar/StatusBar'; -import { isLightTheme, loadFile, throttle } from '../tools'; +import AnnotationFloater from '@/src/annotations/components/AnnotationFloater'; +import { CommandIDs } from '@/src/constants'; +import StatusBar from '@/src/statusbar/StatusBar'; +import { isLightTheme, loadFile, throttle } from '@/src/tools'; import CollaboratorPointers, { ClientPointer } from './CollaboratorPointers'; import { FollowIndicator } from './FollowIndicator'; import TemporalSlider from './TemporalSlider'; diff --git a/packages/base/src/panelview/annotationPanel.tsx b/packages/base/src/panelview/annotationPanel.tsx index ded8b59da..c61d0c4ac 100644 --- a/packages/base/src/panelview/annotationPanel.tsx +++ b/packages/base/src/panelview/annotationPanel.tsx @@ -1,8 +1,8 @@ import { PanelWithToolbar, ReactWidget } from '@jupyterlab/ui-components'; import React, { Component } from 'react'; import { IAnnotationModel } from '@jupytergis/schema'; -import Annotation from '../annotations/components/Annotation'; -import { IControlPanelModel } from '../types'; +import Annotation from '@/src/annotations/components/Annotation'; +import { IControlPanelModel } from '@/src/types'; interface IAnnotationPanelProps { annotationModel: IAnnotationModel; diff --git a/packages/base/src/panelview/components/filter-panel/Filter.tsx b/packages/base/src/panelview/components/filter-panel/Filter.tsx index ac1668b93..ab50cb479 100644 --- a/packages/base/src/panelview/components/filter-panel/Filter.tsx +++ b/packages/base/src/panelview/components/filter-panel/Filter.tsx @@ -9,8 +9,8 @@ import { Button, ReactWidget } from '@jupyterlab/ui-components'; import { Panel } from '@lumino/widgets'; import { cloneDeep } from 'lodash'; import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; -import { debounce, loadFile } from '../../../tools'; -import { IControlPanelModel } from '../../../types'; +import { debounce, loadFile } from '@/src/tools'; +import { IControlPanelModel } from '@/src/types'; import FilterRow from './FilterRow'; /** diff --git a/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx b/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx index 2dbd1d2dc..0c0548026 100644 --- a/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx +++ b/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx @@ -7,7 +7,7 @@ import { import { LabIcon, ReactWidget, caretDownIcon } from '@jupyterlab/ui-components'; import { Panel } from '@lumino/widgets'; import React, { useEffect, useRef, useState } from 'react'; -import { IControlPanelModel } from '../../../types'; +import { IControlPanelModel } from '@/src/types'; import { User } from '@jupyterlab/services'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; diff --git a/packages/base/src/panelview/components/layers.tsx b/packages/base/src/panelview/components/layers.tsx index 7e64e9d99..b2e36c752 100644 --- a/packages/base/src/panelview/components/layers.tsx +++ b/packages/base/src/panelview/components/layers.tsx @@ -19,10 +19,13 @@ import React, { useEffect, useState } from 'react'; -import { icons } from '../../constants'; -import { nonVisibilityIcon, visibilityIcon } from '../../icons'; -import { IControlPanelModel } from '../../types'; -import { ILayerPanelOptions, ILeftPanelClickHandlerParams } from '../leftpanel'; +import { icons } from '@/src/constants'; +import { nonVisibilityIcon, visibilityIcon } from '@/src/icons'; +import { IControlPanelModel } from '@/src/types'; +import { + ILayerPanelOptions, + ILeftPanelClickHandlerParams +} from '@/src/panelview/leftpanel'; const LAYERS_PANEL_CLASS = 'jp-gis-layerPanel'; const LAYER_GROUP_CLASS = 'jp-gis-layerGroup'; diff --git a/packages/base/src/panelview/leftpanel.tsx b/packages/base/src/panelview/leftpanel.tsx index 863159a29..3a536e521 100644 --- a/packages/base/src/panelview/leftpanel.tsx +++ b/packages/base/src/panelview/leftpanel.tsx @@ -8,12 +8,12 @@ import { IStateDB } from '@jupyterlab/statedb'; import { SidePanel } from '@jupyterlab/ui-components'; import { Message } from '@lumino/messaging'; import { MouseEvent as ReactMouseEvent } from 'react'; -import { IControlPanelModel } from '../types'; +import { IControlPanelModel } from '@/src/types'; import { LayersPanel } from './components/layers'; import { ControlPanelHeader } from './header'; import { FilterPanel } from './components/filter-panel/Filter'; import { CommandRegistry } from '@lumino/commands'; -import { CommandIDs } from '../constants'; +import { CommandIDs } from '@/src/constants'; /** * Options of the left panel widget. diff --git a/packages/base/src/panelview/model.ts b/packages/base/src/panelview/model.ts index 23e467a75..27d34613f 100644 --- a/packages/base/src/panelview/model.ts +++ b/packages/base/src/panelview/model.ts @@ -6,7 +6,7 @@ import { } from '@jupytergis/schema'; import { ISignal } from '@lumino/signaling'; -import { IControlPanelModel } from '../types'; +import { IControlPanelModel } from '@/src/types'; export class ControlPanelModel implements IControlPanelModel { constructor(options: ControlPanelModel.IOptions) { diff --git a/packages/base/src/panelview/objectproperties.tsx b/packages/base/src/panelview/objectproperties.tsx index 0b2ee324b..a8257269c 100644 --- a/packages/base/src/panelview/objectproperties.tsx +++ b/packages/base/src/panelview/objectproperties.tsx @@ -10,8 +10,8 @@ import { Panel } from '@lumino/widgets'; import * as React from 'react'; import { v4 as uuid } from 'uuid'; -import { IControlPanelModel } from '../types'; -import { EditForm } from '../formbuilder/editform'; +import { IControlPanelModel } from '@/src/types'; +import { EditForm } from '@/src/formbuilder/editform'; export class ObjectProperties extends PanelWithToolbar { constructor(params: ObjectProperties.IOptions) { diff --git a/packages/base/src/panelview/rightpanel.tsx b/packages/base/src/panelview/rightpanel.tsx index 2b5ddea51..3c42534a6 100644 --- a/packages/base/src/panelview/rightpanel.tsx +++ b/packages/base/src/panelview/rightpanel.tsx @@ -7,7 +7,7 @@ import { } from '@jupytergis/schema'; import { SidePanel } from '@jupyterlab/ui-components'; -import { IControlPanelModel } from '../types'; +import { IControlPanelModel } from '@/src/types'; import { ControlPanelHeader } from './header'; import { ObjectProperties } from './objectproperties'; import { Annotations } from './annotationPanel'; diff --git a/packages/base/src/statusbar/StatusBar.tsx b/packages/base/src/statusbar/StatusBar.tsx index 7b57969fb..62dbd4fa1 100644 --- a/packages/base/src/statusbar/StatusBar.tsx +++ b/packages/base/src/statusbar/StatusBar.tsx @@ -7,7 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Progress } from '@jupyter/react-components'; import { IJupyterGISModel, JgisCoordinates } from '@jupytergis/schema'; import React, { useEffect, useState } from 'react'; -import { version } from '../../package.json'; // Adjust the path as necessary +import { version } from '@/package.json'; interface IStatusBarProps { jgisModel: IJupyterGISModel; diff --git a/packages/base/src/toolbar/widget.tsx b/packages/base/src/toolbar/widget.tsx index eaac14903..1dae61869 100644 --- a/packages/base/src/toolbar/widget.tsx +++ b/packages/base/src/toolbar/widget.tsx @@ -14,9 +14,9 @@ import { CommandRegistry } from '@lumino/commands'; import { Widget } from '@lumino/widgets'; import * as React from 'react'; -import { CommandIDs } from '../constants'; -import { terminalToolbarIcon } from '../icons'; -import { rasterSubMenu, vectorSubMenu } from '../menus'; +import { CommandIDs } from '@/src/constants'; +import { terminalToolbarIcon } from '@/src/icons'; +import { rasterSubMenu, vectorSubMenu } from '@/src/menus'; import { UsersItem } from '@jupyter/collaboration'; export const TOOLBAR_SEPARATOR_CLASS = 'jGIS-Toolbar-Separator'; diff --git a/packages/base/src/tools.ts b/packages/base/src/tools.ts index c505e8fe2..4442eb4ff 100644 --- a/packages/base/src/tools.ts +++ b/packages/base/src/tools.ts @@ -7,7 +7,7 @@ import { Contents, ServerConnection } from '@jupyterlab/services'; import { showErrorMessage } from '@jupyterlab/apputils'; import * as d3Color from 'd3-color'; import shp from 'shpjs'; -import { getGdal } from './gdal'; +import { getGdal } from '@/src/gdal'; import { IDict, @@ -18,7 +18,7 @@ import { IRasterLayerGalleryEntry, SourceType } from '@jupytergis/schema'; -import RASTER_LAYER_GALLERY from '../rasterlayer_gallery/raster_layer_gallery.json'; +import RASTER_LAYER_GALLERY from '@/rasterlayer_gallery/raster_layer_gallery.json'; export const debounce = ( func: CallableFunction, diff --git a/packages/base/tsconfig.json b/packages/base/tsconfig.json index 6c9a090ea..ffecd04c8 100644 --- a/packages/base/tsconfig.json +++ b/packages/base/tsconfig.json @@ -2,7 +2,14 @@ "extends": "../../tsconfigbase.json", "compilerOptions": { "outDir": "lib", - "rootDir": "src" + "rootDir": "src", + "paths": { + "@/*": ["./*"] + }, + "plugins": [ + { "transform": "typescript-transform-paths" }, + { "transform": "typescript-transform-paths", "afterDeclarations": true } + ] }, "include": [ "src/**/*", diff --git a/yarn.lock b/yarn.lock index f275a6b1f..28eb48b2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41,15 +41,15 @@ __metadata: linkType: hard "@babel/generator@npm:^7.27.3": - version: 7.27.3 - resolution: "@babel/generator@npm:7.27.3" + version: 7.27.5 + resolution: "@babel/generator@npm:7.27.5" dependencies: - "@babel/parser": ^7.27.3 + "@babel/parser": ^7.27.5 "@babel/types": ^7.27.3 "@jridgewell/gen-mapping": ^0.3.5 "@jridgewell/trace-mapping": ^0.3.25 jsesc: ^3.0.2 - checksum: c0b1b399ff62fa0f1903679ab2b088fd4312c33154c0ae78228094c196ecf53ce8e525b8f5e537ac3117ff9a49cdf7b3640f129114908dfadc6541853f3747a2 + checksum: f6d3bf70f6bfbc5df263a023200728c53161d7f3ee3607bd8b2222c8568b6dd604ee490e305f0492a8225dac059ad75b4cc772b5cfd7d967e70360499d4d3701 languageName: node linkType: hard @@ -93,14 +93,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.27.2, @babel/parser@npm:^7.27.3": - version: 7.27.3 - resolution: "@babel/parser@npm:7.27.3" +"@babel/parser@npm:^7.27.2, @babel/parser@npm:^7.27.4, @babel/parser@npm:^7.27.5": + version: 7.27.5 + resolution: "@babel/parser@npm:7.27.5" dependencies: "@babel/types": ^7.27.3 bin: parser: ./bin/babel-parser.js - checksum: aef2cfd154e47a639615d173d3f05a8ce8007fcc5a0ade013c953adee71a8bc19465a147e060cc67388fd748b62a3b42bf3b5cc3e83d4f8add526b3b722e2231 + checksum: 16f00a12895522c1682f1f047332010e129ba517add3a2db347a658e02f60434fc38f9105a9d6ec3fd6bfb5d1b0b70d88585c1f10e06e2b58fba29004a42d648 languageName: node linkType: hard @@ -127,17 +127,17 @@ __metadata: linkType: hard "@babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.4.5": - version: 7.27.3 - resolution: "@babel/traverse@npm:7.27.3" + version: 7.27.4 + resolution: "@babel/traverse@npm:7.27.4" dependencies: "@babel/code-frame": ^7.27.1 "@babel/generator": ^7.27.3 - "@babel/parser": ^7.27.3 + "@babel/parser": ^7.27.4 "@babel/template": ^7.27.2 "@babel/types": ^7.27.3 debug: ^4.3.1 globals: ^11.1.0 - checksum: 914402382921b796b740f7c90d56ba130ffd5eeda8d18dc82f1243a1a510ff21a26d5b713df08c8e8aad2ffc969ce4624cee309406d69bcee8efa350483688c9 + checksum: ae0047fe786e200ffb048929347b074988e8b68decdb9fc0e2b36ca3e137d72462f349fa0e6193e44fb3cb99f9c639654515028995b44d7040707cef48ddb5c1 languageName: node linkType: hard @@ -302,8 +302,8 @@ __metadata: linkType: hard "@codemirror/lang-sql@npm:^6.8.0": - version: 6.8.0 - resolution: "@codemirror/lang-sql@npm:6.8.0" + version: 6.9.0 + resolution: "@codemirror/lang-sql@npm:6.9.0" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/language": ^6.0.0 @@ -311,7 +311,7 @@ __metadata: "@lezer/common": ^1.2.0 "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 - checksum: 1b5a3c8129b09f24039d8c0906fc4cb8d0f706a424a1d56721057bd1e647797c2b1240bb53eed9bf2bac5806a4e0363e555a3963f04c478efa05829890c537f7 + checksum: aca08c11b519f962e9a59e14dc6f54102deaa7a15a390c2dc50401234d33a1fd0c5d2436e6f1810a0363b6f2649480d28eb16a10a7e3f4221ffa3f130ef0672e languageName: node linkType: hard @@ -342,8 +342,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0, @codemirror/language@npm:^6.11.0, @codemirror/language@npm:^6.3.0, @codemirror/language@npm:^6.4.0, @codemirror/language@npm:^6.6.0, @codemirror/language@npm:^6.8.0": - version: 6.11.0 - resolution: "@codemirror/language@npm:6.11.0" + version: 6.11.1 + resolution: "@codemirror/language@npm:6.11.1" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.23.0 @@ -351,7 +351,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 5556dc163d5bd1d771a4f64e2750d3d1dc1f39030bc6e4b9a4704e4de7501e8d3511002e0f8f96cd8deef782730e0b49b576e30f0ea820e1c632995bd75caddd + checksum: 8ff27354f39fec45f2306322cd2069aeefd0162fdeec0e5b9215a3fc3fa7bc3212d133402c5f07022ee9de4bef9a69221111beed3abec42abfd246affd48ac42 languageName: node linkType: hard @@ -396,13 +396,14 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.35.0, @codemirror/view@npm:^6.36.6, @codemirror/view@npm:^6.7.0": - version: 6.36.8 - resolution: "@codemirror/view@npm:6.36.8" + version: 6.37.1 + resolution: "@codemirror/view@npm:6.37.1" dependencies: "@codemirror/state": ^6.5.0 + crelt: ^1.0.6 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: 6b5bbbd6f73bf2486170e3ee6b13660b8919ec544dc527dbe6357034a534dbd7deea3e660fbcd67c5e53ea808d6411ddd355eb9cf3dc4dded2a7c3f95a7fb0ac + checksum: 634bd4f9749f5ebcc82f2610ca9c826161385f7fc4a690f2e37c9850613d9bc575e779435c44db51c82ddc9f470d7a895c23200c4c9b513d9f8cf05729b9471a languageName: node linkType: hard @@ -806,7 +807,9 @@ __metadata: styled-components: ^5.3.6 three: ^0.135.0 three-mesh-bvh: ^0.5.17 + ts-patch: ^3.3.0 typescript: ^5 + typescript-transform-paths: ^3.5.5 uuid: ^11.0.3 languageName: unknown linkType: soft @@ -2570,9 +2573,9 @@ __metadata: linkType: hard "@pkgr/core@npm:^0.2.4": - version: 0.2.4 - resolution: "@pkgr/core@npm:0.2.4" - checksum: 8544f0346c3f7035b9e2fdf60179c68b12d3c76b3fba9533844099af67cf5c0ce5257538f5faa05953d48cc1536d046f003231f321b2f75b3fb449db8410a2b7 + version: 0.2.7 + resolution: "@pkgr/core@npm:0.2.7" + checksum: b16959878940f3d3016b79a4b2c23fd518aaec6b47295baa3154fbcf6574fee644c51023bb69069fa3ea9cdcaca40432818f54695f11acc0ae326cf56676e4d1 languageName: node linkType: hard @@ -2844,20 +2847,20 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 22.15.21 - resolution: "@types/node@npm:22.15.21" + version: 22.15.29 + resolution: "@types/node@npm:22.15.29" dependencies: undici-types: ~6.21.0 - checksum: 989f1ce3a99916a7298ae885210385fbcb339b07f8ef420b015d69dd68863aca68aeae07833736b300720d9394b8e1875600ce74166c24957d9907d29de0b788 + checksum: 201aabe3614d68fdf84f3255e2380381180de26ecdfd091f8809bf46fd2a41e73b2df4d94780c2054597f3c203d1c9d378359c21c551fb4eef8b12406698d6c9 languageName: node linkType: hard "@types/node@npm:^18.15.11": - version: 18.19.103 - resolution: "@types/node@npm:18.19.103" + version: 18.19.110 + resolution: "@types/node@npm:18.19.110" dependencies: undici-types: ~5.26.4 - checksum: 8d07dfed849d1cd0adf5ccc2a989c9ed9de4d6c4fdf5524102ad9d392db5d37f788ba1498601c5d46418bf5f0a4f17d136968e6f22efebd9557030e796e2cfa5 + checksum: 21df1474bda95c5e4c7ea746b369a8050185aea6c7f281c27ec7bc0cb404266f6e9680fc3cdd6d02d5da92183283bc479947e9c9dc7eaf33839d17c2c648aceb languageName: node linkType: hard @@ -3761,16 +3764,16 @@ __metadata: linkType: hard "browserslist@npm:^4.24.0": - version: 4.24.5 - resolution: "browserslist@npm:4.24.5" + version: 4.25.0 + resolution: "browserslist@npm:4.25.0" dependencies: - caniuse-lite: ^1.0.30001716 - electron-to-chromium: ^1.5.149 + caniuse-lite: ^1.0.30001718 + electron-to-chromium: ^1.5.160 node-releases: ^2.0.19 update-browserslist-db: ^1.1.3 bin: browserslist: cli.js - checksum: 69310ade58b0cb2b2871022fdaba8388902f9a2d17a6fa05f383d046d6da87fd9f83018a66fe1c6296648ca7d52e3208c3fc68c82f17a0fd4bf12a452c036247 + checksum: 0d34fa0c6e23e962598ba68ee9f4566a4b575ec550ff7e9e7287c5e94a6e0f208f75f4f7d578ccd060f843167e0e495bde8f6d278f353f0da783cd50f758e5c7 languageName: node linkType: hard @@ -3896,10 +3899,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001716": - version: 1.0.30001718 - resolution: "caniuse-lite@npm:1.0.30001718" - checksum: c6598b6eb2c4358fc9f8ead8982bf5f9efdc1f29bb74948b9481d314ced10675bd0beb99771094ac52d56c2cec121049d1f18e9405cab7d81807816d1836b38a +"caniuse-lite@npm:^1.0.30001718": + version: 1.0.30001720 + resolution: "caniuse-lite@npm:1.0.30001720" + checksum: 97b9f9de842595ff9674001abb9c5bc093c03bb985d481ed97617ea48fc248bfb2cc1f1afe19da2bf20016f28793e495fa2f339e22080d8da3c9714fb7950926 languageName: node linkType: hard @@ -3924,7 +3927,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1": +"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -4376,7 +4379,7 @@ __metadata: languageName: node linkType: hard -"crelt@npm:^1.0.5": +"crelt@npm:^1.0.5, crelt@npm:^1.0.6": version: 1.0.6 resolution: "crelt@npm:1.0.6" checksum: dad842093371ad702afbc0531bfca2b0a8dd920b23a42f26e66dabbed9aad9acd5b9030496359545ef3937c3aced0fd4ac39f7a2d280a23ddf9eb7fdcb94a69f @@ -4825,10 +4828,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.149": - version: 1.5.158 - resolution: "electron-to-chromium@npm:1.5.158" - checksum: 897e4a4e8ef65a0aa298477d1f02cada041df2bbe4db506f54fb89f275ca3f135530476a9bb131404547ac0b3af8b3546cb86a04250a52edfdf71f0ff4219083 +"electron-to-chromium@npm:^1.5.160": + version: 1.5.162 + resolution: "electron-to-chromium@npm:1.5.162" + checksum: 777bd278da53730a280166237a9458d6e00bb5c55014146d44fceb74d75fab2149b5484be6f857e3943ba0f6162618c1a028c362950730eeced6921e5c158f6a languageName: node linkType: hard @@ -4939,8 +4942,8 @@ __metadata: linkType: hard "es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.9": - version: 1.23.10 - resolution: "es-abstract@npm:1.23.10" + version: 1.24.0 + resolution: "es-abstract@npm:1.24.0" dependencies: array-buffer-byte-length: ^1.0.2 arraybuffer.prototype.slice: ^1.0.4 @@ -4969,7 +4972,9 @@ __metadata: is-array-buffer: ^3.0.5 is-callable: ^1.2.7 is-data-view: ^1.0.2 + is-negative-zero: ^2.0.3 is-regex: ^1.2.1 + is-set: ^2.0.3 is-shared-array-buffer: ^1.0.4 is-string: ^1.1.1 is-typed-array: ^1.1.15 @@ -4984,6 +4989,7 @@ __metadata: safe-push-apply: ^1.0.0 safe-regex-test: ^1.1.0 set-proto: ^1.0.0 + stop-iteration-iterator: ^1.1.0 string.prototype.trim: ^1.2.10 string.prototype.trimend: ^1.0.9 string.prototype.trimstart: ^1.0.8 @@ -4993,7 +4999,7 @@ __metadata: typed-array-length: ^1.0.7 unbox-primitive: ^1.1.0 which-typed-array: ^1.1.19 - checksum: 0b1baf903096c4f19030ab3334062deb6df577441266223b44cb431d8733f21852e9ac8be1c73c28dddc8f0c214c668969195cee0a14d21967ca91628f5f4366 + checksum: 06b3d605e56e3da9d16d4db2629a42dac1ca31f2961a41d15c860422a266115e865b43e82d6b9da81a0fabbbb65ebc12fb68b0b755bc9dbddacb6bf7450e96df languageName: node linkType: hard @@ -5128,11 +5134,11 @@ __metadata: linkType: hard "eslint-plugin-prettier@npm:^5.0.1": - version: 5.4.0 - resolution: "eslint-plugin-prettier@npm:5.4.0" + version: 5.4.1 + resolution: "eslint-plugin-prettier@npm:5.4.1" dependencies: prettier-linter-helpers: ^1.0.0 - synckit: ^0.11.0 + synckit: ^0.11.7 peerDependencies: "@types/eslint": ">=8.0.0" eslint: ">=8.0.0" @@ -5143,7 +5149,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 1d71d4fb42b8f9654232c6f9c6805549f7e9da6ee3207069dac122ab1c55eae90a0840f5c109e821e3a5145ec223dbbdfa7cfd3c3a28267316d08d55d5812e21 + checksum: ddbfc60e478dd78602b1f1594db539bfc686161eba4531e4c59580c9cf5746919878beabfe31b559d783ad3ed753af158bfa16bd35bd05382c7d2d86c894c81b languageName: node linkType: hard @@ -5961,6 +5967,17 @@ __metadata: languageName: node linkType: hard +"global-prefix@npm:^4.0.0": + version: 4.0.0 + resolution: "global-prefix@npm:4.0.0" + dependencies: + ini: ^4.1.3 + kind-of: ^6.0.3 + which: ^4.0.0 + checksum: 055c7cd1e03519f14aad2decd16d9c2546f7ec90db620da1583a75551a1aa7a29977b94bd192d4ca2eb6689098d64d3f2477b23886009403856cd4870f791d81 + languageName: node + linkType: hard + "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" @@ -6596,6 +6613,13 @@ __metadata: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: c1e6b23d2070c0539d7b36022d5a94407132411d01aba39ec549af824231f3804b1aea90b5e4e58e807a65d23ceb538ed6e355ce76b267bdd86edb757ffcbdcd + languageName: node + linkType: hard + "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -7711,7 +7735,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.0, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.0, minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -7731,7 +7755,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:~1.2.0": +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8, minimist@npm:~1.2.0": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -7890,7 +7914,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.7, nanoid@npm:^3.3.8": +"nanoid@npm:^3.1.23, nanoid@npm:^3.3.11, nanoid@npm:^3.3.7": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -8894,13 +8918,13 @@ __metadata: linkType: hard "postcss@npm:^8.3.11, postcss@npm:^8.4.33": - version: 8.5.3 - resolution: "postcss@npm:8.5.3" + version: 8.5.4 + resolution: "postcss@npm:8.5.4" dependencies: - nanoid: ^3.3.8 + nanoid: ^3.3.11 picocolors: ^1.1.1 source-map-js: ^1.2.1 - checksum: da574620eb84ff60e65e1d8fc6bd5ad87a19101a23d0aba113c653434161543918229a0f673d89efb3b6d4906287eb04b957310dbcf4cbebacad9d1312711461 + checksum: 7ede5eb54aa56767a61541f13ca9994ce56d93340bc3c99328c741e5cc6c0024510e31667be108e3d29e5189d434ae8476c820e8c0ce90cf942d8a2faf1eb876 languageName: node linkType: hard @@ -9387,7 +9411,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.20.0": +"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -9400,7 +9424,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin": +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#~builtin::version=1.22.10&hash=c3c19d" dependencies: @@ -9612,7 +9636,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.3": version: 7.7.2 resolution: "semver@npm:7.7.2" bin: @@ -9723,9 +9747,9 @@ __metadata: linkType: hard "shell-quote@npm:^1.6.1": - version: 1.8.2 - resolution: "shell-quote@npm:1.8.2" - checksum: 1e97b62ced1c4c5135015978ebf273bed1f425a68cf84163e83fbb0f34b3ff9471e656720dab2b7cbb4ae0f58998e686d17d166c28dfb3662acd009e8bd7faed + version: 1.8.3 + resolution: "shell-quote@npm:1.8.3" + checksum: 550dd84e677f8915eb013d43689c80bb114860649ec5298eb978f40b8f3d4bc4ccb072b82c094eb3548dc587144bb3965a8676f0d685c1cf4c40b5dc27166242 languageName: node linkType: hard @@ -10008,6 +10032,16 @@ __metadata: languageName: node linkType: hard +"stop-iteration-iterator@npm:^1.1.0": + version: 1.1.0 + resolution: "stop-iteration-iterator@npm:1.1.0" + dependencies: + es-errors: ^1.3.0 + internal-slot: ^1.1.0 + checksum: be944489d8829fb3bdec1a1cc4a2142c6b6eb317305eeace1ece978d286d6997778afa1ae8cb3bd70e2b274b9aa8c69f93febb1e15b94b1359b11058f9d3c3a1 + languageName: node + linkType: hard + "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -10238,12 +10272,12 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.11.0": - version: 0.11.6 - resolution: "synckit@npm:0.11.6" +"synckit@npm:^0.11.7": + version: 0.11.8 + resolution: "synckit@npm:0.11.8" dependencies: "@pkgr/core": ^0.2.4 - checksum: ce910d27ee1b30ff961905e5d63d60e2cede4f33cd3dc7b46988989f83ac33b3020a193ec8121af9c999b68aa90c01ec42121ebf9fe4356cc6406b9ff037f180 + checksum: dd7193736e0b5eb209192e280649b98b539537bf23bef20c8a2b24cd12ccde47bcf4e77773ff9cb66c35960d2cb41e28c05e0b19124488abbfb6423258b56275 languageName: node linkType: hard @@ -10477,6 +10511,23 @@ __metadata: languageName: node linkType: hard +"ts-patch@npm:^3.3.0": + version: 3.3.0 + resolution: "ts-patch@npm:3.3.0" + dependencies: + chalk: ^4.1.2 + global-prefix: ^4.0.0 + minimist: ^1.2.8 + resolve: ^1.22.2 + semver: ^7.6.3 + strip-ansi: ^6.0.1 + bin: + ts-patch: bin/ts-patch.js + tspc: bin/tspc.js + checksum: b9c85e338406ae75a306d0e12d9968ee3819922f996cecc5d7176842d2e5cb5f194bd651a85098b0a5b6c432fb29f0305e57003d4920ff0a5dfa5b111b9d3e7c + languageName: node + linkType: hard + "tsconfig-paths@npm:^4.1.2": version: 4.2.0 resolution: "tsconfig-paths@npm:4.2.0" @@ -10642,6 +10693,17 @@ __metadata: languageName: node linkType: hard +"typescript-transform-paths@npm:^3.5.5": + version: 3.5.5 + resolution: "typescript-transform-paths@npm:3.5.5" + dependencies: + minimatch: ^9.0.5 + peerDependencies: + typescript: ">=3.6.5" + checksum: 23f744d6aa6baa503044e6b24bbc1ac7e5c7c14dd0731d2a7786cb29a22040deb709efdfa88b810299ec49ad137448872f6062011bee5aac138596f98cde1608 + languageName: node + linkType: hard + "typescript@npm:>=3 < 6, typescript@npm:^5": version: 5.8.3 resolution: "typescript@npm:5.8.3" @@ -11038,9 +11100,9 @@ __metadata: linkType: hard "webpack-sources@npm:^3.2.3": - version: 3.3.0 - resolution: "webpack-sources@npm:3.3.0" - checksum: 3098025872b445f39ab873241303c111a11e832b88ef124d9988593af47f245db4e9a485c449cd63ec14ab2562139b009d15c255599eb9837b67d182519031ff + version: 3.3.2 + resolution: "webpack-sources@npm:3.3.2" + checksum: c0760437165b241376838b20d682f8cc6aaa4f9cf3787d3063bdb997eaf823ac3300f2b1b14a48bbebde7ce4386cabf78e5d17d632dfdef55e84c59c99c68be0 languageName: node linkType: hard From 7302f8b06b6c3f6f413e0e3d0f69bda2b0f4bc0b Mon Sep 17 00:00:00 2001 From: Matt Fisher <3608264+mfisher87@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:41:04 -0600 Subject: [PATCH 03/17] Consistently sort and group all TS imports (#730) --- .eslintrc.js | 22 +- package.json | 1 + .../src/annotations/components/Annotation.tsx | 3 +- .../components/AnnotationFloater.tsx | 3 +- packages/base/src/classificationModes.ts | 1 + packages/base/src/commands.ts | 17 +- packages/base/src/console/consoleview.ts | 9 +- packages/base/src/constants.ts | 1 + .../base/src/dialogs/ProcessingFormDialog.tsx | 5 +- .../base/src/dialogs/layerBrowserDialog.tsx | 2 +- .../src/dialogs/layerCreationFormDialog.tsx | 4 +- .../dialogs/symbology/classificationModes.ts | 1 + .../color_ramp/CanvasSelectComponent.tsx | 1 + .../components/color_ramp/ColorRamp.tsx | 7 +- .../components/color_ramp/ColorRampEntry.tsx | 1 + .../components/color_stops/StopContainer.tsx | 3 +- .../components/color_stops/StopRow.tsx | 1 + .../dialogs/symbology/hooks/useGetBandInfo.ts | 3 +- .../symbology/hooks/useGetProperties.ts | 1 + .../src/dialogs/symbology/symbologyDialog.tsx | 1 + .../src/dialogs/symbology/symbologyUtils.ts | 3 +- .../symbology/tiff_layer/TiffRendering.tsx | 3 +- .../tiff_layer/components/BandRow.tsx | 1 + .../tiff_layer/types/MultibandColor.tsx | 3 +- .../types/SingleBandPseudoColor.tsx | 5 +- .../vector_layer/VectorRendering.tsx | 11 +- .../vector_layer/types/Canonical.tsx | 3 +- .../vector_layer/types/Categorized.tsx | 3 +- .../vector_layer/types/Graduated.tsx | 3 +- .../symbology/vector_layer/types/Heatmap.tsx | 1 + .../vector_layer/types/SimpleSymbol.tsx | 3 +- .../base/src/formbuilder/creationform.tsx | 5 +- .../base/src/formbuilder/formselectors.ts | 15 +- .../src/formbuilder/objectform/baseform.tsx | 1 + .../objectform/fileselectorwidget.tsx | 7 +- .../objectform/layer/heatmapLayerForm.ts | 1 + .../objectform/layer/hillshadeLayerForm.ts | 1 + .../formbuilder/objectform/layer/layerform.ts | 5 +- .../objectform/layer/vectorlayerform.ts | 1 + .../objectform/layer/webGlLayerForm.tsx | 1 + .../process/dissolveProcessForm.tsx | 5 +- .../objectform/source/geojsonsource.ts | 4 +- .../objectform/source/geotiffsource.ts | 2 +- .../objectform/source/pathbasedsource.ts | 2 +- .../objectform/source/sourceform.ts | 5 +- .../objectform/source/tilesourceform.ts | 1 + packages/base/src/icons.ts | 25 +- .../base/src/mainview/FollowIndicator.tsx | 2 +- packages/base/src/mainview/TemporalSlider.tsx | 1 + packages/base/src/mainview/mainView.tsx | 9 +- packages/base/src/menus.ts | 2 +- .../base/src/panelview/annotationPanel.tsx | 3 +- .../components/filter-panel/Filter.tsx | 1 + .../identify-panel/IdentifyPanel.tsx | 8 +- .../base/src/panelview/components/layers.tsx | 3 +- packages/base/src/panelview/leftpanel.tsx | 7 +- .../base/src/panelview/objectproperties.tsx | 2 +- packages/base/src/panelview/rightpanel.tsx | 4 +- packages/base/src/processing.ts | 7 +- packages/base/src/statusbar/StatusBar.tsx | 1 + packages/base/src/toolbar/widget.tsx | 4 +- packages/base/src/tools.ts | 20 +- packages/base/src/widget.ts | 4 +- packages/schema/src/doc.ts | 2 +- packages/schema/src/model.ts | 3 +- python/jupytergis_core/src/factory.ts | 17 +- .../jupytergis_core/src/jgisplugin/plugins.ts | 4 +- python/jupytergis_core/src/plugin.ts | 2 +- python/jupytergis_lab/src/index.ts | 1 + python/jupytergis_qgis/src/plugins.ts | 16 +- yarn.lock | 228 +++++++++++++++++- 71 files changed, 418 insertions(+), 140 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2575b43df..62776d2df 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,7 +9,7 @@ module.exports = { project: "tsconfig.eslint.json", sourceType: "module", }, - plugins: ["@typescript-eslint"], + plugins: ["@typescript-eslint", "import"], rules: { "@typescript-eslint/naming-convention": [ "error", @@ -32,8 +32,24 @@ module.exports = { "single", { avoidEscape: true, allowTemplateLiterals: false }, ], - curly: ["error", "all"], - eqeqeq: "error", + "curly": ["error", "all"], + "eqeqeq": "error", + "import/order": [ + "error", + { + "alphabetize": {"order": "asc"}, + "groups": [ + "external", + "builtin", + ["internal", "sibling", "parent", "index"] + ], + "distinctGroup": false, + "pathGroups": [ + {pattern: "@/**", group: "internal", position: "before"} + ], + "newlines-between": "always" + } + ], "prefer-arrow-callback": "error", "no-duplicate-imports": "error", }, diff --git a/package.json b/package.json index 4575d364a..fc9f4116c 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "copy-webpack-plugin": "^10.0.0", "eslint": "^8.36.0", "eslint-config-prettier": "^8.8.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.0.1", "lerna": "^8.1.9", "npm-run-all": "^4.1.5", diff --git a/packages/base/src/annotations/components/Annotation.tsx b/packages/base/src/annotations/components/Annotation.tsx index 17889e450..18b7bbdc0 100644 --- a/packages/base/src/annotations/components/Annotation.tsx +++ b/packages/base/src/annotations/components/Annotation.tsx @@ -8,8 +8,9 @@ import { IAnnotationModel, IJupyterGISModel } from '@jupytergis/schema'; import { showDialog, Dialog } from '@jupyterlab/apputils'; import { Button } from '@jupyterlab/ui-components'; import React, { useMemo, useState } from 'react'; -import { Message } from './Message'; + import { IControlPanelModel } from '@/src/types'; +import { Message } from './Message'; export interface IAnnotationProps { itemId: string; diff --git a/packages/base/src/annotations/components/AnnotationFloater.tsx b/packages/base/src/annotations/components/AnnotationFloater.tsx index 038c8bc22..816a0cd81 100644 --- a/packages/base/src/annotations/components/AnnotationFloater.tsx +++ b/packages/base/src/annotations/components/AnnotationFloater.tsx @@ -1,6 +1,7 @@ -import React, { useState } from 'react'; import { faWindowMinimize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React, { useState } from 'react'; + import Annotation, { IAnnotationProps } from './Annotation'; const AnnotationFloater = ({ diff --git a/packages/base/src/classificationModes.ts b/packages/base/src/classificationModes.ts index 81f35d9a5..478af0a32 100644 --- a/packages/base/src/classificationModes.ts +++ b/packages/base/src/classificationModes.ts @@ -1,6 +1,7 @@ // Adapted from https://github.com/qgis/QGIS/blob/master/src/core/classification/ import { Pool, fromUrl, TypedArray } from 'geotiff'; + import { InterpolationType } from './dialogs/symbology/tiff_layer/types/SingleBandPseudoColor'; export namespace VectorClassifications { diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 519f2c0ac..51fd0dee6 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -17,23 +17,24 @@ import { IStateDB } from '@jupyterlab/statedb'; import { ITranslator } from '@jupyterlab/translation'; import { CommandRegistry } from '@lumino/commands'; import { ReadonlyPartialJSONObject } from '@lumino/coreutils'; +import { Coordinate } from 'ol/coordinate'; +import { fromLonLat } from 'ol/proj'; + import { CommandIDs, icons } from './constants'; -import { LayerCreationFormDialog } from './dialogs/layerCreationFormDialog'; +import { ProcessingFormDialog } from './dialogs/ProcessingFormDialog'; import { LayerBrowserWidget } from './dialogs/layerBrowserDialog'; +import { LayerCreationFormDialog } from './dialogs/layerCreationFormDialog'; import { SymbologyWidget } from './dialogs/symbology/symbologyDialog'; +import { targetWithCenterIcon } from './icons'; import keybindings from './keybindings.json'; -import { JupyterGISTracker } from './types'; -import { JupyterGISDocumentWidget } from './widget'; -import { getGeoJSONDataFromLayerSource, downloadFile } from './tools'; -import { ProcessingFormDialog } from './dialogs/ProcessingFormDialog'; import { getSingleSelectedLayer, selectedLayerIsOfType, processSelectedLayer } from './processing'; -import { fromLonLat } from 'ol/proj'; -import { Coordinate } from 'ol/coordinate'; -import { targetWithCenterIcon } from './icons'; +import { getGeoJSONDataFromLayerSource, downloadFile } from './tools'; +import { JupyterGISTracker } from './types'; +import { JupyterGISDocumentWidget } from './widget'; interface ICreateEntry { tracker: JupyterGISTracker; diff --git a/packages/base/src/console/consoleview.ts b/packages/base/src/console/consoleview.ts index 096005a85..e530a96aa 100644 --- a/packages/base/src/console/consoleview.ts +++ b/packages/base/src/console/consoleview.ts @@ -1,9 +1,7 @@ +import { IEditorMimeTypeService } from '@jupyterlab/codeeditor'; import { ConsolePanel } from '@jupyterlab/console'; -import { ServiceManager } from '@jupyterlab/services'; -import { BoxPanel, Widget } from '@lumino/widgets'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { IEditorMimeTypeService } from '@jupyterlab/codeeditor'; -import { debounce } from '@/src/tools'; +import { ServiceManager } from '@jupyterlab/services'; import { closeIcon, CommandToolbarButton, @@ -11,6 +9,9 @@ import { Toolbar } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; +import { BoxPanel, Widget } from '@lumino/widgets'; + +import { debounce } from '@/src/tools'; export class ConsoleView extends BoxPanel { constructor(options: ConsoleView.IOptions) { diff --git a/packages/base/src/constants.ts b/packages/base/src/constants.ts index bfafbbfa0..f39694c3c 100644 --- a/packages/base/src/constants.ts +++ b/packages/base/src/constants.ts @@ -1,4 +1,5 @@ import { LabIcon, redoIcon, undoIcon } from '@jupyterlab/ui-components'; + import { bookOpenIcon, clockIcon, diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 19a762892..284d7f93b 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -1,13 +1,14 @@ import { IDict, IJupyterGISModel } from '@jupytergis/schema'; import { Dialog } from '@jupyterlab/apputils'; +import { PromiseDelegate } from '@lumino/coreutils'; +import { Signal } from '@lumino/signaling'; import * as React from 'react'; + import { BaseForm, IBaseFormProps } from '@/src/formbuilder/objectform/baseform'; import { DissolveForm } from '@/src/formbuilder/objectform/process'; -import { Signal } from '@lumino/signaling'; -import { PromiseDelegate } from '@lumino/coreutils'; export interface IProcessingFormDialogOptions extends IBaseFormProps { formContext: 'update' | 'create'; diff --git a/packages/base/src/dialogs/layerBrowserDialog.tsx b/packages/base/src/dialogs/layerBrowserDialog.tsx index a932d9258..7d2b1ee1f 100644 --- a/packages/base/src/dialogs/layerBrowserDialog.tsx +++ b/packages/base/src/dialogs/layerBrowserDialog.tsx @@ -14,8 +14,8 @@ import { PromiseDelegate, UUID } from '@lumino/coreutils'; import { Signal } from '@lumino/signaling'; import React, { ChangeEvent, MouseEvent, useEffect, useState } from 'react'; -import CUSTOM_RASTER_IMAGE from '../../rasterlayer_gallery/custom_raster.png'; import { CreationFormWrapper } from './layerCreationFormDialog'; +import CUSTOM_RASTER_IMAGE from '../../rasterlayer_gallery/custom_raster.png'; interface ILayerBrowserDialogProps { model: IJupyterGISModel; diff --git a/packages/base/src/dialogs/layerCreationFormDialog.tsx b/packages/base/src/dialogs/layerCreationFormDialog.tsx index bc40d050d..af43b3c93 100644 --- a/packages/base/src/dialogs/layerCreationFormDialog.tsx +++ b/packages/base/src/dialogs/layerCreationFormDialog.tsx @@ -1,10 +1,10 @@ import { IDict } from '@jupytergis/schema'; import { Dialog } from '@jupyterlab/apputils'; +import { PromiseDelegate } from '@lumino/coreutils'; +import { Signal } from '@lumino/signaling'; import * as React from 'react'; import { CreationForm, ICreationFormProps } from '@/src/formbuilder'; -import { Signal } from '@lumino/signaling'; -import { PromiseDelegate } from '@lumino/coreutils'; export interface ICreationFormWrapperProps extends ICreationFormProps { /** diff --git a/packages/base/src/dialogs/symbology/classificationModes.ts b/packages/base/src/dialogs/symbology/classificationModes.ts index dea63d92d..f19dd67ec 100644 --- a/packages/base/src/dialogs/symbology/classificationModes.ts +++ b/packages/base/src/dialogs/symbology/classificationModes.ts @@ -1,6 +1,7 @@ // Adapted from https://github.com/qgis/QGIS/blob/master/src/core/classification/ import { Pool, fromUrl, TypedArray } from 'geotiff'; + import { InterpolationType } from './tiff_layer/types/SingleBandPseudoColor'; export namespace VectorClassifications { diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx index 57357f7ee..58fe48c35 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx @@ -1,6 +1,7 @@ import { Button } from '@jupyterlab/ui-components'; import colormap from 'colormap'; import React, { useEffect, useRef, useState } from 'react'; + import ColorRampEntry from './ColorRampEntry'; export interface IColorMap { diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx index 6b2e65a60..78e16c2ff 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx @@ -1,10 +1,11 @@ +import { faSpinner } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IDict } from '@jupytergis/schema'; import { Button } from '@jupyterlab/ui-components'; import React, { useEffect, useState } from 'react'; + import CanvasSelectComponent from './CanvasSelectComponent'; -import { faSpinner } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import ModeSelectRow from './ModeSelectRow'; -import { IDict } from '@jupytergis/schema'; interface IColorRampProps { modeOptions: string[]; diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRampEntry.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRampEntry.tsx index 6f909bb30..4b674cec8 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRampEntry.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRampEntry.tsx @@ -1,4 +1,5 @@ import React, { useEffect } from 'react'; + import { IColorMap } from './CanvasSelectComponent'; interface IColorRampEntryProps { diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx index 82414af36..0418adb19 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx @@ -1,5 +1,6 @@ -import React from 'react'; import { Button } from '@jupyterlab/ui-components'; +import React from 'react'; + import { IStopRow } from '@/src/dialogs/symbology/symbologyDialog'; import StopRow from './StopRow'; diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx index 5d05d3247..326885e9d 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx @@ -2,6 +2,7 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button } from '@jupyterlab/ui-components'; import React, { useEffect, useRef } from 'react'; + import { IStopRow } from '@/src/dialogs/symbology/symbologyDialog'; const StopRow = ({ diff --git a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts index 711ca4fd4..3e9773c26 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts @@ -1,6 +1,7 @@ import { IJGISLayer, IJupyterGISModel } from '@jupytergis/schema'; -import { useEffect, useState } from 'react'; import { fromUrl, fromBlob } from 'geotiff'; +import { useEffect, useState } from 'react'; + import { loadFile } from '@/src/tools'; export interface IBandHistogram { diff --git a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts index 5a192611f..c56c472ce 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts @@ -2,6 +2,7 @@ import { GeoJSONFeature1, IJupyterGISModel } from '@jupytergis/schema'; import { useEffect, useState } from 'react'; + import { loadFile } from '@/src/tools'; interface IUseGetPropertiesProps { diff --git a/packages/base/src/dialogs/symbology/symbologyDialog.tsx b/packages/base/src/dialogs/symbology/symbologyDialog.tsx index ed7386a66..a4bf7cba4 100644 --- a/packages/base/src/dialogs/symbology/symbologyDialog.tsx +++ b/packages/base/src/dialogs/symbology/symbologyDialog.tsx @@ -4,6 +4,7 @@ import { IStateDB } from '@jupyterlab/statedb'; import { PromiseDelegate } from '@lumino/coreutils'; import { Signal } from '@lumino/signaling'; import React, { useEffect, useState } from 'react'; + import TiffRendering from './tiff_layer/TiffRendering'; import VectorRendering from './vector_layer/VectorRendering'; diff --git a/packages/base/src/dialogs/symbology/symbologyUtils.ts b/packages/base/src/dialogs/symbology/symbologyUtils.ts index 341405b58..b42a2894c 100644 --- a/packages/base/src/dialogs/symbology/symbologyUtils.ts +++ b/packages/base/src/dialogs/symbology/symbologyUtils.ts @@ -1,7 +1,8 @@ import { IJGISLayer } from '@jupytergis/schema'; -import { IStopRow } from './symbologyDialog'; import colormap from 'colormap'; +import { IStopRow } from './symbologyDialog'; + export namespace VectorUtils { export const buildColorInfo = (layer: IJGISLayer) => { // This it to parse a color object on the layer diff --git a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx index 5bdb65d3e..cb75d3ae7 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useState } from 'react'; + import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; -import SingleBandPseudoColor from './types/SingleBandPseudoColor'; import MultibandColor from './types/MultibandColor'; +import SingleBandPseudoColor from './types/SingleBandPseudoColor'; const TiffRendering = ({ model, diff --git a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx index bf52b5562..d996ab852 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; + import { IBandRow } from '@/src/dialogs/symbology/hooks/useGetBandInfo'; interface IBandRowProps { diff --git a/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx b/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx index f2e97a65c..fb35f25e9 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/types/MultibandColor.tsx @@ -1,10 +1,11 @@ import { IWebGlLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { Spinner } from '@/src/mainview/spinner'; + import useGetBandInfo from '@/src/dialogs/symbology/hooks/useGetBandInfo'; import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; import BandRow from '@/src/dialogs/symbology/tiff_layer/components/BandRow'; +import { Spinner } from '@/src/mainview/spinner'; interface ISelectedBands { red: number; diff --git a/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx b/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx index 2abe6d098..6e2127e90 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.tsx @@ -3,8 +3,7 @@ import { Button } from '@jupyterlab/ui-components'; import { ReadonlyJSONObject } from '@lumino/coreutils'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { Spinner } from '@/src/mainview/spinner'; -import { GlobalStateDbManager } from '@/src/store'; + import { GeoTiffClassifications } from '@/src/dialogs/symbology/classificationModes'; import ColorRamp, { ColorRampOptions @@ -19,6 +18,8 @@ import { } from '@/src/dialogs/symbology/symbologyDialog'; import { Utils } from '@/src/dialogs/symbology/symbologyUtils'; import BandRow from '@/src/dialogs/symbology/tiff_layer/components/BandRow'; +import { Spinner } from '@/src/mainview/spinner'; +import { GlobalStateDbManager } from '@/src/store'; export type InterpolationType = 'discrete' | 'linear' | 'exact'; diff --git a/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx b/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx index f333869b9..74fad2205 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/VectorRendering.tsx @@ -1,15 +1,16 @@ import React, { useEffect, useState } from 'react'; + +import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; +import { + getColorCodeFeatureAttributes, + getNumericFeatureAttributes +} from '@/src/tools'; import Canonical from './types/Canonical'; import Categorized from './types/Categorized'; import Graduated from './types/Graduated'; import Heatmap from './types/Heatmap'; import SimpleSymbol from './types/SimpleSymbol'; -import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; -import { - getColorCodeFeatureAttributes, - getNumericFeatureAttributes -} from '@/src/tools'; const VectorRendering = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx index 428ec1080..098401661 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Canonical.tsx @@ -1,10 +1,11 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getColorCodeFeatureAttributes } from '@/src/tools'; + import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; +import { getColorCodeFeatureAttributes } from '@/src/tools'; const Canonical = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx index cbe041c80..d2762d294 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx @@ -2,7 +2,7 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ReadonlyJSONObject } from '@lumino/coreutils'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getNumericFeatureAttributes } from '@/src/tools'; + import ColorRamp from '@/src/dialogs/symbology/components/color_ramp/ColorRamp'; import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopContainer'; import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; @@ -12,6 +12,7 @@ import { } from '@/src/dialogs/symbology/symbologyDialog'; import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; +import { getNumericFeatureAttributes } from '@/src/tools'; const Categorized = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx index 7666de85d..22d1d31a0 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx @@ -1,7 +1,7 @@ import { IVectorLayer } from '@jupytergis/schema'; import { ExpressionValue } from 'ol/expr/expression'; import React, { useEffect, useRef, useState } from 'react'; -import { getNumericFeatureAttributes } from '@/src/tools'; + import { VectorClassifications } from '@/src/dialogs/symbology/classificationModes'; import ColorRamp, { ColorRampOptions @@ -14,6 +14,7 @@ import { } from '@/src/dialogs/symbology/symbologyDialog'; import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; +import { getNumericFeatureAttributes } from '@/src/tools'; const Graduated = ({ model, diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx index 1b590b758..3c9404ebd 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx @@ -1,5 +1,6 @@ import colormap from 'colormap'; import React, { useEffect, useRef, useState } from 'react'; + import CanvasSelectComponent from '@/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent'; import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx index e996c7aed..bbe307ead 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx @@ -1,7 +1,8 @@ import { FlatStyle } from 'ol/style/flat'; import React, { useEffect, useRef, useState } from 'react'; -import { IParsedStyle, parseColor } from '@/src/tools'; + import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; +import { IParsedStyle, parseColor } from '@/src/tools'; const SimpleSymbol = ({ model, diff --git a/packages/base/src/formbuilder/creationform.tsx b/packages/base/src/formbuilder/creationform.tsx index 09dbb37d5..51ad318b0 100644 --- a/packages/base/src/formbuilder/creationform.tsx +++ b/packages/base/src/formbuilder/creationform.tsx @@ -7,13 +7,12 @@ import { LayerType, SourceType } from '@jupytergis/schema'; - -import { deepCopy } from '@/src/tools'; - import { Dialog } from '@jupyterlab/apputils'; import { PromiseDelegate, UUID } from '@lumino/coreutils'; import { Signal } from '@lumino/signaling'; import * as React from 'react'; + +import { deepCopy } from '@/src/tools'; import { getLayerTypeForm, getSourceTypeForm } from './formselectors'; export interface ICreationFormProps { diff --git a/packages/base/src/formbuilder/formselectors.ts b/packages/base/src/formbuilder/formselectors.ts index 23ff0cecc..0696eceed 100644 --- a/packages/base/src/formbuilder/formselectors.ts +++ b/packages/base/src/formbuilder/formselectors.ts @@ -1,11 +1,5 @@ import { LayerType, SourceType } from '@jupytergis/schema'; -import { - GeoJSONSourcePropertiesForm, - GeoTiffSourcePropertiesForm, - PathBasedSourcePropertiesForm, - TileSourcePropertiesForm, - SourcePropertiesForm -} from './objectform/source'; + import { HeatmapLayerPropertiesForm, HillshadeLayerPropertiesForm, @@ -13,6 +7,13 @@ import { VectorLayerPropertiesForm, WebGlLayerPropertiesForm } from './objectform/layer'; +import { + GeoJSONSourcePropertiesForm, + GeoTiffSourcePropertiesForm, + PathBasedSourcePropertiesForm, + TileSourcePropertiesForm, + SourcePropertiesForm +} from './objectform/source'; export function getLayerTypeForm( layerType: LayerType diff --git a/packages/base/src/formbuilder/objectform/baseform.tsx b/packages/base/src/formbuilder/objectform/baseform.tsx index fc2e94ff4..5050da2f6 100644 --- a/packages/base/src/formbuilder/objectform/baseform.tsx +++ b/packages/base/src/formbuilder/objectform/baseform.tsx @@ -6,6 +6,7 @@ import { Signal } from '@lumino/signaling'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; import validatorAjv8 from '@rjsf/validator-ajv8'; import * as React from 'react'; + import { deepCopy } from '@/src/tools'; import { IDict } from '@/src/types'; diff --git a/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx b/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx index b9f813b3b..179d921ce 100644 --- a/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx +++ b/packages/base/src/formbuilder/objectform/fileselectorwidget.tsx @@ -1,8 +1,9 @@ -import React, { useState, useEffect, useRef } from 'react'; -import { FileDialog } from '@jupyterlab/filebrowser'; import { Dialog } from '@jupyterlab/apputils'; -import { LayerCreationFormDialog } from '@/src/dialogs/layerCreationFormDialog'; import { PathExt } from '@jupyterlab/coreutils'; +import { FileDialog } from '@jupyterlab/filebrowser'; +import React, { useState, useEffect, useRef } from 'react'; + +import { LayerCreationFormDialog } from '@/src/dialogs/layerCreationFormDialog'; export const FileSelectorWidget = (props: any) => { const { options } = props; diff --git a/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts b/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts index 2ca557436..6f492a3aa 100644 --- a/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts +++ b/packages/base/src/formbuilder/objectform/layer/heatmapLayerForm.ts @@ -1,5 +1,6 @@ import { IDict, IGeoJSONSource, IHeatmapLayer } from '@jupytergis/schema'; import { IChangeEvent } from '@rjsf/core'; + import { loadFile } from '@/src/tools'; import { ILayerProps, LayerPropertiesForm } from './layerform'; diff --git a/packages/base/src/formbuilder/objectform/layer/hillshadeLayerForm.ts b/packages/base/src/formbuilder/objectform/layer/hillshadeLayerForm.ts index 871c83fea..6dce00fe6 100644 --- a/packages/base/src/formbuilder/objectform/layer/hillshadeLayerForm.ts +++ b/packages/base/src/formbuilder/objectform/layer/hillshadeLayerForm.ts @@ -1,4 +1,5 @@ import { IDict } from '@jupytergis/schema'; + import { LayerPropertiesForm } from './layerform'; /** diff --git a/packages/base/src/formbuilder/objectform/layer/layerform.ts b/packages/base/src/formbuilder/objectform/layer/layerform.ts index bbc40556d..1e3dce9e2 100644 --- a/packages/base/src/formbuilder/objectform/layer/layerform.ts +++ b/packages/base/src/formbuilder/objectform/layer/layerform.ts @@ -1,10 +1,11 @@ import { IDict, SourceType } from '@jupytergis/schema'; +import { Signal } from '@lumino/signaling'; +import { IChangeEvent } from '@rjsf/core'; + import { BaseForm, IBaseFormProps } from '@/src/formbuilder/objectform/baseform'; -import { Signal } from '@lumino/signaling'; -import { IChangeEvent } from '@rjsf/core'; export interface ILayerProps extends IBaseFormProps { /** diff --git a/packages/base/src/formbuilder/objectform/layer/vectorlayerform.ts b/packages/base/src/formbuilder/objectform/layer/vectorlayerform.ts index beebabe56..37e54ca7d 100644 --- a/packages/base/src/formbuilder/objectform/layer/vectorlayerform.ts +++ b/packages/base/src/formbuilder/objectform/layer/vectorlayerform.ts @@ -1,5 +1,6 @@ import { IDict, IVectorLayer } from '@jupytergis/schema'; import { IChangeEvent } from '@rjsf/core'; + import { ILayerProps, LayerPropertiesForm } from './layerform'; /** diff --git a/packages/base/src/formbuilder/objectform/layer/webGlLayerForm.tsx b/packages/base/src/formbuilder/objectform/layer/webGlLayerForm.tsx index 8a79e6888..f47b42bfb 100644 --- a/packages/base/src/formbuilder/objectform/layer/webGlLayerForm.tsx +++ b/packages/base/src/formbuilder/objectform/layer/webGlLayerForm.tsx @@ -1,4 +1,5 @@ import { IDict } from '@jupytergis/schema'; + import { LayerPropertiesForm } from './layerform'; /** diff --git a/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx b/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx index d63ddb7d3..8b9b8017a 100644 --- a/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx +++ b/packages/base/src/formbuilder/objectform/process/dissolveProcessForm.tsx @@ -1,10 +1,11 @@ +import { IDict, IJupyterGISModel, IGeoJSONSource } from '@jupytergis/schema'; +import { IChangeEvent } from '@rjsf/core'; + import { BaseForm, IBaseFormProps, IBaseFormStates } from '@/src/formbuilder/objectform/baseform'; // Ensure BaseForm imports states -import { IDict, IJupyterGISModel, IGeoJSONSource } from '@jupytergis/schema'; -import { IChangeEvent } from '@rjsf/core'; import { loadFile } from '@/src/tools'; interface IDissolveFormOptions extends IBaseFormProps { diff --git a/packages/base/src/formbuilder/objectform/source/geojsonsource.ts b/packages/base/src/formbuilder/objectform/source/geojsonsource.ts index bc96a8792..668904b3a 100644 --- a/packages/base/src/formbuilder/objectform/source/geojsonsource.ts +++ b/packages/base/src/formbuilder/objectform/source/geojsonsource.ts @@ -1,9 +1,9 @@ import { IDict } from '@jupytergis/schema'; -import { Ajv, ValidateFunction } from 'ajv'; import * as geojson from '@jupytergis/schema/src/schema/geojson.json'; +import { Ajv, ValidateFunction } from 'ajv'; -import { PathBasedSourcePropertiesForm } from './pathbasedsource'; import { loadFile } from '@/src/tools'; +import { PathBasedSourcePropertiesForm } from './pathbasedsource'; import { ISourceFormProps } from './sourceform'; /** diff --git a/packages/base/src/formbuilder/objectform/source/geotiffsource.ts b/packages/base/src/formbuilder/objectform/source/geotiffsource.ts index 47b127c0e..941563f52 100644 --- a/packages/base/src/formbuilder/objectform/source/geotiffsource.ts +++ b/packages/base/src/formbuilder/objectform/source/geotiffsource.ts @@ -2,9 +2,9 @@ import { IDict } from '@jupytergis/schema'; import { showErrorMessage } from '@jupyterlab/apputils'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; +import { FileSelectorWidget } from '@/src/formbuilder/objectform/fileselectorwidget'; import { getMimeType } from '@/src/tools'; import { ISourceFormProps, SourcePropertiesForm } from './sourceform'; -import { FileSelectorWidget } from '@/src/formbuilder/objectform/fileselectorwidget'; /** * The form to modify a GeoTiff source. diff --git a/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts b/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts index 12a05f41d..c56cc1040 100644 --- a/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts +++ b/packages/base/src/formbuilder/objectform/source/pathbasedsource.ts @@ -2,8 +2,8 @@ import { IDict } from '@jupytergis/schema'; import { showErrorMessage } from '@jupyterlab/apputils'; import { IChangeEvent, ISubmitEvent } from '@rjsf/core'; -import { loadFile } from '@/src/tools'; import { FileSelectorWidget } from '@/src/formbuilder/objectform/fileselectorwidget'; +import { loadFile } from '@/src/tools'; import { ISourceFormProps, SourcePropertiesForm } from './sourceform'; /** diff --git a/packages/base/src/formbuilder/objectform/source/sourceform.ts b/packages/base/src/formbuilder/objectform/source/sourceform.ts index 8ee59b082..33b62bb85 100644 --- a/packages/base/src/formbuilder/objectform/source/sourceform.ts +++ b/packages/base/src/formbuilder/objectform/source/sourceform.ts @@ -1,10 +1,11 @@ import { IDict, SourceType } from '@jupytergis/schema'; +import { Signal } from '@lumino/signaling'; +import { IChangeEvent } from '@rjsf/core'; + import { BaseForm, IBaseFormProps } from '@/src/formbuilder/objectform/baseform'; -import { Signal } from '@lumino/signaling'; -import { IChangeEvent } from '@rjsf/core'; export interface ISourceFormProps extends IBaseFormProps { /** diff --git a/packages/base/src/formbuilder/objectform/source/tilesourceform.ts b/packages/base/src/formbuilder/objectform/source/tilesourceform.ts index 6fb1663b0..521b6a0d6 100644 --- a/packages/base/src/formbuilder/objectform/source/tilesourceform.ts +++ b/packages/base/src/formbuilder/objectform/source/tilesourceform.ts @@ -1,4 +1,5 @@ import { IDict } from '@jupytergis/schema'; + import { SourcePropertiesForm } from './sourceform'; export class TileSourcePropertiesForm extends SourcePropertiesForm { diff --git a/packages/base/src/icons.ts b/packages/base/src/icons.ts index ece63911f..636ad24ec 100644 --- a/packages/base/src/icons.ts +++ b/packages/base/src/icons.ts @@ -6,23 +6,24 @@ // This file is based on iconimports.ts in @jupyterlab/ui-components, but is manually generated. import { LabIcon } from '@jupyterlab/ui-components'; + +import bookOpenSvgStr from '../style/icons/book_open.svg'; +import clockSvgStr from '../style/icons/clock-solid.svg'; +import geoJsonSvgStr from '../style/icons/geojson.svg'; +import geolocationSvgStr from '../style/icons/geolocation.svg'; +import infoSvgStr from '../style/icons/info-solid.svg'; import logoSvgStr from '../style/icons/logo.svg'; import logoMiniSvgStr from '../style/icons/logo_mini.svg'; import logoMiniAlternativeSvgStr from '../style/icons/logo_mini_alternative.svg'; -import rasterSvgStr from '../style/icons/raster.svg'; -import visibilitySvgStr from '../style/icons/visibility.svg'; -import nonVisibilitySvgStr from '../style/icons/nonvisibility.svg'; -import geoJsonSvgStr from '../style/icons/geojson.svg'; -import moundSvgStr from '../style/icons/mound.svg'; import logoMiniQGZ from '../style/icons/logo_mini_qgz.svg'; -import bookOpenSvgStr from '../style/icons/book_open.svg'; -import vectorSquareSvgStr from '../style/icons/vector_square.svg'; -import infoSvgStr from '../style/icons/info-solid.svg'; -import clockSvgStr from '../style/icons/clock-solid.svg'; -import terminalToolbarSvgStr from '../style/icons/terminal_toolbar.svg'; -import geolocationSvgStr from '../style/icons/geolocation.svg'; -import targetWithoutCenterSvgStr from '../style/icons/target_without_center.svg'; +import moundSvgStr from '../style/icons/mound.svg'; +import nonVisibilitySvgStr from '../style/icons/nonvisibility.svg'; +import rasterSvgStr from '../style/icons/raster.svg'; import targetWithCenterSvgStr from '../style/icons/target_with_center.svg'; +import targetWithoutCenterSvgStr from '../style/icons/target_without_center.svg'; +import terminalToolbarSvgStr from '../style/icons/terminal_toolbar.svg'; +import vectorSquareSvgStr from '../style/icons/vector_square.svg'; +import visibilitySvgStr from '../style/icons/visibility.svg'; export const logoIcon = new LabIcon({ name: 'jupytergis::logo', diff --git a/packages/base/src/mainview/FollowIndicator.tsx b/packages/base/src/mainview/FollowIndicator.tsx index 277a0adc4..75570a5e0 100644 --- a/packages/base/src/mainview/FollowIndicator.tsx +++ b/packages/base/src/mainview/FollowIndicator.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { User } from '@jupyterlab/services'; +import React from 'react'; interface IFollowIndicatorProps { remoteUser: User.IIdentity | null | undefined; diff --git a/packages/base/src/mainview/TemporalSlider.tsx b/packages/base/src/mainview/TemporalSlider.tsx index 1e127213a..d593d6824 100644 --- a/packages/base/src/mainview/TemporalSlider.tsx +++ b/packages/base/src/mainview/TemporalSlider.tsx @@ -19,6 +19,7 @@ import { minutesInMonth } from 'date-fns/constants'; import React, { useEffect, useRef, useState } from 'react'; + import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; interface ITemporalSliderProps { diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index 31344382a..ee746b75f 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -36,13 +36,12 @@ import { CommandRegistry } from '@lumino/commands'; import { JSONValue, UUID } from '@lumino/coreutils'; import { ContextMenu } from '@lumino/widgets'; import { Collection, MapBrowserEvent, Map as OlMap, View, getUid } from 'ol'; -//@ts-expect-error no types for ol-pmtiles -import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles'; import Feature, { FeatureLike } from 'ol/Feature'; import { ScaleLine } from 'ol/control'; import { Coordinate } from 'ol/coordinate'; import { singleClick } from 'ol/events/condition'; import { GeoJSON, MVT } from 'ol/format'; +import { Geometry, Point } from 'ol/geom'; import { DragAndDrop, Select } from 'ol/interaction'; import { Heatmap as HeatmapLayer, @@ -59,8 +58,8 @@ import { toLonLat, transformExtent } from 'ol/proj'; -import { get as getProjection } from 'ol/proj.js'; import { register } from 'ol/proj/proj4.js'; +import { get as getProjection } from 'ol/proj.js'; import RenderFeature from 'ol/render/Feature'; import { GeoTIFF as GeoTIFFSource, @@ -73,9 +72,12 @@ import Static from 'ol/source/ImageStatic'; import TileSource from 'ol/source/Tile'; import { Circle, Fill, Stroke, Style } from 'ol/style'; import { Rule } from 'ol/style/flat'; +//@ts-expect-error no types for ol-pmtiles +import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles'; import proj4 from 'proj4'; import proj4list from 'proj4-list'; import * as React from 'react'; + import AnnotationFloater from '@/src/annotations/components/AnnotationFloater'; import { CommandIDs } from '@/src/constants'; import StatusBar from '@/src/statusbar/StatusBar'; @@ -85,7 +87,6 @@ import { FollowIndicator } from './FollowIndicator'; import TemporalSlider from './TemporalSlider'; import { MainViewModel } from './mainviewmodel'; import { Spinner } from './spinner'; -import { Geometry, Point } from 'ol/geom'; interface IProps { viewModel: MainViewModel; diff --git a/packages/base/src/menus.ts b/packages/base/src/menus.ts index a207c0144..a15cbc657 100644 --- a/packages/base/src/menus.ts +++ b/packages/base/src/menus.ts @@ -1,5 +1,5 @@ -import { Menu } from '@lumino/widgets'; import { CommandRegistry } from '@lumino/commands'; +import { Menu } from '@lumino/widgets'; import { CommandIDs } from './constants'; import { rasterIcon } from './icons'; diff --git a/packages/base/src/panelview/annotationPanel.tsx b/packages/base/src/panelview/annotationPanel.tsx index c61d0c4ac..5138d5fad 100644 --- a/packages/base/src/panelview/annotationPanel.tsx +++ b/packages/base/src/panelview/annotationPanel.tsx @@ -1,6 +1,7 @@ +import { IAnnotationModel } from '@jupytergis/schema'; import { PanelWithToolbar, ReactWidget } from '@jupyterlab/ui-components'; import React, { Component } from 'react'; -import { IAnnotationModel } from '@jupytergis/schema'; + import Annotation from '@/src/annotations/components/Annotation'; import { IControlPanelModel } from '@/src/types'; diff --git a/packages/base/src/panelview/components/filter-panel/Filter.tsx b/packages/base/src/panelview/components/filter-panel/Filter.tsx index ab50cb479..567162319 100644 --- a/packages/base/src/panelview/components/filter-panel/Filter.tsx +++ b/packages/base/src/panelview/components/filter-panel/Filter.tsx @@ -9,6 +9,7 @@ import { Button, ReactWidget } from '@jupyterlab/ui-components'; import { Panel } from '@lumino/widgets'; import { cloneDeep } from 'lodash'; import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; + import { debounce, loadFile } from '@/src/tools'; import { IControlPanelModel } from '@/src/types'; import FilterRow from './FilterRow'; diff --git a/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx b/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx index 0c0548026..708bafaba 100644 --- a/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx +++ b/packages/base/src/panelview/components/identify-panel/IdentifyPanel.tsx @@ -1,17 +1,17 @@ +import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IDict, IJupyterGISClientState, IJupyterGISModel, IJupyterGISTracker } from '@jupytergis/schema'; +import { User } from '@jupyterlab/services'; import { LabIcon, ReactWidget, caretDownIcon } from '@jupyterlab/ui-components'; import { Panel } from '@lumino/widgets'; import React, { useEffect, useRef, useState } from 'react'; -import { IControlPanelModel } from '@/src/types'; -import { User } from '@jupyterlab/services'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; +import { IControlPanelModel } from '@/src/types'; export class IdentifyPanel extends Panel { constructor(options: IdentifyPanel.IOptions) { diff --git a/packages/base/src/panelview/components/layers.tsx b/packages/base/src/panelview/components/layers.tsx index b2e36c752..ea8bf0598 100644 --- a/packages/base/src/panelview/components/layers.tsx +++ b/packages/base/src/panelview/components/layers.tsx @@ -19,13 +19,14 @@ import React, { useEffect, useState } from 'react'; + import { icons } from '@/src/constants'; import { nonVisibilityIcon, visibilityIcon } from '@/src/icons'; -import { IControlPanelModel } from '@/src/types'; import { ILayerPanelOptions, ILeftPanelClickHandlerParams } from '@/src/panelview/leftpanel'; +import { IControlPanelModel } from '@/src/types'; const LAYERS_PANEL_CLASS = 'jp-gis-layerPanel'; const LAYER_GROUP_CLASS = 'jp-gis-layerGroup'; diff --git a/packages/base/src/panelview/leftpanel.tsx b/packages/base/src/panelview/leftpanel.tsx index 3a536e521..3b9f1775d 100644 --- a/packages/base/src/panelview/leftpanel.tsx +++ b/packages/base/src/panelview/leftpanel.tsx @@ -6,14 +6,15 @@ import { } from '@jupytergis/schema'; import { IStateDB } from '@jupyterlab/statedb'; import { SidePanel } from '@jupyterlab/ui-components'; +import { CommandRegistry } from '@lumino/commands'; import { Message } from '@lumino/messaging'; import { MouseEvent as ReactMouseEvent } from 'react'; + +import { CommandIDs } from '@/src/constants'; import { IControlPanelModel } from '@/src/types'; +import { FilterPanel } from './components/filter-panel/Filter'; import { LayersPanel } from './components/layers'; import { ControlPanelHeader } from './header'; -import { FilterPanel } from './components/filter-panel/Filter'; -import { CommandRegistry } from '@lumino/commands'; -import { CommandIDs } from '@/src/constants'; /** * Options of the left panel widget. diff --git a/packages/base/src/panelview/objectproperties.tsx b/packages/base/src/panelview/objectproperties.tsx index a8257269c..5f97b8c66 100644 --- a/packages/base/src/panelview/objectproperties.tsx +++ b/packages/base/src/panelview/objectproperties.tsx @@ -10,8 +10,8 @@ import { Panel } from '@lumino/widgets'; import * as React from 'react'; import { v4 as uuid } from 'uuid'; -import { IControlPanelModel } from '@/src/types'; import { EditForm } from '@/src/formbuilder/editform'; +import { IControlPanelModel } from '@/src/types'; export class ObjectProperties extends PanelWithToolbar { constructor(params: ObjectProperties.IOptions) { diff --git a/packages/base/src/panelview/rightpanel.tsx b/packages/base/src/panelview/rightpanel.tsx index 3c42534a6..f95b3da01 100644 --- a/packages/base/src/panelview/rightpanel.tsx +++ b/packages/base/src/panelview/rightpanel.tsx @@ -8,10 +8,10 @@ import { import { SidePanel } from '@jupyterlab/ui-components'; import { IControlPanelModel } from '@/src/types'; -import { ControlPanelHeader } from './header'; -import { ObjectProperties } from './objectproperties'; import { Annotations } from './annotationPanel'; import IdentifyPanel from './components/identify-panel/IdentifyPanel'; +import { ControlPanelHeader } from './header'; +import { ObjectProperties } from './objectproperties'; export class RightPanelWidget extends SidePanel { constructor(options: RightPanelWidget.IOptions) { diff --git a/packages/base/src/processing.ts b/packages/base/src/processing.ts index 23fb245ce..3baf78c0f 100644 --- a/packages/base/src/processing.ts +++ b/packages/base/src/processing.ts @@ -6,12 +6,13 @@ import { IJGISFormSchemaRegistry, LayerType } from '@jupytergis/schema'; -import { getGdal } from './gdal'; -import { JupyterGISTracker } from './types'; +import { JupyterFrontEnd } from '@jupyterlab/application'; import { UUID } from '@lumino/coreutils'; + import { ProcessingFormDialog } from './dialogs/ProcessingFormDialog'; +import { getGdal } from './gdal'; import { getGeoJSONDataFromLayerSource } from './tools'; -import { JupyterFrontEnd } from '@jupyterlab/application'; +import { JupyterGISTracker } from './types'; /** * Get the currently selected layer from the shared model. Returns null if there is no selection or multiple layer is selected. diff --git a/packages/base/src/statusbar/StatusBar.tsx b/packages/base/src/statusbar/StatusBar.tsx index 62dbd4fa1..9c156800a 100644 --- a/packages/base/src/statusbar/StatusBar.tsx +++ b/packages/base/src/statusbar/StatusBar.tsx @@ -7,6 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Progress } from '@jupyter/react-components'; import { IJupyterGISModel, JgisCoordinates } from '@jupytergis/schema'; import React, { useEffect, useState } from 'react'; + import { version } from '@/package.json'; interface IStatusBarProps { diff --git a/packages/base/src/toolbar/widget.tsx b/packages/base/src/toolbar/widget.tsx index 1dae61869..3615b6194 100644 --- a/packages/base/src/toolbar/widget.tsx +++ b/packages/base/src/toolbar/widget.tsx @@ -1,3 +1,4 @@ +import { UsersItem } from '@jupyter/collaboration'; import { IJGISExternalCommand, JupyterGISModel } from '@jupytergis/schema'; import { CommandToolbarButton } from '@jupyterlab/apputils'; import { @@ -12,12 +13,11 @@ import { } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { Widget } from '@lumino/widgets'; - import * as React from 'react'; + import { CommandIDs } from '@/src/constants'; import { terminalToolbarIcon } from '@/src/icons'; import { rasterSubMenu, vectorSubMenu } from '@/src/menus'; -import { UsersItem } from '@jupyter/collaboration'; export const TOOLBAR_SEPARATOR_CLASS = 'jGIS-Toolbar-Separator'; export const TOOLBAR_GROUPNAME_CLASS = 'jGIS-Toolbar-GroupName'; diff --git a/packages/base/src/tools.ts b/packages/base/src/tools.ts index 4442eb4ff..e4a3a7977 100644 --- a/packages/base/src/tools.ts +++ b/packages/base/src/tools.ts @@ -1,14 +1,3 @@ -import Protobuf from 'pbf'; - -import { VectorTile } from '@mapbox/vector-tile'; - -import { PathExt, URLExt } from '@jupyterlab/coreutils'; -import { Contents, ServerConnection } from '@jupyterlab/services'; -import { showErrorMessage } from '@jupyterlab/apputils'; -import * as d3Color from 'd3-color'; -import shp from 'shpjs'; -import { getGdal } from '@/src/gdal'; - import { IDict, IJGISLayerBrowserRegistry, @@ -18,7 +7,16 @@ import { IRasterLayerGalleryEntry, SourceType } from '@jupytergis/schema'; +import { showErrorMessage } from '@jupyterlab/apputils'; +import { PathExt, URLExt } from '@jupyterlab/coreutils'; +import { Contents, ServerConnection } from '@jupyterlab/services'; +import { VectorTile } from '@mapbox/vector-tile'; +import * as d3Color from 'd3-color'; +import Protobuf from 'pbf'; +import shp from 'shpjs'; + import RASTER_LAYER_GALLERY from '@/rasterlayer_gallery/raster_layer_gallery.json'; +import { getGdal } from '@/src/gdal'; export const debounce = ( func: CallableFunction, diff --git a/packages/base/src/widget.ts b/packages/base/src/widget.ts index b0889ec93..3dfde7707 100644 --- a/packages/base/src/widget.ts +++ b/packages/base/src/widget.ts @@ -7,12 +7,12 @@ import { MainAreaWidget } from '@jupyterlab/apputils'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; import { DocumentWidget } from '@jupyterlab/docregistry'; import { IObservableMap, ObservableMap } from '@jupyterlab/observables'; +import { CommandRegistry } from '@lumino/commands'; import { JSONValue } from '@lumino/coreutils'; +import { MessageLoop } from '@lumino/messaging'; import { ISignal, Signal } from '@lumino/signaling'; import { SplitPanel, Widget } from '@lumino/widgets'; -import { CommandRegistry } from '@lumino/commands'; -import { MessageLoop } from '@lumino/messaging'; import { ConsoleView } from './console'; import { JupyterGISMainViewPanel } from './mainview'; import { MainViewModel } from './mainview/mainviewmodel'; diff --git a/packages/schema/src/doc.ts b/packages/schema/src/doc.ts index f51c53d79..dd9e3ff0e 100644 --- a/packages/schema/src/doc.ts +++ b/packages/schema/src/doc.ts @@ -1,7 +1,6 @@ import { Delta, MapChange, YDocument } from '@jupyter/ydoc'; import { JSONExt, JSONObject } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; -import { SCHEMA_VERSION } from './_interface/version'; import * as Y from 'yjs'; import { @@ -13,6 +12,7 @@ import { IJGISSource, IJGISSources } from './_interface/project/jgis'; +import { SCHEMA_VERSION } from './_interface/version'; import { IDict, IJGISLayerDocChange, diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index b079591de..3107ad685 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -2,9 +2,11 @@ import { MapChange } from '@jupyter/ydoc'; import { IChangedArgs } from '@jupyterlab/coreutils'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; +import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { PartialJSONObject } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; import Ajv from 'ajv'; + import { IJGISContent, IJGISLayer, @@ -34,7 +36,6 @@ import { IJupyterGISSettings } from './interfaces'; import jgisSchema from './schema/project/jgis.json'; -import { ISettingRegistry } from '@jupyterlab/settingregistry'; const SETTINGS_ID = '@jupytergis/jupytergis-core:jupytergis-settings'; diff --git a/python/jupytergis_core/src/factory.ts b/python/jupytergis_core/src/factory.ts index f2363d90e..6fee7ea00 100644 --- a/python/jupytergis_core/src/factory.ts +++ b/python/jupytergis_core/src/factory.ts @@ -1,21 +1,20 @@ -import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; import { ICollaborativeDrive } from '@jupyter/collaborative-drive'; +import { + JupyterGISPanel, + JupyterGISDocumentWidget, + ToolbarWidget +} from '@jupytergis/base'; import { JupyterGISModel, IJupyterGISTracker, IJGISExternalCommandRegistry } from '@jupytergis/schema'; -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { IEditorMimeTypeService } from '@jupyterlab/codeeditor'; +import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry'; -import { CommandRegistry } from '@lumino/commands'; - -import { - JupyterGISPanel, - JupyterGISDocumentWidget, - ToolbarWidget -} from '@jupytergis/base'; +import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { Contents, ServiceManager } from '@jupyterlab/services'; +import { CommandRegistry } from '@lumino/commands'; interface IOptions extends DocumentRegistry.IWidgetFactoryOptions { tracker: IJupyterGISTracker; diff --git a/python/jupytergis_core/src/jgisplugin/plugins.ts b/python/jupytergis_core/src/jgisplugin/plugins.ts index 3c3b54e54..c51d0074c 100644 --- a/python/jupytergis_core/src/jgisplugin/plugins.ts +++ b/python/jupytergis_core/src/jgisplugin/plugins.ts @@ -2,6 +2,7 @@ import { ICollaborativeDrive, SharedDocumentFactory } from '@jupyter/collaborative-drive'; +import { CommandIDs, logoIcon, logoMiniIcon } from '@jupytergis/base'; import { IAnnotationModel, IAnnotationToken, @@ -24,15 +25,14 @@ import { import { IEditorServices } from '@jupyterlab/codeeditor'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; import { PageConfig } from '@jupyterlab/coreutils'; +import { MimeDocumentFactory } from '@jupyterlab/docregistry'; import { IFileBrowserFactory } from '@jupyterlab/filebrowser'; import { ILauncher } from '@jupyterlab/launcher'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { CommandIDs, logoIcon, logoMiniIcon } from '@jupytergis/base'; import { JupyterGISDocumentWidgetFactory } from '../factory'; import { JupyterGISModelFactory } from './modelfactory'; -import { MimeDocumentFactory } from '@jupyterlab/docregistry'; const FACTORY = 'JupyterGIS .jgis Viewer'; const CONTENT_TYPE = 'jgis'; diff --git a/python/jupytergis_core/src/plugin.ts b/python/jupytergis_core/src/plugin.ts index 87c9ee85b..bf18c7ece 100644 --- a/python/jupytergis_core/src/plugin.ts +++ b/python/jupytergis_core/src/plugin.ts @@ -17,9 +17,9 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application'; import { WidgetTracker } from '@jupyterlab/apputils'; +import { IDocumentManager } from '@jupyterlab/docmanager'; import { IMainMenu } from '@jupyterlab/mainmenu'; import { ITranslator } from '@jupyterlab/translation'; -import { IDocumentManager } from '@jupyterlab/docmanager'; import { JupyterGISExternalCommandRegistry } from './externalcommand'; import { JupyterGISLayerBrowserRegistry } from './layerBrowserRegistry'; diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index 83aeaf127..a1d32f9a7 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -33,6 +33,7 @@ import { IMainMenu } from '@jupyterlab/mainmenu'; import { IStateDB } from '@jupyterlab/statedb'; import { ITranslator, nullTranslator } from '@jupyterlab/translation'; import { ContextMenu, Menu } from '@lumino/widgets'; + import { notebookRendererPlugin } from './notebookrenderer'; const NAME_SPACE = 'jupytergis'; diff --git a/python/jupytergis_qgis/src/plugins.ts b/python/jupytergis_qgis/src/plugins.ts index f828d0070..6aa347ade 100644 --- a/python/jupytergis_qgis/src/plugins.ts +++ b/python/jupytergis_qgis/src/plugins.ts @@ -2,6 +2,13 @@ import { ICollaborativeDrive, SharedDocumentFactory } from '@jupyter/collaborative-drive'; +import { + JupyterGISDocumentWidget, + logoMiniIcon, + logoMiniIconQGZ, + requestAPI +} from '@jupytergis/base'; +import { JupyterGISDocumentWidgetFactory } from '@jupytergis/jupytergis-core'; import { IJGISExternalCommandRegistry, IJGISExternalCommandRegistryToken, @@ -28,16 +35,9 @@ import { IEditorServices } from '@jupyterlab/codeeditor'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; import { PathExt } from '@jupyterlab/coreutils'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { Widget } from '@lumino/widgets'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { Widget } from '@lumino/widgets'; -import { - JupyterGISDocumentWidget, - logoMiniIcon, - logoMiniIconQGZ, - requestAPI -} from '@jupytergis/base'; -import { JupyterGISDocumentWidgetFactory } from '@jupytergis/jupytergis-core'; import { QGSModelFactory, QGZModelFactory } from './modelfactory'; /** diff --git a/yarn.lock b/yarn.lock index 28eb48b2c..e562f429d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -921,6 +921,7 @@ __metadata: copy-webpack-plugin: ^10.0.0 eslint: ^8.36.0 eslint-config-prettier: ^8.8.0 + eslint-plugin-import: ^2.31.0 eslint-plugin-prettier: ^5.0.1 lerna: ^8.1.9 npm-run-all: ^4.1.5 @@ -2644,6 +2645,13 @@ __metadata: languageName: node linkType: hard +"@rtsao/scc@npm:^1.1.0": + version: 1.1.0 + resolution: "@rtsao/scc@npm:1.1.0" + checksum: 17d04adf404e04c1e61391ed97bca5117d4c2767a76ae3e879390d6dec7b317fcae68afbf9e98badee075d0b64fa60f287729c4942021b4d19cd01db77385c01 + languageName: node + linkType: hard + "@sigstore/bundle@npm:^2.3.2": version: 2.3.2 resolution: "@sigstore/bundle@npm:2.3.2" @@ -2809,6 +2817,13 @@ __metadata: languageName: node linkType: hard +"@types/json5@npm:^0.0.29": + version: 0.0.29 + resolution: "@types/json5@npm:0.0.29" + checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac + languageName: node + linkType: hard + "@types/leaflet@npm:^1.9.8": version: 1.9.18 resolution: "@types/leaflet@npm:1.9.18" @@ -3585,6 +3600,22 @@ __metadata: languageName: node linkType: hard +"array-includes@npm:^3.1.8": + version: 3.1.9 + resolution: "array-includes@npm:3.1.9" + dependencies: + call-bind: ^1.0.8 + call-bound: ^1.0.4 + define-properties: ^1.2.1 + es-abstract: ^1.24.0 + es-object-atoms: ^1.1.1 + get-intrinsic: ^1.3.0 + is-string: ^1.1.1 + math-intrinsics: ^1.1.0 + checksum: b58dc526fe415252e50319eaf88336e06e75aa673e3b58d252414739a4612dbe56e7b613fdcc7c90561dc9cf9202bbe5ca029ccd8c08362746459475ae5a8f3e + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -3599,6 +3630,45 @@ __metadata: languageName: node linkType: hard +"array.prototype.findlastindex@npm:^1.2.5": + version: 1.2.6 + resolution: "array.prototype.findlastindex@npm:1.2.6" + dependencies: + call-bind: ^1.0.8 + call-bound: ^1.0.4 + define-properties: ^1.2.1 + es-abstract: ^1.23.9 + es-errors: ^1.3.0 + es-object-atoms: ^1.1.1 + es-shim-unscopables: ^1.1.0 + checksum: bd2665bd51f674d4e1588ce5d5848a8adb255f414070e8e652585598b801480516df2c6cef2c60b6ea1a9189140411c49157a3f112d52e9eabb4e9fc80936ea6 + languageName: node + linkType: hard + +"array.prototype.flat@npm:^1.3.2": + version: 1.3.3 + resolution: "array.prototype.flat@npm:1.3.3" + dependencies: + call-bind: ^1.0.8 + define-properties: ^1.2.1 + es-abstract: ^1.23.5 + es-shim-unscopables: ^1.0.2 + checksum: 5d5a7829ab2bb271a8d30a1c91e6271cef0ec534593c0fe6d2fb9ebf8bb62c1e5326e2fddcbbcbbe5872ca04f5e6b54a1ecf092e0af704fb538da9b2bfd95b40 + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.2": + version: 1.3.3 + resolution: "array.prototype.flatmap@npm:1.3.3" + dependencies: + call-bind: ^1.0.8 + define-properties: ^1.2.1 + es-abstract: ^1.23.5 + es-shim-unscopables: ^1.0.2 + checksum: 11b4de09b1cf008be6031bb507d997ad6f1892e57dc9153583de6ebca0f74ea403fffe0f203461d359de05048d609f3f480d9b46fed4099652d8b62cc972f284 + languageName: node + linkType: hard + "arraybuffer.prototype.slice@npm:^1.0.4": version: 1.0.4 resolution: "arraybuffer.prototype.slice@npm:1.0.4" @@ -4569,6 +4639,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:^3.2.7": + version: 3.2.7 + resolution: "debug@npm:3.2.7" + dependencies: + ms: ^2.1.1 + checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c + languageName: node + linkType: hard + "decamelize-keys@npm:^1.1.0": version: 1.1.1 resolution: "decamelize-keys@npm:1.1.1" @@ -4694,6 +4773,15 @@ __metadata: languageName: node linkType: hard +"doctrine@npm:^2.1.0": + version: 2.1.0 + resolution: "doctrine@npm:2.1.0" + dependencies: + esutils: ^2.0.2 + checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 + languageName: node + linkType: hard + "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -4941,7 +5029,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.9": +"es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0": version: 1.24.0 resolution: "es-abstract@npm:1.24.0" dependencies: @@ -5045,6 +5133,15 @@ __metadata: languageName: node linkType: hard +"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": + version: 1.1.0 + resolution: "es-shim-unscopables@npm:1.1.0" + dependencies: + hasown: ^2.0.2 + checksum: 33cfb1ebcb2f869f0bf528be1a8660b4fe8b6cec8fc641f330e508db2284b58ee2980fad6d0828882d22858c759c0806076427a3673b6daa60f753e3b558ee15 + languageName: node + linkType: hard + "es-to-primitive@npm:^1.3.0": version: 1.3.0 resolution: "es-to-primitive@npm:1.3.0" @@ -5133,6 +5230,58 @@ __metadata: languageName: node linkType: hard +"eslint-import-resolver-node@npm:^0.3.9": + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" + dependencies: + debug: ^3.2.7 + is-core-module: ^2.13.0 + resolve: ^1.22.4 + checksum: 439b91271236b452d478d0522a44482e8c8540bf9df9bd744062ebb89ab45727a3acd03366a6ba2bdbcde8f9f718bab7fe8db64688aca75acf37e04eafd25e22 + languageName: node + linkType: hard + +"eslint-module-utils@npm:^2.12.0": + version: 2.12.0 + resolution: "eslint-module-utils@npm:2.12.0" + dependencies: + debug: ^3.2.7 + peerDependenciesMeta: + eslint: + optional: true + checksum: be3ac52e0971c6f46daeb1a7e760e45c7c45f820c8cc211799f85f10f04ccbf7afc17039165d56cb2da7f7ca9cec2b3a777013cddf0b976784b37eb9efa24180 + languageName: node + linkType: hard + +"eslint-plugin-import@npm:^2.31.0": + version: 2.31.0 + resolution: "eslint-plugin-import@npm:2.31.0" + dependencies: + "@rtsao/scc": ^1.1.0 + array-includes: ^3.1.8 + array.prototype.findlastindex: ^1.2.5 + array.prototype.flat: ^1.3.2 + array.prototype.flatmap: ^1.3.2 + debug: ^3.2.7 + doctrine: ^2.1.0 + eslint-import-resolver-node: ^0.3.9 + eslint-module-utils: ^2.12.0 + hasown: ^2.0.2 + is-core-module: ^2.15.1 + is-glob: ^4.0.3 + minimatch: ^3.1.2 + object.fromentries: ^2.0.8 + object.groupby: ^1.0.3 + object.values: ^1.2.0 + semver: ^6.3.1 + string.prototype.trimend: ^1.0.8 + tsconfig-paths: ^3.15.0 + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + checksum: b1d2ac268b3582ff1af2a72a2c476eae4d250c100f2e335b6e102036e4a35efa530b80ec578dfc36761fabb34a635b9bf5ab071abe9d4404a4bb054fdf22d415 + languageName: node + linkType: hard + "eslint-plugin-prettier@npm:^5.0.1": version: 5.4.1 resolution: "eslint-plugin-prettier@npm:5.4.1" @@ -6509,7 +6658,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.16.0, is-core-module@npm:^2.5.0": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.15.1, is-core-module@npm:^2.16.0, is-core-module@npm:^2.5.0": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -7086,6 +7235,17 @@ __metadata: languageName: node linkType: hard +"json5@npm:^1.0.2": + version: 1.0.2 + resolution: "json5@npm:1.0.2" + dependencies: + minimist: ^1.2.0 + bin: + json5: lib/cli.js + checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 + languageName: node + linkType: hard + "json5@npm:^2.1.2, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -7869,7 +8029,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.1.3": +"ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -8310,6 +8470,41 @@ __metadata: languageName: node linkType: hard +"object.fromentries@npm:^2.0.8": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" + dependencies: + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-object-atoms: ^1.0.0 + checksum: 29b2207a2db2782d7ced83f93b3ff5d425f901945f3665ffda1821e30a7253cd1fd6b891a64279976098137ddfa883d748787a6fea53ecdb51f8df8b8cec0ae1 + languageName: node + linkType: hard + +"object.groupby@npm:^1.0.3": + version: 1.0.3 + resolution: "object.groupby@npm:1.0.3" + dependencies: + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + checksum: 0d30693ca3ace29720bffd20b3130451dca7a56c612e1926c0a1a15e4306061d84410bdb1456be2656c5aca53c81b7a3661eceaa362db1bba6669c2c9b6d1982 + languageName: node + linkType: hard + +"object.values@npm:^1.2.0": + version: 1.2.1 + resolution: "object.values@npm:1.2.1" + dependencies: + call-bind: ^1.0.8 + call-bound: ^1.0.3 + define-properties: ^1.2.1 + es-object-atoms: ^1.0.0 + checksum: f9b9a2a125ccf8ded29414d7c056ae0d187b833ee74919821fc60d7e216626db220d9cb3cf33f965c84aaaa96133626ca13b80f3c158b673976dc8cfcfcd26bb + languageName: node + linkType: hard + "ol-pmtiles@npm:^0.5.0": version: 0.5.0 resolution: "ol-pmtiles@npm:0.5.0" @@ -9411,7 +9606,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2": +"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -9424,7 +9619,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin": +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#~builtin::version=1.22.10&hash=c3c19d" dependencies: @@ -9636,6 +9831,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + languageName: node + linkType: hard + "semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.3": version: 7.7.2 resolution: "semver@npm:7.7.2" @@ -10091,7 +10295,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.9": +"string.prototype.trimend@npm:^1.0.8, string.prototype.trimend@npm:^1.0.9": version: 1.0.9 resolution: "string.prototype.trimend@npm:1.0.9" dependencies: @@ -10528,6 +10732,18 @@ __metadata: languageName: node linkType: hard +"tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" + dependencies: + "@types/json5": ^0.0.29 + json5: ^1.0.2 + minimist: ^1.2.6 + strip-bom: ^3.0.0 + checksum: 59f35407a390d9482b320451f52a411a256a130ff0e7543d18c6f20afab29ac19fbe55c360a93d6476213cc335a4d76ce90f67df54c4e9037f7d240920832201 + languageName: node + linkType: hard + "tsconfig-paths@npm:^4.1.2": version: 4.2.0 resolution: "tsconfig-paths@npm:4.2.0" From e4d256702b73e4e446fa36ef14127c6cd147699c Mon Sep 17 00:00:00 2001 From: Matt Fisher <3608264+mfisher87@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:07:43 -0600 Subject: [PATCH 04/17] Update prettier config to always use trailing commas (#731) --- .prettierrc | 2 +- .../how-tos/commands/index.md | 8 +- .../src/annotations/components/Annotation.tsx | 8 +- .../components/AnnotationFloater.tsx | 2 +- .../src/annotations/components/Message.tsx | 4 +- packages/base/src/annotations/model.ts | 6 +- packages/base/src/classificationModes.ts | 16 +- packages/base/src/commands.ts | 162 +++++------ packages/base/src/console/consoleview.ts | 12 +- packages/base/src/constants.ts | 6 +- .../base/src/dialogs/ProcessingFormDialog.tsx | 16 +- .../base/src/dialogs/layerBrowserDialog.tsx | 22 +- .../src/dialogs/layerCreationFormDialog.tsx | 4 +- .../dialogs/symbology/classificationModes.ts | 16 +- .../color_ramp/CanvasSelectComponent.tsx | 6 +- .../components/color_ramp/ColorRamp.tsx | 6 +- .../components/color_ramp/ModeSelectRow.tsx | 2 +- .../components/color_stops/StopContainer.tsx | 6 +- .../components/color_stops/StopRow.tsx | 4 +- .../dialogs/symbology/hooks/useGetBandInfo.ts | 6 +- .../symbology/hooks/useGetProperties.ts | 4 +- .../src/dialogs/symbology/symbologyDialog.tsx | 2 +- .../src/dialogs/symbology/symbologyUtils.ts | 12 +- .../symbology/tiff_layer/TiffRendering.tsx | 2 +- .../tiff_layer/components/BandRow.tsx | 6 +- .../tiff_layer/types/MultibandColor.tsx | 10 +- .../types/SingleBandPseudoColor.tsx | 36 +-- .../vector_layer/VectorRendering.tsx | 10 +- .../vector_layer/components/ValueSelect.tsx | 2 +- .../vector_layer/types/Canonical.tsx | 6 +- .../vector_layer/types/Categorized.tsx | 14 +- .../vector_layer/types/Graduated.tsx | 28 +- .../symbology/vector_layer/types/Heatmap.tsx | 14 +- .../vector_layer/types/SimpleSymbol.tsx | 20 +- .../base/src/formbuilder/creationform.tsx | 16 +- packages/base/src/formbuilder/editform.tsx | 8 +- .../base/src/formbuilder/formselectors.ts | 8 +- .../src/formbuilder/objectform/baseform.tsx | 32 +-- .../objectform/fileselectorwidget.tsx | 20 +- .../objectform/layer/heatmapLayerForm.ts | 10 +- .../objectform/layer/hillshadeLayerForm.ts | 4 +- .../formbuilder/objectform/layer/layerform.ts | 6 +- .../objectform/layer/vectorlayerform.ts | 2 +- .../objectform/layer/webGlLayerForm.tsx | 2 +- .../process/dissolveProcessForm.tsx | 16 +- .../objectform/source/geojsonsource.ts | 8 +- .../objectform/source/geotiffsource.ts | 22 +- .../objectform/source/pathbasedsource.ts | 12 +- .../objectform/source/sourceform.ts | 2 +- .../objectform/source/tilesourceform.ts | 8 +- packages/base/src/gdal.ts | 4 +- packages/base/src/icons.ts | 34 +-- .../src/mainview/CollaboratorPointers.tsx | 8 +- .../base/src/mainview/FollowIndicator.tsx | 2 +- packages/base/src/mainview/TemporalSlider.tsx | 28 +- packages/base/src/mainview/mainView.tsx | 256 +++++++++--------- packages/base/src/mainview/mainviewmodel.ts | 8 +- packages/base/src/menus.ts | 14 +- .../base/src/panelview/annotationPanel.tsx | 6 +- .../components/filter-panel/Filter.tsx | 16 +- .../components/filter-panel/FilterRow.tsx | 10 +- .../identify-panel/IdentifyPanel.tsx | 20 +- .../base/src/panelview/components/layers.tsx | 38 +-- packages/base/src/panelview/leftpanel.tsx | 14 +- packages/base/src/panelview/model.ts | 2 +- .../base/src/panelview/objectproperties.tsx | 24 +- packages/base/src/panelview/rightpanel.tsx | 8 +- packages/base/src/processing.ts | 42 +-- packages/base/src/statusbar/StatusBar.tsx | 4 +- packages/base/src/toolbar/widget.tsx | 24 +- packages/base/src/tools.ts | 77 +++--- packages/base/src/types.ts | 2 +- packages/base/src/widget.ts | 14 +- packages/schema/src/doc.ts | 26 +- packages/schema/src/interfaces.ts | 12 +- packages/schema/src/model.ts | 52 ++-- packages/schema/src/token.ts | 8 +- python/jupytergis_core/src/externalcommand.ts | 2 +- python/jupytergis_core/src/factory.ts | 10 +- python/jupytergis_core/src/index.ts | 4 +- .../src/jgisplugin/modelfactory.ts | 6 +- .../jupytergis_core/src/jgisplugin/plugins.ts | 52 ++-- .../src/layerBrowserRegistry.ts | 2 +- python/jupytergis_core/src/plugin.ts | 22 +- python/jupytergis_lab/src/index.ts | 78 +++--- python/jupytergis_lab/src/notebookrenderer.ts | 34 +-- python/jupytergis_qgis/src/modelfactory.ts | 6 +- python/jupytergis_qgis/src/plugins.ts | 62 ++--- ui-tests/tests/annotations.spec.ts | 12 +- ui-tests/tests/contextmenu.spec.ts | 12 +- ui-tests/tests/export.spec.ts | 8 +- ui-tests/tests/filters.spec.ts | 8 +- ui-tests/tests/geojson-layers.spec.ts | 10 +- ui-tests/tests/layer-browser.spec.ts | 30 +- ui-tests/tests/left-panel.spec.ts | 24 +- ui-tests/tests/lite.spec.ts | 20 +- ui-tests/tests/notebook.spec.ts | 16 +- ui-tests/tests/ui.spec.ts | 6 +- 98 files changed, 918 insertions(+), 915 deletions(-) diff --git a/.prettierrc b/.prettierrc index d0824a69c..642dbe454 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "singleQuote": true, - "trailingComma": "none", + "trailingComma": "all", "arrowParens": "avoid", "endOfLine": "auto" } diff --git a/docs/contributor_guide/how-tos/commands/index.md b/docs/contributor_guide/how-tos/commands/index.md index 19f40e680..498809fea 100644 --- a/docs/contributor_guide/how-tos/commands/index.md +++ b/docs/contributor_guide/how-tos/commands/index.md @@ -24,7 +24,7 @@ is a behavior that can be triggered from a menu in the JupyterGIS UI. ```typescript const iconObject = { // ... - [CommandIDs.myNewCommand]: { iconClass: 'fas fa-question' } + [CommandIDs.myNewCommand]: { iconClass: 'fas fa-question' }, // ... }; ``` @@ -46,7 +46,7 @@ is a behavior that can be triggered from a menu in the JupyterGIS UI. execute: (): void => { // ... }, - ...icons.get(CommandIDs.myNewCommand) + ...icons.get(CommandIDs.myNewCommand), }); // ... @@ -80,8 +80,8 @@ is a behavior that can be triggered from a menu in the JupyterGIS UI. new CommandToolbarButton({ id: CommandIDs.myNewCommand, label: '', - commands: options.commands - }) + commands: options.commands, + }), ); // ... diff --git a/packages/base/src/annotations/components/Annotation.tsx b/packages/base/src/annotations/components/Annotation.tsx index 18b7bbdc0..fc6e32289 100644 --- a/packages/base/src/annotations/components/Annotation.tsx +++ b/packages/base/src/annotations/components/Annotation.tsx @@ -1,7 +1,7 @@ import { faTrash, faPaperPlane, - faArrowsToDot + faArrowsToDot, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IAnnotationModel, IJupyterGISModel } from '@jupytergis/schema'; @@ -23,11 +23,11 @@ const Annotation = ({ itemId, annotationModel, rightPanelModel, - children + children, }: IAnnotationProps) => { const [messageContent, setMessageContent] = useState(''); const [jgisModel, setJgisModel] = useState( - rightPanelModel?.jGISModel + rightPanelModel?.jGISModel, ); const annotation = annotationModel.getAnnotation(itemId); @@ -55,7 +55,7 @@ const Annotation = ({ const result = await showDialog({ title: 'Delete Annotation', body: 'Are you sure you want to delete this annotation?', - buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'Delete' })] + buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'Delete' })], }); if (result.button.accept) { diff --git a/packages/base/src/annotations/components/AnnotationFloater.tsx b/packages/base/src/annotations/components/AnnotationFloater.tsx index 816a0cd81..8c5deccb4 100644 --- a/packages/base/src/annotations/components/AnnotationFloater.tsx +++ b/packages/base/src/annotations/components/AnnotationFloater.tsx @@ -6,7 +6,7 @@ import Annotation, { IAnnotationProps } from './Annotation'; const AnnotationFloater = ({ itemId, - annotationModel: model + annotationModel: model, }: IAnnotationProps) => { const annotation = model.getAnnotation(itemId); const [isOpen, setIsOpen] = useState(annotation?.open); diff --git a/packages/base/src/annotations/components/Message.tsx b/packages/base/src/annotations/components/Message.tsx index 872f624d1..c5ecf71a3 100644 --- a/packages/base/src/annotations/components/Message.tsx +++ b/packages/base/src/annotations/components/Message.tsx @@ -28,13 +28,13 @@ export const Message = (props: IProps): JSX.Element => {
diff --git a/packages/base/src/annotations/model.ts b/packages/base/src/annotations/model.ts index 430f396ad..b9666a1f5 100644 --- a/packages/base/src/annotations/model.ts +++ b/packages/base/src/annotations/model.ts @@ -2,7 +2,7 @@ import { IAnnotation, IAnnotationContent, IAnnotationModel, - IJupyterGISModel + IJupyterGISModel, } from '@jupytergis/schema'; import { User } from '@jupyterlab/services'; import { ISignal, Signal } from '@lumino/signaling'; @@ -80,13 +80,13 @@ export class AnnotationModel implements IAnnotationModel { addContent(id: string, value: string): void { const newContent: IAnnotationContent = { value, - user: this._user + user: this._user, }; const currentAnnotation = this.getAnnotation(id); if (currentAnnotation) { const newAnnotation: IAnnotation = { ...currentAnnotation, - contents: [...currentAnnotation.contents, newContent] + contents: [...currentAnnotation.contents, newContent], }; this._model?.sharedModel.setMetadata(id, newAnnotation); diff --git a/packages/base/src/classificationModes.ts b/packages/base/src/classificationModes.ts index 478af0a32..2dcc24981 100644 --- a/packages/base/src/classificationModes.ts +++ b/packages/base/src/classificationModes.ts @@ -7,7 +7,7 @@ import { InterpolationType } from './dialogs/symbology/tiff_layer/types/SingleBa export namespace VectorClassifications { export const calculateQuantileBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { // q-th quantile of a data set: // value where q fraction of data is below and (1-q) fraction is above this value @@ -48,7 +48,7 @@ export namespace VectorClassifications { export const calculateEqualIntervalBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { const minimum = Math.min(...values); const maximum = Math.max(...values); @@ -87,10 +87,10 @@ export namespace VectorClassifications { const n = sample.length; const matrixOne = Array.from({ length: n + 1 }, () => - Array(nClasses + 1).fill(0) + Array(nClasses + 1).fill(0), ); const matrixTwo = Array.from({ length: n + 1 }, () => - Array(nClasses + 1).fill(Number.MAX_VALUE) + Array(nClasses + 1).fill(Number.MAX_VALUE), ); for (let i = 1; i <= nClasses; i++) { @@ -265,7 +265,7 @@ export namespace VectorClassifications { export const calculateLogarithmicBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { const minimum = Math.min(...values); const maximum = Math.max(...values); @@ -302,7 +302,7 @@ export namespace GeoTiffClassifications { nClasses: number, bandNumber: number, url: string, - colorRampType: string + colorRampType: string, ) => { const breaks: number[] = []; const isDiscrete = colorRampType === 'discrete'; @@ -364,7 +364,7 @@ export namespace GeoTiffClassifications { nClasses: number, minimumValue: number, maximumValue: number, - colorRampType: InterpolationType + colorRampType: InterpolationType, ) => { const min = minimumValue; const max = maximumValue; @@ -404,7 +404,7 @@ export namespace GeoTiffClassifications { nClasses: number, minimumValue: number, maximumValue: number, - colorRampType: InterpolationType + colorRampType: InterpolationType, ) => { const min = minimumValue; const max = maximumValue; diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 51fd0dee6..7e3f627cc 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -8,7 +8,7 @@ import { JgisCoordinates, LayerType, SelectionType, - SourceType + SourceType, } from '@jupytergis/schema'; import { JupyterFrontEnd } from '@jupyterlab/application'; import { showErrorMessage } from '@jupyterlab/apputils'; @@ -30,7 +30,7 @@ import keybindings from './keybindings.json'; import { getSingleSelectedLayer, selectedLayerIsOfType, - processSelectedLayer + processSelectedLayer, } from './processing'; import { getGeoJSONDataFromLayerSource, downloadFile } from './tools'; import { JupyterGISTracker } from './types'; @@ -53,7 +53,7 @@ function loadKeybindings(commands: CommandRegistry, keybindings: any[]) { commands.addKeyBinding({ command: binding.command, keys: binding.keys, - selector: binding.selector + selector: binding.selector, }); }); } @@ -68,7 +68,7 @@ export function addCommands( formSchemaRegistry: IJGISFormSchemaRegistry, layerBrowserRegistry: IJGISLayerBrowserRegistry, state: IStateDB, - completionProviderManager: ICompletionProviderManager | undefined + completionProviderManager: ICompletionProviderManager | undefined, ): void { const trans = translator.load('jupyterlab'); const { commands } = app; @@ -101,14 +101,14 @@ export function addCommands( 'VectorLayer', 'VectorTileLayer', 'WebGlLayer', - 'HeatmapLayer' + 'HeatmapLayer', ].includes(layer.type); return isValidLayer; }, execute: Private.createSymbologyDialog(tracker, state), - ...icons.get(CommandIDs.symbology) + ...icons.get(CommandIDs.symbology), }); commands.addCommand(CommandIDs.redo, { @@ -125,7 +125,7 @@ export function addCommands( return current.model.sharedModel.redo(); } }, - ...icons.get(CommandIDs.redo)?.icon + ...icons.get(CommandIDs.redo)?.icon, }); commands.addCommand(CommandIDs.undo, { @@ -142,7 +142,7 @@ export function addCommands( return current.model.sharedModel.undo(); } }, - ...icons.get(CommandIDs.undo) + ...icons.get(CommandIDs.undo), }); commands.addCommand(CommandIDs.identify, { @@ -160,7 +160,7 @@ export function addCommands( const canIdentify = [ 'VectorLayer', 'ShapefileLayer', - 'WebGlLayer' + 'WebGlLayer', ].includes(selectedLayer.type); const isIdentifying = current.model.isIdentifying; @@ -178,7 +178,7 @@ export function addCommands( return false; } return ['VectorLayer', 'ShapefileLayer', 'WebGlLayer'].includes( - selectedLayer.type + selectedLayer.type, ); }, execute: args => { @@ -205,7 +205,7 @@ export function addCommands( current.model.toggleIdentify(); commands.notifyCommandChanged(CommandIDs.identify); }, - ...icons.get(CommandIDs.identify) + ...icons.get(CommandIDs.identify), }); commands.addCommand(CommandIDs.temporalController, { @@ -254,7 +254,7 @@ export function addCommands( current.model.toggleTemporalController(); commands.notifyCommandChanged(CommandIDs.temporalController); }, - ...icons.get(CommandIDs.temporalController) + ...icons.get(CommandIDs.temporalController), }); /** @@ -270,9 +270,9 @@ export function addCommands( execute: Private.createLayerBrowser( tracker, layerBrowserRegistry, - formSchemaRegistry + formSchemaRegistry, ), - ...icons.get(CommandIDs.openLayerBrowser) + ...icons.get(CommandIDs.openLayerBrowser), }); /** @@ -293,13 +293,13 @@ export function addCommands( createSource: true, sourceData: { minZoom: 0, - maxZoom: 24 + maxZoom: 24, }, layerData: { name: 'Custom Raster Tile Layer' }, sourceType: 'RasterSource', - layerType: 'RasterLayer' + layerType: 'RasterLayer', }), - ...icons.get(CommandIDs.newRasterEntry) + ...icons.get(CommandIDs.newRasterEntry), }); commands.addCommand(CommandIDs.newVectorTileEntry, { @@ -318,9 +318,9 @@ export function addCommands( sourceData: { minZoom: 0, maxZoom: 24 }, layerData: { name: 'Custom Vector Tile Layer' }, sourceType: 'VectorTileSource', - layerType: 'VectorTileLayer' + layerType: 'VectorTileLayer', }), - ...icons.get(CommandIDs.newVectorTileEntry) + ...icons.get(CommandIDs.newVectorTileEntry), }); commands.addCommand(CommandIDs.buffer, { @@ -344,12 +344,12 @@ export function addCommands( 'SQLITE', '-sql', sqlQuery, - 'output.geojson' - ] + 'output.geojson', + ], }, - app + app, ); - } + }, }); commands.addCommand(CommandIDs.dissolve, { @@ -374,12 +374,12 @@ export function addCommands( 'SQLITE', '-sql', sqlQuery, - 'output.geojson' - ] + 'output.geojson', + ], }, - app + app, ); - } + }, }); commands.addCommand(CommandIDs.newGeoJSONEntry, { @@ -397,9 +397,9 @@ export function addCommands( createSource: true, layerData: { name: 'Custom GeoJSON Layer' }, sourceType: 'GeoJSONSource', - layerType: 'VectorLayer' + layerType: 'VectorLayer', }), - ...icons.get(CommandIDs.newGeoJSONEntry) + ...icons.get(CommandIDs.newGeoJSONEntry), }); commands.addCommand(CommandIDs.newHillshadeEntry, { @@ -417,9 +417,9 @@ export function addCommands( createSource: true, layerData: { name: 'Custom Hillshade Layer' }, sourceType: 'RasterDemSource', - layerType: 'HillshadeLayer' + layerType: 'HillshadeLayer', }), - ...icons.get(CommandIDs.newHillshadeEntry) + ...icons.get(CommandIDs.newHillshadeEntry), }); commands.addCommand(CommandIDs.newImageEntry, { @@ -442,14 +442,14 @@ export function addCommands( [-80.425, 46.437], [-71.516, 46.437], [-71.516, 37.936], - [-80.425, 37.936] - ] + [-80.425, 37.936], + ], }, layerData: { name: 'Custom Image Layer' }, sourceType: 'ImageSource', - layerType: 'ImageLayer' + layerType: 'ImageLayer', }), - ...icons.get(CommandIDs.newImageEntry) + ...icons.get(CommandIDs.newImageEntry), }); commands.addCommand(CommandIDs.newVideoEntry, { @@ -469,20 +469,20 @@ export function addCommands( name: 'Custom Video Source', urls: [ 'https://static-assets.mapbox.com/mapbox-gl-js/drone.mp4', - 'https://static-assets.mapbox.com/mapbox-gl-js/drone.webm' + 'https://static-assets.mapbox.com/mapbox-gl-js/drone.webm', ], coordinates: [ [-122.51596391201019, 37.56238816766053], [-122.51467645168304, 37.56410183312965], [-122.51309394836426, 37.563391708549425], - [-122.51423120498657, 37.56161849366671] - ] + [-122.51423120498657, 37.56161849366671], + ], }, layerData: { name: 'Custom Video Layer' }, sourceType: 'VideoSource', - layerType: 'RasterLayer' + layerType: 'RasterLayer', }), - ...icons.get(CommandIDs.newVideoEntry) + ...icons.get(CommandIDs.newVideoEntry), }); commands.addCommand(CommandIDs.newGeoTiffEntry, { @@ -500,13 +500,13 @@ export function addCommands( createSource: true, sourceData: { name: 'Custom GeoTiff Source', - urls: [{}] + urls: [{}], }, layerData: { name: 'Custom GeoTiff Layer' }, sourceType: 'GeoTiffSource', - layerType: 'WebGlLayer' + layerType: 'WebGlLayer', }), - ...icons.get(CommandIDs.newGeoTiffEntry) + ...icons.get(CommandIDs.newGeoTiffEntry), }); commands.addCommand(CommandIDs.newShapefileEntry, { @@ -525,9 +525,9 @@ export function addCommands( sourceData: { name: 'Custom Shapefile Source' }, layerData: { name: 'Custom Shapefile Layer' }, sourceType: 'ShapefileSource', - layerType: 'VectorLayer' + layerType: 'VectorLayer', }), - ...icons.get(CommandIDs.newShapefileEntry) + ...icons.get(CommandIDs.newShapefileEntry), }); /** @@ -544,7 +544,7 @@ export function addCommands( model?.sharedModel.updateLayer(layerId, layer); } }); - } + }, }); commands.addCommand(CommandIDs.removeLayer, { @@ -554,7 +554,7 @@ export function addCommands( Private.removeSelectedItems(model, 'layer', selection => { model?.removeLayer(selection); }); - } + }, }); commands.addCommand(CommandIDs.renameGroup, { @@ -564,7 +564,7 @@ export function addCommands( await Private.renameSelectedItem(model, 'group', (groupName, newName) => { model?.renameLayerGroup(groupName, newName); }); - } + }, }); commands.addCommand(CommandIDs.removeGroup, { @@ -574,7 +574,7 @@ export function addCommands( Private.removeSelectedItems(model, 'group', selection => { model?.removeLayerGroup(selection); }); - } + }, }); commands.addCommand(CommandIDs.moveLayersToGroup, { @@ -591,7 +591,7 @@ export function addCommands( } model.moveItemsToGroup(Object.keys(selectedLayers), groupName); - } + }, }); commands.addCommand(CommandIDs.moveLayerToNewGroup, { @@ -650,11 +650,11 @@ export function addCommands( const newLayerGroup: IJGISLayerGroup = { name: newName, - layers: layers + layers: layers, }; model.addNewLayerGroup(selectedLayers, newLayerGroup); - } + }, }); /** @@ -671,7 +671,7 @@ export function addCommands( model?.sharedModel.updateSource(sourceId, source); } }); - } + }, }); commands.addCommand(CommandIDs.removeSource, { @@ -684,11 +684,11 @@ export function addCommands( } else { showErrorMessage( 'Remove source error', - 'The source is used by a layer.' + 'The source is used by a layer.', ); } }); - } + }, }); // Console commands @@ -710,7 +710,7 @@ export function addCommands( execute: async () => { await Private.toggleConsole(tracker); commands.notifyCommandChanged(CommandIDs.toggleConsole); - } + }, }); commands.addCommand(CommandIDs.executeConsole, { label: trans.__('Execute console'), @@ -720,7 +720,7 @@ export function addCommands( ? tracker.currentWidget.model.sharedModel.editable : false; }, - execute: () => Private.executeConsole(tracker) + execute: () => Private.executeConsole(tracker), }); commands.addCommand(CommandIDs.removeConsole, { label: trans.__('Remove console'), @@ -730,7 +730,7 @@ export function addCommands( ? tracker.currentWidget.model.sharedModel.editable : false; }, - execute: () => Private.removeConsole(tracker) + execute: () => Private.removeConsole(tracker), }); commands.addCommand(CommandIDs.invokeCompleter, { @@ -749,7 +749,7 @@ export function addCommands( if (id) { return completionProviderManager.invoke(id); } - } + }, }); commands.addCommand(CommandIDs.selectCompleter, { @@ -768,7 +768,7 @@ export function addCommands( if (id) { return completionProviderManager.select(id); } - } + }, }); commands.addCommand(CommandIDs.zoomToLayer, { @@ -788,7 +788,7 @@ export function addCommands( const layerId = Object.keys(selectedItems)[0]; model.centerOnPosition(layerId); - } + }, }); commands.addCommand(CommandIDs.downloadGeoJSON, { @@ -808,7 +808,9 @@ export function addCommands( const sources = model.sharedModel.sources ?? {}; const exportSchema = { - ...(formSchemaRegistry.getSchemas().get('ExportGeoJSONSchema') as IDict) + ...(formSchemaRegistry + .getSchemas() + .get('ExportGeoJSONSchema') as IDict), }; const formValues = await new Promise(resolve => { @@ -822,7 +824,7 @@ export function addCommands( syncData: (props: IDict) => { resolve(props); dialog.dispose(); - } + }, }); dialog.launch(); @@ -844,9 +846,9 @@ export function addCommands( downloadFile( geojsonString, `${exportFileName}.geojson`, - 'application/geo+json' + 'application/geo+json', ); - } + }, }); commands.addCommand(CommandIDs.getGeolocation, { @@ -856,16 +858,16 @@ export function addCommands( const options = { enableHighAccuracy: true, timeout: 5000, - maximumAge: 0 + maximumAge: 0, }; const success = (pos: any) => { const location: Coordinate = fromLonLat([ pos.coords.longitude, - pos.coords.latitude + pos.coords.latitude, ]); const Jgislocation: JgisCoordinates = { x: location[0], - y: location[1] + y: location[1], }; if (viewModel) { viewModel.geolocationChanged.emit(Jgislocation); @@ -876,7 +878,7 @@ export function addCommands( }; navigator.geolocation.getCurrentPosition(success, error, options); }, - icon: targetWithCenterIcon + icon: targetWithCenterIcon, }); loadKeybindings(commands, keybindings); @@ -886,7 +888,7 @@ namespace Private { export function createLayerBrowser( tracker: JupyterGISTracker, layerBrowserRegistry: IJGISLayerBrowserRegistry, - formSchemaRegistry: IJGISFormSchemaRegistry + formSchemaRegistry: IJGISFormSchemaRegistry, ) { return async () => { const current = tracker.currentWidget; @@ -898,7 +900,7 @@ namespace Private { const dialog = new LayerBrowserWidget({ model: current.model, registry: layerBrowserRegistry.getRegistryLayers(), - formSchemaRegistry + formSchemaRegistry, }); await dialog.launch(); }; @@ -906,7 +908,7 @@ namespace Private { export function createSymbologyDialog( tracker: JupyterGISTracker, - state: IStateDB + state: IStateDB, ) { return async () => { const current = tracker.currentWidget; @@ -917,7 +919,7 @@ namespace Private { const dialog = new SymbologyWidget({ model: current.model, - state + state, }); await dialog.launch(); }; @@ -932,7 +934,7 @@ namespace Private { sourceData, layerData, sourceType, - layerType + layerType, }: ICreateEntry) { return async () => { const current = tracker.currentWidget; @@ -950,7 +952,7 @@ namespace Private { sourceType, layerData, layerType, - formSchemaRegistry + formSchemaRegistry, }); await dialog.launch(); }; @@ -959,7 +961,7 @@ namespace Private { export async function getUserInputForRename( text: HTMLElement, input: HTMLInputElement, - original: string + original: string, ): Promise { const parent = text.parentElement as HTMLElement; parent.replaceChild(input, text); @@ -992,7 +994,7 @@ namespace Private { export function removeSelectedItems( model: IJupyterGISModel | undefined, itemTypeToRemove: SelectionType, - removeFunction: (id: string) => void + removeFunction: (id: string) => void, ) { const selected = model?.localState?.selected?.value; @@ -1011,7 +1013,7 @@ namespace Private { export async function renameSelectedItem( model: IJupyterGISModel | undefined, itemType: SelectionType, - callback: (itemId: string, newName: string) => void + callback: (itemId: string, newName: string) => void, ) { const selectedItems = model?.localState?.selected.value; @@ -1051,7 +1053,7 @@ namespace Private { const newName = await Private.getUserInputForRename( node, edit, - originalName + originalName, ); if (!newName) { @@ -1082,7 +1084,7 @@ namespace Private { } export async function toggleConsole( - tracker: JupyterGISTracker + tracker: JupyterGISTracker, ): Promise { const current = tracker.currentWidget; diff --git a/packages/base/src/console/consoleview.ts b/packages/base/src/console/consoleview.ts index e530a96aa..8b627c306 100644 --- a/packages/base/src/console/consoleview.ts +++ b/packages/base/src/console/consoleview.ts @@ -6,7 +6,7 @@ import { closeIcon, CommandToolbarButton, expandIcon, - Toolbar + Toolbar, } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { BoxPanel, Widget } from '@lumino/widgets'; @@ -24,7 +24,7 @@ export class ConsoleView extends BoxPanel { contentFactory, mimeTypeService, rendermime: clonedRendermime, - kernelPreference: { name: 'python3', shutdownOnDispose: true } + kernelPreference: { name: 'python3', shutdownOnDispose: true }, }); this._consolePanel.console.node.dataset.jpInteractionMode = 'notebook'; this.addWidget(this._consolePanel); @@ -38,8 +38,8 @@ export class ConsoleView extends BoxPanel { label: '', icon: expandIcon, id: 'jupytergis:toggleConsole', - commands: options.commandRegistry - }) + commands: options.commandRegistry, + }), ); this._consolePanel.toolbar.addItem( 'close', @@ -47,8 +47,8 @@ export class ConsoleView extends BoxPanel { label: '', icon: closeIcon, id: 'jupytergis:removeConsole', - commands: options.commandRegistry - }) + commands: options.commandRegistry, + }), ); } diff --git a/packages/base/src/constants.ts b/packages/base/src/constants.ts index f39694c3c..9506c768c 100644 --- a/packages/base/src/constants.ts +++ b/packages/base/src/constants.ts @@ -7,7 +7,7 @@ import { infoIcon, moundIcon, rasterIcon, - vectorSquareIcon + vectorSquareIcon, } from './icons'; /** @@ -99,12 +99,12 @@ const iconObject = { [CommandIDs.newGeoTiffEntry]: { iconClass: 'fa fa-image' }, [CommandIDs.symbology]: { iconClass: 'fa fa-brush' }, [CommandIDs.identify]: { icon: infoIcon }, - [CommandIDs.temporalController]: { icon: clockIcon } + [CommandIDs.temporalController]: { icon: clockIcon }, }; /** * The registered icons */ export const icons = new Map( - Object.entries(iconObject) + Object.entries(iconObject), ); diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 284d7f93b..81d191cf9 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { BaseForm, - IBaseFormProps + IBaseFormProps, } from '@/src/formbuilder/objectform/baseform'; import { DissolveForm } from '@/src/formbuilder/objectform/process'; @@ -19,7 +19,7 @@ export interface IProcessingFormDialogOptions extends IBaseFormProps { syncSelectedPropField?: ( id: string | null, value: any, - parentType: 'dialog' | 'panel' + parentType: 'dialog' | 'panel', ) => void; model: IJupyterGISModel; processingType: 'Buffer' | 'Dissolve' | 'Export'; @@ -42,7 +42,7 @@ const ProcessingFormWrapper = (props: IProcessingFormWrapperProps) => { Promise.all([ props.okSignalPromise.promise, - props.formErrorSignalPromise?.promise + props.formErrorSignalPromise?.promise, ]).then(([ok, formChanged]) => { okSignal.current = ok; formErrorSignal.current = formChanged; @@ -85,17 +85,17 @@ export class ProcessingFormDialog extends Dialog { const layers = options.model.sharedModel.layers ?? {}; const layerOptions = Object.keys(layers).map(layerId => ({ value: layerId, - label: layers[layerId].name + label: layers[layerId].name, })); // Modify schema to include layer options and layer name field if (options.schema) { if (options.schema.properties?.inputLayer) { options.schema.properties.inputLayer.enum = layerOptions.map( - option => option.value + option => option.value, ); options.schema.properties.inputLayer.enumNames = layerOptions.map( - option => option.label + option => option.label, ); } @@ -103,7 +103,7 @@ export class ProcessingFormDialog extends Dialog { if (!options.schema.properties?.outputLayerName) { options.schema.properties.outputLayerName = { type: 'string', - title: 'outputLayerName' + title: 'outputLayerName', // default: '' }; } @@ -147,7 +147,7 @@ export class ProcessingFormDialog extends Dialog { super({ title: options.title, body, - buttons: [Dialog.cancelButton(), Dialog.okButton()] + buttons: [Dialog.cancelButton(), Dialog.okButton()], }); this.okSignal = new Signal(this); diff --git a/packages/base/src/dialogs/layerBrowserDialog.tsx b/packages/base/src/dialogs/layerBrowserDialog.tsx index 7d2b1ee1f..9539d9fe1 100644 --- a/packages/base/src/dialogs/layerBrowserDialog.tsx +++ b/packages/base/src/dialogs/layerBrowserDialog.tsx @@ -7,7 +7,7 @@ import { IJGISLayerDocChange, IJGISSource, IJupyterGISModel, - IRasterLayerGalleryEntry + IRasterLayerGalleryEntry, } from '@jupytergis/schema'; import { Dialog } from '@jupyterlab/apputils'; import { PromiseDelegate, UUID } from '@lumino/coreutils'; @@ -30,7 +30,7 @@ export const LayerBrowserComponent = ({ registry, formSchemaRegistry, okSignalPromise, - cancel + cancel, }: ILayerBrowserDialogProps) => { const [searchTerm, setSearchTerm] = useState(''); const [activeLayers, setActiveLayers] = useState([]); @@ -44,7 +44,7 @@ export const LayerBrowserComponent = ({ const providers = [...new Set(registry.map(item => item.source.provider))]; const filteredGallery = galleryWithCategory.filter(item => - item.name.toLowerCase().includes(searchTerm) + item.name.toLowerCase().includes(searchTerm), ); useEffect(() => { @@ -62,8 +62,8 @@ export const LayerBrowserComponent = ({ // The split is to get rid of the 'Layer' part of the name to match the names in the gallery setActiveLayers( Object.values(model.sharedModel.layers).map( - layer => layer.name.split(' ')[0] - ) + layer => layer.name.split(' ')[0], + ), ); }; @@ -81,7 +81,7 @@ export const LayerBrowserComponent = ({ const filteredGallery = sameAsOld ? registry : registry.filter(item => - item.source.provider?.includes(categoryTab.innerText) + item.source.provider?.includes(categoryTab.innerText), ); setGalleryWithCategory(filteredGallery); @@ -103,16 +103,16 @@ export const LayerBrowserComponent = ({ const sourceModel: IJGISSource = { type: 'RasterSource', name: tile.name, - parameters: tile.source + parameters: tile.source, }; const layerModel: IJGISLayer = { type: 'RasterLayer', parameters: { - source: sourceId + source: sourceId, }, visible: true, - name: tile.name + ' Layer' + name: tile.name + ' Layer', }; model.sharedModel.addSource(sourceId, sourceModel); @@ -135,13 +135,13 @@ export const LayerBrowserComponent = ({ layerType={'RasterLayer'} sourceType={'RasterSource'} layerData={{ - name: 'Custom Raster' + name: 'Custom Raster', }} sourceData={{ url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', maxZoom: 24, minZoom: 0, - attribution: '(C) OpenStreetMap contributors' + attribution: '(C) OpenStreetMap contributors', }} okSignalPromise={okSignalPromise} cancel={cancel} diff --git a/packages/base/src/dialogs/layerCreationFormDialog.tsx b/packages/base/src/dialogs/layerCreationFormDialog.tsx index af43b3c93..802b9e649 100644 --- a/packages/base/src/dialogs/layerCreationFormDialog.tsx +++ b/packages/base/src/dialogs/layerCreationFormDialog.tsx @@ -37,7 +37,7 @@ export const CreationFormWrapper = (props: ICreationFormWrapperProps) => { Promise.all([ props.okSignalPromise.promise, - props.formErrorSignalPromise?.promise + props.formErrorSignalPromise?.promise, ]).then(([ok, formChanged]) => { okSignal.current = ok; formErrorSignal.current = formChanged; @@ -102,7 +102,7 @@ export class LayerCreationFormDialog extends Dialog { super({ title: options.title, body, - buttons: [Dialog.cancelButton(), Dialog.okButton()] + buttons: [Dialog.cancelButton(), Dialog.okButton()], }); this.okSignal = new Signal(this); diff --git a/packages/base/src/dialogs/symbology/classificationModes.ts b/packages/base/src/dialogs/symbology/classificationModes.ts index f19dd67ec..b4ab85989 100644 --- a/packages/base/src/dialogs/symbology/classificationModes.ts +++ b/packages/base/src/dialogs/symbology/classificationModes.ts @@ -7,7 +7,7 @@ import { InterpolationType } from './tiff_layer/types/SingleBandPseudoColor'; export namespace VectorClassifications { export const calculateQuantileBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { // q-th quantile of a data set: // value where q fraction of data is below and (1-q) fraction is above this value @@ -48,7 +48,7 @@ export namespace VectorClassifications { export const calculateEqualIntervalBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { const minimum = Math.min(...values); const maximum = Math.max(...values); @@ -87,10 +87,10 @@ export namespace VectorClassifications { const n = sample.length; const matrixOne = Array.from({ length: n + 1 }, () => - Array(nClasses + 1).fill(0) + Array(nClasses + 1).fill(0), ); const matrixTwo = Array.from({ length: n + 1 }, () => - Array(nClasses + 1).fill(Number.MAX_VALUE) + Array(nClasses + 1).fill(Number.MAX_VALUE), ); for (let i = 1; i <= nClasses; i++) { @@ -265,7 +265,7 @@ export namespace VectorClassifications { export const calculateLogarithmicBreaks = ( values: number[], - nClasses: number + nClasses: number, ) => { const minimum = Math.min(...values); const maximum = Math.max(...values); @@ -302,7 +302,7 @@ export namespace GeoTiffClassifications { nClasses: number, bandNumber: number, url: string, - colorRampType: string + colorRampType: string, ) => { const breaks: number[] = []; const isDiscrete = colorRampType === 'discrete'; @@ -364,7 +364,7 @@ export namespace GeoTiffClassifications { nClasses: number, minimumValue: number, maximumValue: number, - colorRampType: InterpolationType + colorRampType: InterpolationType, ) => { const min = minimumValue; const max = maximumValue; @@ -404,7 +404,7 @@ export namespace GeoTiffClassifications { nClasses: number, minimumValue: number, maximumValue: number, - colorRampType: InterpolationType + colorRampType: InterpolationType, ) => { const min = minimumValue; const max = maximumValue; diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx index 58fe48c35..fe153b159 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/CanvasSelectComponent.tsx @@ -16,7 +16,7 @@ interface ICanvasSelectComponentProps { const CanvasSelectComponent = ({ selectedRamp, - setSelected + setSelected, }: ICanvasSelectComponentProps) => { const colorRampNames = [ 'jet', @@ -60,7 +60,7 @@ const CanvasSelectComponent = ({ 'temperature', 'turbidity', 'velocity-blue', - 'velocity-green' + 'velocity-green', // 'cubehelix' 16 steps min ]; @@ -75,7 +75,7 @@ const CanvasSelectComponent = ({ const colorRamp = colormap({ colormap: name, nshades: 255, - format: 'rgbaString' + format: 'rgbaString', }); const colorMap = { name: name, colors: colorRamp }; colorMapList.push(colorMap); diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx index 78e16c2ff..4095e03b1 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx @@ -14,7 +14,7 @@ interface IColorRampProps { selectedMode: string, numberOfShades: string, selectedRamp: string, - setIsLoading: (isLoading: boolean) => void + setIsLoading: (isLoading: boolean) => void, ) => void; showModeRow: boolean; } @@ -29,7 +29,7 @@ const ColorRamp = ({ layerParams, modeOptions, classifyFunc, - showModeRow + showModeRow, }: IColorRampProps) => { const [selectedRamp, setSelectedRamp] = useState(''); const [selectedMode, setSelectedMode] = useState(''); @@ -81,7 +81,7 @@ const ColorRamp = ({ selectedMode, numberOfShades, selectedRamp, - setIsLoading + setIsLoading, ) } > diff --git a/packages/base/src/dialogs/symbology/components/color_ramp/ModeSelectRow.tsx b/packages/base/src/dialogs/symbology/components/color_ramp/ModeSelectRow.tsx index 354ba6f41..1f1274c91 100644 --- a/packages/base/src/dialogs/symbology/components/color_ramp/ModeSelectRow.tsx +++ b/packages/base/src/dialogs/symbology/components/color_ramp/ModeSelectRow.tsx @@ -11,7 +11,7 @@ const ModeSelectRow = ({ setNumberOfShades, selectedMode, setSelectedMode, - modeOptions + modeOptions, }: IModeSelectRowProps) => { return (
diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx index 0418adb19..9a14ae998 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopContainer.tsx @@ -13,15 +13,15 @@ interface IStopContainerProps { const StopContainer = ({ selectedMethod, stopRows, - setStopRows + setStopRows, }: IStopContainerProps) => { const addStopRow = () => { setStopRows([ { stop: 0, - output: [0, 0, 0, 1] + output: [0, 0, 0, 1], }, - ...stopRows + ...stopRows, ]); }; diff --git a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx index 326885e9d..ecc7270ab 100644 --- a/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx +++ b/packages/base/src/dialogs/symbology/components/color_stops/StopRow.tsx @@ -12,7 +12,7 @@ const StopRow = ({ stopRows, setStopRows, deleteRow, - useNumber + useNumber, }: { index: number; value: number; @@ -56,7 +56,7 @@ const StopRow = ({ parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16), - 1 // TODO: Make alpha customizable? + 1, // TODO: Make alpha customizable? ]; return rgbValues; diff --git a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts index 3e9773c26..fd1074eb3 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetBandInfo.ts @@ -52,7 +52,7 @@ const useGetBandInfo = (model: IJupyterGISModel, layer: IJGISLayer) => { const preloadedFile = await loadFile({ filepath: sourceInfo.url, type: 'GeoTiffSource', - model + model, }); if (!preloadedFile.file) { @@ -72,8 +72,8 @@ const useGetBandInfo = (model: IJupyterGISModel, layer: IJGISLayer) => { band: i, stats: { minimum: sourceInfo.min ?? 0, - maximum: sourceInfo.max ?? 100 - } + maximum: sourceInfo.max ?? 100, + }, }); } diff --git a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts index c56c472ce..b404b4cd0 100644 --- a/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts +++ b/packages/base/src/dialogs/symbology/hooks/useGetProperties.ts @@ -18,7 +18,7 @@ interface IUseGetPropertiesResult { export const useGetProperties = ({ layerId, - model + model, }: IUseGetPropertiesProps): IUseGetPropertiesResult => { const [featureProperties, setFeatureProperties] = useState({}); const [isLoading, setIsLoading] = useState(true); @@ -40,7 +40,7 @@ export const useGetProperties = ({ const data = await loadFile({ filepath: source.parameters?.path, type: 'GeoJSONSource', - model: model + model: model, }); if (!data) { diff --git a/packages/base/src/dialogs/symbology/symbologyDialog.tsx b/packages/base/src/dialogs/symbology/symbologyDialog.tsx index a4bf7cba4..f3c817802 100644 --- a/packages/base/src/dialogs/symbology/symbologyDialog.tsx +++ b/packages/base/src/dialogs/symbology/symbologyDialog.tsx @@ -30,7 +30,7 @@ const SymbologyDialog = ({ model, state, okSignalPromise, - cancel + cancel, }: ISymbologyDialogProps) => { const [selectedLayer, setSelectedLayer] = useState(null); const [componentToRender, setComponentToRender] = useState(null); diff --git a/packages/base/src/dialogs/symbology/symbologyUtils.ts b/packages/base/src/dialogs/symbology/symbologyUtils.ts index b42a2894c..0b0b8e289 100644 --- a/packages/base/src/dialogs/symbology/symbologyUtils.ts +++ b/packages/base/src/dialogs/symbology/symbologyUtils.ts @@ -37,7 +37,7 @@ export namespace VectorUtils { if (!seenPairs.has(pairKey)) { valueColorPairs.push({ stop: color[key][i], - output: color[key][i + 1] + output: color[key][i + 1], }); seenPairs.add(pairKey); } @@ -50,7 +50,7 @@ export namespace VectorUtils { if (!seenPairs.has(pairKey)) { valueColorPairs.push({ stop: color[key][i][2], - output: color[key][i + 1] + output: color[key][i + 1], }); seenPairs.add(pairKey); } @@ -79,7 +79,7 @@ export namespace VectorUtils { for (let i = 3; i < color['circle-radius'].length; i += 2) { const obj: IStopRow = { stop: color['circle-radius'][i], - output: color['circle-radius'][i + 1] + output: color['circle-radius'][i + 1], }; stopOutputPairs.push(obj); } @@ -92,12 +92,12 @@ export namespace Utils { export const getValueColorPairs = ( stops: number[], selectedRamp: string, - nClasses: number + nClasses: number, ) => { let colorMap = colormap({ colormap: selectedRamp, nshades: nClasses > 9 ? nClasses : 9, - format: 'rgba' + format: 'rgba', }); const valueColorPairs: IStopRow[] = []; @@ -112,7 +112,7 @@ export namespace Utils { // Get the last n/2 elements from the second array const secondPart = colorMap.slice( - colorMap.length - (stops.length - firstPart.length) + colorMap.length - (stops.length - firstPart.length), ); // Create the new array by combining the first and last parts diff --git a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx index cb75d3ae7..256f9a7cb 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/TiffRendering.tsx @@ -9,7 +9,7 @@ const TiffRendering = ({ state, okSignalPromise, cancel, - layerId + layerId, }: ISymbologyDialogProps) => { const renderTypes = ['Singleband Pseudocolor', 'Multiband Color']; const [selectedRenderType, setSelectedRenderType] = useState(); diff --git a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx index d996ab852..d75080839 100644 --- a/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx +++ b/packages/base/src/dialogs/symbology/tiff_layer/components/BandRow.tsx @@ -29,7 +29,7 @@ const BandRow = ({ bandRows, setSelectedBand, setBandRows, - isMultibandColor + isMultibandColor, }: IBandRowProps) => { const [minValue, setMinValue] = useState(bandRow?.stats.minimum); const [maxValue, setMaxValue] = useState(bandRow?.stats.maximum); @@ -96,7 +96,7 @@ const BandRow = ({ style={{ display: 'flex', justifyContent: 'space-between', - width: '50%' + width: '50%', }} >
)} @@ -368,7 +368,7 @@ function LayerComponent(props: ILayerProps): JSX.Element { const [id, setId] = useState(''); const [selected, setSelected] = useState( // TODO Support multi-selection as `model?.jGISModel?.localState?.selected.value` does - isSelected(layerId, gisModel) + isSelected(layerId, gisModel), ); const name = layer.name; @@ -382,7 +382,7 @@ function LayerComponent(props: ILayerProps): JSX.Element { useEffect(() => { const onClientSharedStateChanged = ( sender: IJupyterGISModel, - clients: Map + clients: Map, ) => { // TODO Support follow mode and remoteUser state setSelected(isSelected(layerId, gisModel)); @@ -461,7 +461,7 @@ namespace Private { export const dragInfo: IDragInfo = { draggedElement: null, dragOverElement: null, - dragOverPosition: null + dragOverPosition: null, }; export const onDragStart = (e: React.DragEvent) => { @@ -474,7 +474,7 @@ namespace Private { const { clientY } = e; let target = (e.target as HTMLElement).closest( - `.${LAYER_GROUP_HEADER_CLASS}, .${LAYER_ITEM_CLASS}` + `.${LAYER_GROUP_HEADER_CLASS}, .${LAYER_ITEM_CLASS}`, ) as HTMLDivElement; if (!target) { diff --git a/packages/base/src/panelview/leftpanel.tsx b/packages/base/src/panelview/leftpanel.tsx index 3b9f1775d..57d7564db 100644 --- a/packages/base/src/panelview/leftpanel.tsx +++ b/packages/base/src/panelview/leftpanel.tsx @@ -2,7 +2,7 @@ import { IJupyterGISTracker, ISelection, JupyterGISDoc, - SelectionType + SelectionType, } from '@jupytergis/schema'; import { IStateDB } from '@jupyterlab/statedb'; import { SidePanel } from '@jupyterlab/ui-components'; @@ -52,7 +52,7 @@ export class LeftPanelWidget extends SidePanel { const layerTree = new LayersPanel({ model: this._model, state: this._state, - onSelect: this._onSelect + onSelect: this._onSelect, }); layerTree.title.caption = 'Layer tree'; layerTree.title.label = 'Layers'; @@ -60,7 +60,7 @@ export class LeftPanelWidget extends SidePanel { const filterPanel = new FilterPanel({ model: this._model, - tracker: options.tracker + tracker: options.tracker, }); filterPanel.title.caption = 'Filters'; @@ -121,7 +121,7 @@ export class LeftPanelWidget extends SidePanel { type, item, nodeId, - event + event, }: ILeftPanelClickHandlerParams) => { if (!this._model || !nodeId) { return; @@ -158,7 +158,7 @@ export class LeftPanelWidget extends SidePanel { if (nodeId) { // Check if new selection is the same type as previous selections const isSelectedSameType = Object.values(selectedValue).some( - selection => selection.type === type + selection => selection.type === type, ); if (!isSelectedSameType) { @@ -170,7 +170,7 @@ export class LeftPanelWidget extends SidePanel { // If types are the same add the selection const updatedSelectedValue = { ...selectedValue, - [item]: { type, selectedNodeId: nodeId } + [item]: { type, selectedNodeId: nodeId }, }; this._lastSelectedNodeId = nodeId; @@ -185,7 +185,7 @@ export class LeftPanelWidget extends SidePanel { if (item && nodeId) { selection[item] = { type, - selectedNodeId: nodeId + selectedNodeId: nodeId, }; this._lastSelectedNodeId = nodeId; } diff --git a/packages/base/src/panelview/model.ts b/packages/base/src/panelview/model.ts index 27d34613f..03f8ff96d 100644 --- a/packages/base/src/panelview/model.ts +++ b/packages/base/src/panelview/model.ts @@ -2,7 +2,7 @@ import { IJupyterGISDoc, IJupyterGISModel, IJupyterGISTracker, - IJupyterGISWidget + IJupyterGISWidget, } from '@jupytergis/schema'; import { ISignal } from '@lumino/signaling'; diff --git a/packages/base/src/panelview/objectproperties.tsx b/packages/base/src/panelview/objectproperties.tsx index 5f97b8c66..86f57d73e 100644 --- a/packages/base/src/panelview/objectproperties.tsx +++ b/packages/base/src/panelview/objectproperties.tsx @@ -2,7 +2,7 @@ import { IJGISFormSchemaRegistry, IJupyterGISClientState, IJupyterGISModel, - IJupyterGISTracker + IJupyterGISTracker, } from '@jupytergis/schema'; import { ReactWidget } from '@jupyterlab/apputils'; import { PanelWithToolbar } from '@jupyterlab/ui-components'; @@ -22,7 +22,7 @@ export class ObjectProperties extends PanelWithToolbar { cpModel={params.controlPanelModel} tracker={params.tracker} formSchemaRegistry={params.formSchemaRegistry} - /> + />, ); this.addWidget(body); this.addClass('jGIS-sidebar-propertiespanel'); @@ -49,14 +49,14 @@ class ObjectPropertiesReact extends React.Component { this.state = { model: props.tracker.currentWidget?.model, clientId: null, - id: uuid() + id: uuid(), }; this.props.cpModel.jGISModel?.sharedLayersChanged.connect( - this._sharedJGISModelChanged + this._sharedJGISModelChanged, ); this.props.cpModel.jGISModel?.sharedSourcesChanged.connect( - this._sharedJGISModelChanged + this._sharedJGISModelChanged, ); this.props.cpModel.documentChanged.connect((_, changed) => { if (changed) { @@ -65,21 +65,21 @@ class ObjectPropertiesReact extends React.Component { changed.model.sharedLayersChanged.connect(this._sharedJGISModelChanged); changed.model.sharedSourcesChanged.connect( - this._sharedJGISModelChanged + this._sharedJGISModelChanged, ); changed.model.clientStateChanged.connect( - this._onClientSharedStateChanged + this._onClientSharedStateChanged, ); this.setState(old => ({ ...old, model: changed.model, filePath: changed.model.filePath, - clientId: changed.model.getClientId() + clientId: changed.model.getClientId(), })); } else { this.setState({ model: undefined, - selectedObject: undefined + selectedObject: undefined, }); } }); @@ -91,7 +91,7 @@ class ObjectPropertiesReact extends React.Component { private _onClientSharedStateChanged = ( sender: IJupyterGISModel, - clients: Map + clients: Map, ): void => { let newState: IJupyterGISClientState | undefined; const clientId = this.state.clientId; @@ -112,7 +112,7 @@ class ObjectPropertiesReact extends React.Component { if (selection === undefined || selectedObjectIds.length !== 1) { this.setState(old => ({ ...old, - selectedObject: undefined + selectedObject: undefined, })); return; } @@ -121,7 +121,7 @@ class ObjectPropertiesReact extends React.Component { if (selectedObject !== this.state.selectedObject) { this.setState(old => ({ ...old, - selectedObject + selectedObject, })); } } diff --git a/packages/base/src/panelview/rightpanel.tsx b/packages/base/src/panelview/rightpanel.tsx index f95b3da01..758e9a023 100644 --- a/packages/base/src/panelview/rightpanel.tsx +++ b/packages/base/src/panelview/rightpanel.tsx @@ -3,7 +3,7 @@ import { IJGISFormSchemaRegistry, IJupyterGISModel, IJupyterGISTracker, - JupyterGISDoc + JupyterGISDoc, } from '@jupytergis/schema'; import { SidePanel } from '@jupyterlab/ui-components'; @@ -28,20 +28,20 @@ export class RightPanelWidget extends SidePanel { const properties = new ObjectProperties({ controlPanelModel: this._model, formSchemaRegistry: options.formSchemaRegistry, - tracker: options.tracker + tracker: options.tracker, }); this.addWidget(properties); const annotations = new Annotations({ rightPanelModel: this._model, - annotationModel: this._annotationModel + annotationModel: this._annotationModel, }); this.addWidget(annotations); const identifyPanel = new IdentifyPanel({ model: this._model, - tracker: options.tracker + tracker: options.tracker, }); identifyPanel.title.caption = 'Identify'; identifyPanel.title.label = 'Identify'; diff --git a/packages/base/src/processing.ts b/packages/base/src/processing.ts index 3baf78c0f..c5d693eb6 100644 --- a/packages/base/src/processing.ts +++ b/packages/base/src/processing.ts @@ -4,7 +4,7 @@ import { IJGISSource, IJupyterGISModel, IJGISFormSchemaRegistry, - LayerType + LayerType, } from '@jupytergis/schema'; import { JupyterFrontEnd } from '@jupyterlab/application'; import { UUID } from '@lumino/coreutils'; @@ -18,7 +18,7 @@ import { JupyterGISTracker } from './types'; * Get the currently selected layer from the shared model. Returns null if there is no selection or multiple layer is selected. */ export function getSingleSelectedLayer( - tracker: JupyterGISTracker + tracker: JupyterGISTracker, ): IJGISLayer | null { const model = tracker.currentWidget?.model as IJupyterGISModel; if (!model) { @@ -49,7 +49,7 @@ export function getSingleSelectedLayer( */ export function selectedLayerIsOfType( allowedTypes: LayerType[], - tracker: JupyterGISTracker + tracker: JupyterGISTracker, ): boolean { const selectedLayer = getSingleSelectedLayer(tracker); return selectedLayer ? allowedTypes.includes(selectedLayer.type) : false; @@ -61,7 +61,7 @@ export function selectedLayerIsOfType( export async function getLayerGeoJSON( layer: IJGISLayer, sources: IDict, - model: IJupyterGISModel + model: IJupyterGISModel, ): Promise { if (!layer.parameters || !layer.parameters.source) { console.error('Selected layer does not have a valid source.'); @@ -71,7 +71,7 @@ export async function getLayerGeoJSON( const source = sources[layer.parameters.source]; if (!source || !source.parameters) { console.error( - `Source with ID ${layer.parameters.source} not found or missing path.` + `Source with ID ${layer.parameters.source} not found or missing path.`, ); return null; } @@ -97,7 +97,7 @@ export async function processSelectedLayer( gdalFunction: GdalFunctions; options: (sqlQuery: string) => string[]; }, - app: JupyterFrontEnd + app: JupyterFrontEnd, ) { const selected = getSingleSelectedLayer(tracker); if (!selected || !tracker.currentWidget) { @@ -113,10 +113,10 @@ export async function processSelectedLayer( } const schema = { - ...(formSchemaRegistry.getSchemas().get(processingType) as IDict) + ...(formSchemaRegistry.getSchemas().get(processingType) as IDict), }; const selectedLayerId = Object.keys( - model?.sharedModel.awareness.getLocalState()?.selected?.value || {} + model?.sharedModel.awareness.getLocalState()?.selected?.value || {}, )[0]; // Open ProcessingFormDialog @@ -127,14 +127,14 @@ export async function processSelectedLayer( model, sourceData: { inputLayer: selectedLayerId, - outputLayerName: selected.name + outputLayerName: selected.name, }, formContext: 'create', processingType, syncData: (props: IDict) => { resolve(props); dialog.dispose(); - } + }, }); dialog.launch(); }); @@ -159,10 +159,10 @@ export async function processSelectedLayer( const embedOutputLayer = formValues.embedOutputLayer; const fileBlob = new Blob([geojsonString], { - type: 'application/geo+json' + type: 'application/geo+json', }); const geoFile = new File([fileBlob], 'data.geojson', { - type: 'application/geo+json' + type: 'application/geo+json', }); const Gdal = await getGdal(); @@ -182,7 +182,7 @@ export async function processSelectedLayer( processingType, embedOutputLayer, tracker, - app + app, ); } @@ -195,12 +195,12 @@ export async function executeSQLProcessing( processingType: 'Buffer' | 'Dissolve', embedOutputLayer: boolean, tracker: JupyterGISTracker, - app: JupyterFrontEnd + app: JupyterFrontEnd, ) { const geoFile = new File( [new Blob([geojsonString], { type: 'application/geo+json' })], 'data.geojson', - { type: 'application/geo+json' } + { type: 'application/geo+json' }, ); const Gdal = await getGdal(); @@ -229,7 +229,7 @@ export async function executeSQLProcessing( await app.serviceManager.contents.save(savePath, { type: 'file', format: 'text', - content: processedGeoJSONString + content: processedGeoJSONString, }); const newSourceId = UUID.uuid4(); @@ -237,15 +237,15 @@ export async function executeSQLProcessing( type: 'GeoJSONSource', name: outputFileName, parameters: { - path: outputFileName - } + path: outputFileName, + }, }; const layerModel: IJGISLayer = { type: 'VectorLayer', parameters: { source: newSourceId }, visible: true, - name: outputFileName + name: outputFileName, }; model.sharedModel.addSource(newSourceId, sourceModel); @@ -258,14 +258,14 @@ export async function executeSQLProcessing( const sourceModel: IJGISSource = { type: 'GeoJSONSource', name: `${layerNamePrefix} ${processingType.charAt(0).toUpperCase() + processingType.slice(1)}`, - parameters: { data: processedGeoJSON } + parameters: { data: processedGeoJSON }, }; const layerModel: IJGISLayer = { type: 'VectorLayer', parameters: { source: newSourceId }, visible: true, - name: `${layerNamePrefix} ${processingType.charAt(0).toUpperCase() + processingType.slice(1)}` + name: `${layerNamePrefix} ${processingType.charAt(0).toUpperCase() + processingType.slice(1)}`, }; model.sharedModel.addSource(newSourceId, sourceModel); diff --git a/packages/base/src/statusbar/StatusBar.tsx b/packages/base/src/statusbar/StatusBar.tsx index 9c156800a..2708763bb 100644 --- a/packages/base/src/statusbar/StatusBar.tsx +++ b/packages/base/src/statusbar/StatusBar.tsx @@ -1,7 +1,7 @@ import { faGlobe, faLocationDot, - faRuler + faRuler, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Progress } from '@jupyter/react-components'; @@ -20,7 +20,7 @@ const StatusBar = ({ jgisModel, loading, projection, - scale + scale, }: IStatusBarProps) => { const [coords, setCoords] = useState({ x: 0, y: 0 }); diff --git a/packages/base/src/toolbar/widget.tsx b/packages/base/src/toolbar/widget.tsx index 3615b6194..7c03cfa17 100644 --- a/packages/base/src/toolbar/widget.tsx +++ b/packages/base/src/toolbar/widget.tsx @@ -9,7 +9,7 @@ import { ToolbarButton, addIcon, redoIcon, - undoIcon + undoIcon, } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { Widget } from '@lumino/widgets'; @@ -43,7 +43,7 @@ export class ToolbarWidget extends ReactiveToolbar { id: CommandIDs.undo, label: '', icon: undoIcon, - commands: options.commands + commands: options.commands, }); this.addItem('undo', undoButton); @@ -53,7 +53,7 @@ export class ToolbarWidget extends ReactiveToolbar { id: CommandIDs.redo, label: '', icon: redoIcon, - commands: options.commands + commands: options.commands, }); this.addItem('redo', redoButton); @@ -63,7 +63,7 @@ export class ToolbarWidget extends ReactiveToolbar { id: CommandIDs.toggleConsole, commands: options.commands, label: '', - icon: terminalToolbarIcon + icon: terminalToolbarIcon, }); this.addItem('Toggle console', toggleConsoleButton); toggleConsoleButton.node.dataset.testid = 'toggle-console-button'; @@ -73,7 +73,7 @@ export class ToolbarWidget extends ReactiveToolbar { const openLayersBrowserButton = new CommandToolbarButton({ id: CommandIDs.openLayerBrowser, label: '', - commands: options.commands + commands: options.commands, }); this.addItem('openLayerBrowser', openLayersBrowserButton); openLayersBrowserButton.node.dataset.testid = 'open-layers-browser'; @@ -83,11 +83,11 @@ export class ToolbarWidget extends ReactiveToolbar { NewSubMenu.addItem({ type: 'submenu', - submenu: rasterSubMenu(options.commands) + submenu: rasterSubMenu(options.commands), }); NewSubMenu.addItem({ type: 'submenu', - submenu: vectorSubMenu(options.commands) + submenu: vectorSubMenu(options.commands), }); const NewEntryButton = new ToolbarButton({ @@ -101,7 +101,7 @@ export class ToolbarWidget extends ReactiveToolbar { const bbox = NewEntryButton.node.getBoundingClientRect(); NewSubMenu.open(bbox.x, bbox.bottom); - } + }, }); NewEntryButton.node.dataset.testid = 'new-entry-button'; @@ -112,7 +112,7 @@ export class ToolbarWidget extends ReactiveToolbar { const geolocationButton = new CommandToolbarButton({ id: CommandIDs.getGeolocation, commands: options.commands, - label: '' + label: '', }); this.addItem('Geolocation', geolocationButton); geolocationButton.node.dataset.testid = 'geolocation-button'; @@ -120,7 +120,7 @@ export class ToolbarWidget extends ReactiveToolbar { const identifyButton = new CommandToolbarButton({ id: CommandIDs.identify, label: '', - commands: options.commands + commands: options.commands, }); this.addItem('identify', identifyButton); @@ -129,7 +129,7 @@ export class ToolbarWidget extends ReactiveToolbar { const temporalControllerButton = new CommandToolbarButton({ id: CommandIDs.temporalController, label: '', - commands: options.commands + commands: options.commands, }); this.addItem('temporalController', temporalControllerButton); temporalControllerButton.node.dataset.testid = @@ -140,7 +140,7 @@ export class ToolbarWidget extends ReactiveToolbar { // Users this.addItem( 'users', - ReactWidget.create() + ReactWidget.create(), ); } } diff --git a/packages/base/src/tools.ts b/packages/base/src/tools.ts index e4a3a7977..dde6dd58f 100644 --- a/packages/base/src/tools.ts +++ b/packages/base/src/tools.ts @@ -5,7 +5,7 @@ import { IJGISSource, IJupyterGISModel, IRasterLayerGalleryEntry, - SourceType + SourceType, } from '@jupytergis/schema'; import { showErrorMessage } from '@jupyterlab/apputils'; import { PathExt, URLExt } from '@jupyterlab/coreutils'; @@ -20,7 +20,7 @@ import { getGdal } from '@/src/gdal'; export const debounce = ( func: CallableFunction, - timeout = 100 + timeout = 100, ): CallableFunction => { let timeoutId: number; return (...args: any[]) => { @@ -33,7 +33,7 @@ export const debounce = ( export function throttle void>( callback: T, - delay = 100 + delay = 100, ): T { let last: number; let timer: any; @@ -54,7 +54,7 @@ export function throttle void>( export function getElementFromProperty( filePath?: string | null, - prop?: string | null + prop?: string | null, ): HTMLElement | undefined | null { if (!filePath || !prop) { return; @@ -92,7 +92,7 @@ export function getCSSVariableColor(name: string): string { */ export async function requestAPI( endPoint = '', - init: RequestInit = {} + init: RequestInit = {}, ): Promise { // Make request to Jupyter API const settings = ServerConnection.makeSettings(); @@ -139,7 +139,7 @@ export function deepCopy>(value: T): T { * @param layerBrowserRegistry Registry to add layers to */ export function createDefaultLayerRegistry( - layerBrowserRegistry: IJGISLayerBrowserRegistry + layerBrowserRegistry: IJGISLayerBrowserRegistry, ): void { const RASTER_THUMBNAILS: { [key: string]: string } = {}; @@ -156,7 +156,7 @@ export function createDefaultLayerRegistry( const context = require.context( '../rasterlayer_gallery', false, - /\.(png|jpe?g|gif|svg)$/ + /\.(png|jpe?g|gif|svg)$/, ); importAll(context); @@ -171,7 +171,7 @@ export function createDefaultLayerRegistry( const tile = convertToRegistryEntry( xyzprovider[mapName]['name'], xyzprovider[mapName], - entry + entry, ); layerBrowserRegistry.addRegistryLayer(tile); @@ -191,7 +191,7 @@ export function createDefaultLayerRegistry( function convertToRegistryEntry( entry: string, xyzprovider: { [x: string]: any }, - provider?: string | undefined + provider?: string | undefined, ): IRasterLayerGalleryEntry { const urlParameters: any = {}; if (xyzprovider.time) { @@ -216,8 +216,8 @@ export function createDefaultLayerRegistry( maxZoom: xyzprovider['max_zoom'] || 24, attribution: xyzprovider['attribution'] || '', provider: provider ?? entry, - urlParameters - } + urlParameters, + }, }; } } @@ -229,7 +229,7 @@ function getTileCoordinates(latDeg: number, lonDeg: number, zoom: number) { const n = 1 << zoom; const xTile = Math.floor(((lonDeg + 180.0) / 360.0) * n); const yTile = Math.floor( - (n * (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2 + (n * (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2, ); // Check if either xTile or yTile is NaN @@ -243,7 +243,7 @@ function getTileCoordinates(latDeg: number, lonDeg: number, zoom: number) { export async function getLayerTileInfo( tileUrl: string, mapOptions: Pick, - urlParameters?: IDict + urlParameters?: IDict, ): Promise { // If it's tilejson, fetch the json to access the pbf url if (tileUrl.includes('.json')) { @@ -312,7 +312,7 @@ export function parseColor(style: any): IParsedStyle | undefined { joinStyle: style['circle-stroke-line-join'] ?? style['stroke-line-join'] ?? 'round', capStyle: - style['circle-stroke-line-cap'] ?? style['stroke-line-cap'] ?? 'round' + style['circle-stroke-line-cap'] ?? style['stroke-line-cap'] ?? 'round', }; return parsedStyle; @@ -350,7 +350,7 @@ export const openDatabase = () => { export const saveToIndexedDB = async ( key: string, file: any, - metadata?: any | undefined + metadata?: any | undefined, ) => { const db = await openDatabase(); return new Promise((resolve, reject) => { @@ -390,7 +390,7 @@ export const getFromIndexedDB = async (key: string) => { const fetchWithProxies = async ( url: string, model: IJupyterGISModel, - parseResponse: (response: Response) => Promise + parseResponse: (response: Response) => Promise, ): Promise => { let settings: any = null; @@ -406,7 +406,7 @@ const fetchWithProxies = async ( const proxyUrls = [ url, // Direct fetch `/jupytergis_core/proxy?url=${encodeURIComponent(url)}`, // Internal proxy - `${proxyUrl}/?url=${encodeURIComponent(url)}` // External proxy + `${proxyUrl}/?url=${encodeURIComponent(url)}`, // External proxy ]; for (const proxyUrl of proxyUrls) { @@ -414,7 +414,7 @@ const fetchWithProxies = async ( const response = await fetch(proxyUrl); if (!response.ok) { console.warn( - `Failed to fetch from ${proxyUrl}: ${response.statusText}` + `Failed to fetch from ${proxyUrl}: ${response.statusText}`, ); continue; } @@ -436,7 +436,7 @@ const fetchWithProxies = async ( export const loadGeoTiff = async ( sourceInfo: { url?: string | undefined }, model: IJupyterGISModel, - file?: Contents.IModel | null + file?: Contents.IModel | null, ) => { if (!sourceInfo?.url) { return null; @@ -453,7 +453,7 @@ export const loadGeoTiff = async ( return { file: cachedData.file, metadata: cachedData.metadata, - sourceUrl: url + sourceUrl: url, }; } @@ -461,7 +461,7 @@ export const loadGeoTiff = async ( if (!file) { fileBlob = await fetchWithProxies(url, model, async response => - response.blob() + response.blob(), ); if (!fileBlob) { showErrorMessage('Network error', `Failed to fetch ${url}`); @@ -483,7 +483,7 @@ export const loadGeoTiff = async ( return { file: fileBlob, metadata, - sourceUrl: url + sourceUrl: url, }; }; @@ -535,7 +535,7 @@ export const loadFile = async (fileInfo: { async response => { const arrayBuffer = await response.arrayBuffer(); return shp(arrayBuffer); - } + }, ); if (geojson) { @@ -556,7 +556,7 @@ export const loadFile = async (fileInfo: { const geojson = await fetchWithProxies( filepath, model, - async response => response.json() + async response => response.json(), ); if (geojson) { @@ -580,12 +580,12 @@ export const loadFile = async (fileInfo: { const absolutePath = PathExt.resolve( PathExt.dirname(model.filePath), - filepath + filepath, ); try { const file = await model.contentsManager.get(absolutePath, { - content: true + content: true, }); if (!file.content) { @@ -668,7 +668,7 @@ const validateImage = async (blob: Blob): Promise => { */ export const base64ToBlob = async ( base64: string, - mimeType: string + mimeType: string, ): Promise => { const response = await fetch(`data:${mimeType};base64,${base64}`); return await response.blob(); @@ -816,7 +816,7 @@ export const MIME_TYPES: { [ext: string]: string } = { '.xul': 'text/xul', '.xwd': 'image/x-xwindowdump', '.zip': 'application/zip', - '.ipynb': 'application/json' + '.ipynb': 'application/json', }; /** @@ -833,7 +833,7 @@ export const getMimeType = (filename: string): string => { } console.warn( - `Unknown file extension: ${extension}, defaulting to 'application/octet-stream'.` + `Unknown file extension: ${extension}, defaulting to 'application/octet-stream'.`, ); return 'application/octet-stream'; }; @@ -845,17 +845,18 @@ export const getMimeType = (filename: string): string => { * @returns An ArrayBuffer. */ export const stringToArrayBuffer = async ( - content: string + content: string, ): Promise => { const base64Response = await fetch( - `data:application/octet-stream;base64,${content}` + `data:application/octet-stream;base64,${content}`, ); return await base64Response.arrayBuffer(); }; const getFeatureAttributes = ( featureProperties: Record>, - predicate: (key: string, value: any) => boolean = (key: string, value) => true + predicate: (key: string, value: any) => boolean = (key: string, value) => + true, ): Record> => { const filteredRecord: Record> = {}; @@ -878,7 +879,7 @@ const getFeatureAttributes = ( * @returns - Attributes which are numeric. */ export const getNumericFeatureAttributes = ( - featureProperties: Record> + featureProperties: Record>, ): Record> => { return getFeatureAttributes(featureProperties, (_: string, value) => { return !(typeof value === 'string' && isNaN(Number(value))); @@ -892,7 +893,7 @@ export const getNumericFeatureAttributes = ( * @returns - Attributes which look like hex color codes. */ export const getColorCodeFeatureAttributes = ( - featureProperties: Record> + featureProperties: Record>, ): Record> => { return getFeatureAttributes(featureProperties, (_, value) => { const regex = new RegExp('^#[0-9a-f]{6}$'); @@ -903,7 +904,7 @@ export const getColorCodeFeatureAttributes = ( export function downloadFile( content: BlobPart, fileName: string, - mimeType: string + mimeType: string, ) { const blob = new Blob([content], { type: mimeType }); const url = URL.createObjectURL(blob); @@ -917,13 +918,13 @@ export function downloadFile( export async function getGeoJSONDataFromLayerSource( source: IJGISSource, - model: IJupyterGISModel + model: IJupyterGISModel, ): Promise { const vectorSourceTypes: SourceType[] = ['GeoJSONSource', 'ShapefileSource']; if (!vectorSourceTypes.includes(source.type as SourceType)) { console.error( - `Invalid source type '${source.type}'. Expected one of: ${vectorSourceTypes.join(', ')}` + `Invalid source type '${source.type}'. Expected one of: ${vectorSourceTypes.join(', ')}`, ); return null; } @@ -937,7 +938,7 @@ export async function getGeoJSONDataFromLayerSource( const fileContent = await loadFile({ filepath: source.parameters.path, type: source.type, - model + model, }); return typeof fileContent === 'object' ? JSON.stringify(fileContent) diff --git a/packages/base/src/types.ts b/packages/base/src/types.ts index 8c1da18b9..c64013820 100644 --- a/packages/base/src/types.ts +++ b/packages/base/src/types.ts @@ -3,7 +3,7 @@ import { IJupyterGISDoc, IJupyterGISModel, IJupyterGISTracker, - IJupyterGISWidget + IJupyterGISWidget, } from '@jupytergis/schema'; import { WidgetTracker } from '@jupyterlab/apputils'; import { ISignal } from '@lumino/signaling'; diff --git a/packages/base/src/widget.ts b/packages/base/src/widget.ts index 3dfde7707..474e114ae 100644 --- a/packages/base/src/widget.ts +++ b/packages/base/src/widget.ts @@ -1,7 +1,7 @@ import { IJupyterGISDocumentWidget, IJupyterGISModel, - IJupyterGISOutputWidget + IJupyterGISOutputWidget, } from '@jupytergis/schema'; import { MainAreaWidget } from '@jupyterlab/apputils'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; @@ -28,7 +28,7 @@ export class JupyterGISDocumentWidget implements IJupyterGISDocumentWidget { constructor( - options: DocumentWidget.IOptions + options: DocumentWidget.IOptions, ) { super(options); } @@ -112,13 +112,13 @@ export class JupyterGISPanel extends SplitPanel { this._mainViewModel = new MainViewModel({ jGISModel: options.model, viewSetting: this._view, - commands: options.commandRegistry + commands: options.commandRegistry, }); } _initView() { this._jupyterGISMainViewPanel = new JupyterGISMainViewPanel({ - mainViewModel: this._mainViewModel + mainViewModel: this._mainViewModel, }); this.addWidget(this._jupyterGISMainViewPanel); SplitPanel.setStretch(this._jupyterGISMainViewPanel, 1); @@ -186,7 +186,7 @@ export class JupyterGISPanel extends SplitPanel { manager, mimeTypeService, rendermime, - commandRegistry + commandRegistry, } = this._consoleOption; if ( contentFactory && @@ -201,7 +201,7 @@ export class JupyterGISPanel extends SplitPanel { manager, mimeTypeService, rendermime, - commandRegistry + commandRegistry, }); const { consolePanel } = this._consoleView; @@ -211,7 +211,7 @@ export class JupyterGISPanel extends SplitPanel { this.setRelativeSizes([2, 1]); this._consoleOpened = true; await consolePanel.console.inject( - `from jupytergis import GISDocument\ndoc = GISDocument("${jgisPath}")` + `from jupytergis import GISDocument\ndoc = GISDocument("${jgisPath}")`, ); consolePanel.console.sessionContext.kernelChanged.connect((_, arg) => { if (!arg.newValue) { diff --git a/packages/schema/src/doc.ts b/packages/schema/src/doc.ts index dd9e3ff0e..2f7f6619c 100644 --- a/packages/schema/src/doc.ts +++ b/packages/schema/src/doc.ts @@ -10,7 +10,7 @@ import { IJGISLayers, IJGISOptions, IJGISSource, - IJGISSources + IJGISSources, } from './_interface/project/jgis'; import { SCHEMA_VERSION } from './_interface/version'; import { @@ -19,7 +19,7 @@ import { IJGISLayerTreeDocChange, IJGISSourceDocChange, IJupyterGISDoc, - IJupyterGISDocChange + IJupyterGISDocChange, } from './interfaces'; export class JupyterGISDoc @@ -67,7 +67,7 @@ export class JupyterGISDoc this.transact(() => { const layers = value['layers'] ?? {}; Object.entries(layers).forEach(([key, val]) => - this._layers.set(key, val as string) + this._layers.set(key, val as string), ); const layerTree = @@ -78,17 +78,17 @@ export class JupyterGISDoc const options = value['options'] ?? {}; Object.entries(options).forEach(([key, val]) => - this._options.set(key, val) + this._options.set(key, val), ); const sources = value['sources'] ?? {}; Object.entries(sources).forEach(([key, val]) => - this._sources.set(key, val) + this._sources.set(key, val), ); const metadata = value['metadata'] ?? {}; Object.entries(metadata).forEach(([key, val]) => - this._metadata.set(key, val as string) + this._metadata.set(key, val as string), ); }); } @@ -229,13 +229,13 @@ export class JupyterGISDoc updateObjectParameters( id: string, - value: IJGISLayer['parameters'] | IJGISSource['parameters'] + value: IJGISLayer['parameters'] | IJGISSource['parameters'], ) { const layer = this.getLayer(id); if (layer) { layer.parameters = { ...layer.parameters, - ...value + ...value, }; this.updateLayer(id, layer); @@ -245,7 +245,7 @@ export class JupyterGISDoc if (source) { source.parameters = { ...source.parameters, - ...value + ...value, }; this.updateSource(id, source); @@ -349,7 +349,7 @@ export class JupyterGISDoc changes.push({ id: key as string, oldValue: change.oldValue, - newValue: JSONExt.deepCopy(event.target.toJSON()[key]) + newValue: JSONExt.deepCopy(event.target.toJSON()[key]), }); }); }); @@ -377,7 +377,7 @@ export class JupyterGISDoc } changes.push({ id: key as string, - newValue: JSONExt.deepCopy(event.target.toJSON()[key]) + newValue: JSONExt.deepCopy(event.target.toJSON()[key]), }); }); }); @@ -403,14 +403,14 @@ export class JupyterGISDoc private _optionsChanged = new Signal(this); private _layersChanged = new Signal( - this + this, ); private _layerTreeChanged = new Signal< IJupyterGISDoc, IJGISLayerTreeDocChange >(this); private _sourcesChanged = new Signal( - this + this, ); private _metadataChanged = new Signal(this); } diff --git a/packages/schema/src/interfaces.ts b/packages/schema/src/interfaces.ts index 43fc5d1e0..b11785a27 100644 --- a/packages/schema/src/interfaces.ts +++ b/packages/schema/src/interfaces.ts @@ -3,7 +3,7 @@ import { DocumentChange, MapChange, StateChange, - YDocument + YDocument, } from '@jupyter/ydoc'; import { IWidgetTracker, MainAreaWidget } from '@jupyterlab/apputils'; import { IChangedArgs } from '@jupyterlab/coreutils'; @@ -24,7 +24,7 @@ import { IJGISOptions, IJGISSource, IJGISSources, - SourceType + SourceType, } from './_interface/project/jgis'; import { IRasterSource } from './_interface/project/sources/rastersource'; export { IGeoJSONSource } from './_interface/geojsonsource'; @@ -106,7 +106,7 @@ export interface IJupyterGISDoc extends YDocument { id: string, value: IJGISLayer, groupName?: string, - position?: number + position?: number, ): void; updateLayer(id: string, value: IJGISLayer): void; @@ -122,7 +122,7 @@ export interface IJupyterGISDoc extends YDocument { updateObjectParameters( id: string, - value: IJGISLayer['parameters'] | IJGISSource['parameters'] + value: IJGISLayer['parameters'] | IJGISSource['parameters'], ): void; getObject(id: string): IJGISLayer | IJGISSource | undefined; @@ -196,7 +196,7 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel { id: string, layer: IJGISLayer, groupName?: string, - position?: number + position?: number, ): void; removeLayer(id: string): void; getOptions(): IJGISOptions; @@ -208,7 +208,7 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel { moveItemRelatedTo(item: string, relativeItem: string, after: boolean): void; addNewLayerGroup( selected: { [key: string]: ISelection }, - group: IJGISLayerGroup + group: IJGISLayerGroup, ): void; syncViewport(viewport?: IViewPortState, emitter?: string): void; diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index 3107ad685..f87f0b147 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -16,7 +16,7 @@ import { IJGISLayers, IJGISOptions, IJGISSource, - IJGISSources + IJGISSources, } from './_interface/project/jgis'; import { JupyterGISDoc } from './doc'; import { @@ -33,7 +33,7 @@ import { IViewPortState, JgisCoordinates, Pointer, - IJupyterGISSettings + IJupyterGISSettings, } from './interfaces'; import jgisSchema from './schema/project/jgis.json'; @@ -52,7 +52,7 @@ export class JupyterGISModel implements IJupyterGISModel { this.sharedModel.awareness.on('change', this._onClientStateChanged); this._sharedModel.metadataChanged.connect( this._metadataChangedHandler, - this + this, ); this.annotationModel = annotationModel; this.settingRegistry = settingRegistry; @@ -253,7 +253,7 @@ export class JupyterGISModel implements IJupyterGISModel { zoom: 0, bearing: 0, pitch: 0, - projection: 'EPSG:3857' + projection: 'EPSG:3857', }; this.sharedModel.metadata = jsonData.metadata ?? {}; }); @@ -285,7 +285,7 @@ export class JupyterGISModel implements IJupyterGISModel { layers: this.sharedModel.layers, layerTree: this.sharedModel.layerTree, options: this.sharedModel.options, - metadata: this.sharedModel.metadata + metadata: this.sharedModel.metadata, }; } @@ -386,7 +386,7 @@ export class JupyterGISModel implements IJupyterGISModel { } const item: IJGISLayerGroup = { name, - layers: [] + layers: [], }; this._addLayerTreeItem(item, groupName, position); } @@ -405,7 +405,7 @@ export class JupyterGISModel implements IJupyterGISModel { id: string, layer: IJGISLayer, groupName?: string, - position?: number + position?: number, ): void { if (!this.getLayer(id)) { this.sharedModel.addLayer(id, layer); @@ -434,28 +434,28 @@ export class JupyterGISModel implements IJupyterGISModel { syncViewport(viewport?: IViewPortState, emitter?: string): void { this.sharedModel.awareness.setLocalStateField('viewportState', { value: viewport, - emitter + emitter, }); } syncPointer(pointer?: Pointer, emitter?: string): void { this.sharedModel.awareness.setLocalStateField('pointer', { value: pointer, - emitter + emitter, }); } syncSelected(value: { [key: string]: ISelection }, emitter?: string): void { this.sharedModel.awareness.setLocalStateField('selected', { value, - emitter + emitter, }); } syncIdentifiedFeatures(features: IDict, emitter?: string): void { this.sharedModel.awareness.setLocalStateField('identifiedFeatures', { value: features, - emitter + emitter, }); } @@ -481,7 +481,7 @@ export class JupyterGISModel implements IJupyterGISModel { private _addLayerTreeItem( item: IJGISLayerItem, groupName?: string, - index?: number + index?: number, ): void { if (groupName) { const layerTreeInfo = this._getLayerTreeInfo(groupName); @@ -490,18 +490,18 @@ export class JupyterGISModel implements IJupyterGISModel { layerTreeInfo.workingGroup.layers.splice( index ?? layerTreeInfo.workingGroup.layers.length, 0, - item + item, ); this._sharedModel.updateLayerTreeItem( layerTreeInfo.mainGroupIndex, - layerTreeInfo.mainGroup + layerTreeInfo.mainGroup, ); } } else { this.sharedModel.addLayerTreeItem( index ?? this.getLayerTree().length, - item + item, ); } } @@ -560,7 +560,7 @@ export class JupyterGISModel implements IJupyterGISModel { addNewLayerGroup( selected: { [key: string]: ISelection }, - group: IJGISLayerGroup + group: IJGISLayerGroup, ) { const layerTree = this.getLayerTree(); for (const item in selected) { @@ -572,7 +572,7 @@ export class JupyterGISModel implements IJupyterGISModel { private _removeLayerTreeLayer( layerTree: IJGISLayerItem[], - layerIdToRemove: string + layerIdToRemove: string, ) { this._removeLayerTreeItem(layerTree, layerIdToRemove, true); this.sharedModel.layerTree = layerTree; @@ -580,7 +580,7 @@ export class JupyterGISModel implements IJupyterGISModel { private _removeLayerTreeGroup( layerTree: IJGISLayerItem[], - groupName: string + groupName: string, ) { this._removeLayerTreeItem(layerTree, groupName, false); this.sharedModel.layerTree = layerTree; @@ -589,7 +589,7 @@ export class JupyterGISModel implements IJupyterGISModel { private _removeLayerTreeItem( layerTree: IJGISLayerItem[], target: string, - isLayer: boolean + isLayer: boolean, ) { // Iterate over each item in the layerTree for (let i = 0; i < layerTree.length; i++) { @@ -618,7 +618,7 @@ export class JupyterGISModel implements IJupyterGISModel { layerTreeInfo.workingGroup.name = newName; this._sharedModel.updateLayerTreeItem( layerTreeInfo.mainGroupIndex, - layerTreeInfo.mainGroup + layerTreeInfo.mainGroup, ); } else { console.log('Something went wrong when renaming layer'); @@ -632,7 +632,7 @@ export class JupyterGISModel implements IJupyterGISModel { function removeLayerGroupEntry( layerTree: IJGISLayerItem[], - groupName: string + groupName: string, ): IJGISLayerItem[] { const result: IJGISLayerItem[] = []; @@ -651,7 +651,7 @@ export class JupyterGISModel implements IJupyterGISModel { if (layerTreeInfo) { this._sharedModel.updateLayerTreeItem( layerTreeInfo.mainGroupIndex, - updatedLayerTree[layerTreeInfo.mainGroupIndex] + updatedLayerTree[layerTreeInfo.mainGroupIndex], ); } } @@ -665,7 +665,7 @@ export class JupyterGISModel implements IJupyterGISModel { this.sharedModel.awareness.setLocalStateField( 'isTemporalControllerActive', - this._isTemporalControllerActive + this._isTemporalControllerActive, ); } @@ -700,7 +700,7 @@ export class JupyterGISModel implements IJupyterGISModel { return { mainGroup, workingGroup, - mainGroupIndex + mainGroupIndex, }; } @@ -810,7 +810,7 @@ namespace Private { */ export function layerTreeRecursion( items: IJGISLayerItem[], - current: string[] = [] + current: string[] = [], ): string[] { for (const layer of items) { if (typeof layer === 'string') { @@ -833,7 +833,7 @@ namespace Private { export function findItemPath( items: IJGISLayerItem[], itemId: string, - indexes: number[] = [] + indexes: number[] = [], ): number[] { for (let index = 0; index < items.length; index++) { const item = items[index]; diff --git a/packages/schema/src/token.ts b/packages/schema/src/token.ts index a7490e7ff..30b117458 100644 --- a/packages/schema/src/token.ts +++ b/packages/schema/src/token.ts @@ -5,15 +5,15 @@ import { IJGISExternalCommandRegistry, IJGISFormSchemaRegistry, IJGISLayerBrowserRegistry, - IJupyterGISTracker + IJupyterGISTracker, } from './interfaces'; export const IJupyterGISDocTracker = new Token( - 'jupyterGISDocTracker' + 'jupyterGISDocTracker', ); export const IJGISFormSchemaRegistryToken = new Token( - 'jupytergisFormSchemaRegistry' + 'jupytergisFormSchemaRegistry', ); export const IJGISExternalCommandRegistryToken = @@ -23,5 +23,5 @@ export const IJGISLayerBrowserRegistryToken = new Token('jupytergisExternalCommandRegistry'); export const IAnnotationToken = new Token( - 'jupytergisAnnotationModel' + 'jupytergisAnnotationModel', ); diff --git a/python/jupytergis_core/src/externalcommand.ts b/python/jupytergis_core/src/externalcommand.ts index ac815f400..03f2e5e74 100644 --- a/python/jupytergis_core/src/externalcommand.ts +++ b/python/jupytergis_core/src/externalcommand.ts @@ -1,6 +1,6 @@ import { IJGISExternalCommand, - IJGISExternalCommandRegistry + IJGISExternalCommandRegistry, } from '@jupytergis/schema'; export class JupyterGISExternalCommandRegistry diff --git a/python/jupytergis_core/src/factory.ts b/python/jupytergis_core/src/factory.ts index 6fee7ea00..2e3b04732 100644 --- a/python/jupytergis_core/src/factory.ts +++ b/python/jupytergis_core/src/factory.ts @@ -2,12 +2,12 @@ import { ICollaborativeDrive } from '@jupyter/collaborative-drive'; import { JupyterGISPanel, JupyterGISDocumentWidget, - ToolbarWidget + ToolbarWidget, } from '@jupytergis/base'; import { JupyterGISModel, IJupyterGISTracker, - IJGISExternalCommandRegistry + IJGISExternalCommandRegistry, } from '@jupytergis/schema'; import { IEditorMimeTypeService } from '@jupyterlab/codeeditor'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; @@ -49,7 +49,7 @@ export class JupyterGISDocumentWidgetFactory extends ABCWidgetFactory< * @returns The widget */ protected createNewWidget( - context: DocumentRegistry.IContext + context: DocumentRegistry.IContext, ): JupyterGISDocumentWidget { if (this._backendCheck) { const checked = this._backendCheck(); @@ -69,12 +69,12 @@ export class JupyterGISDocumentWidgetFactory extends ABCWidgetFactory< mimeTypeService: this.options.mimeTypeService, rendermime: this.options.rendermime, consoleTracker: this.options.consoleTracker, - commandRegistry: this.options.commands + commandRegistry: this.options.commands, }); const toolbar = new ToolbarWidget({ commands: this._commands, model, - externalCommands: this._externalCommandRegistry.getCommands() + externalCommands: this._externalCommandRegistry.getCommands(), }); return new JupyterGISDocumentWidget({ context, content, toolbar }); } diff --git a/python/jupytergis_core/src/index.ts b/python/jupytergis_core/src/index.ts index 7b1c54436..1f5b22fb5 100644 --- a/python/jupytergis_core/src/index.ts +++ b/python/jupytergis_core/src/index.ts @@ -4,7 +4,7 @@ import { formSchemaRegistryPlugin, layerBrowserRegistryPlugin, trackerPlugin, - annotationPlugin + annotationPlugin, } from './plugin'; export * from './factory'; @@ -14,5 +14,5 @@ export default [ formSchemaRegistryPlugin, externalCommandRegistryPlugin, layerBrowserRegistryPlugin, - annotationPlugin + annotationPlugin, ]; diff --git a/python/jupytergis_core/src/jgisplugin/modelfactory.ts b/python/jupytergis_core/src/jgisplugin/modelfactory.ts index 9b6c2fce8..ae485f305 100644 --- a/python/jupytergis_core/src/jgisplugin/modelfactory.ts +++ b/python/jupytergis_core/src/jgisplugin/modelfactory.ts @@ -1,7 +1,7 @@ import { IAnnotationModel, IJupyterGISDoc, - JupyterGISModel + JupyterGISModel, } from '@jupytergis/schema'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; @@ -81,13 +81,13 @@ export class JupyterGISModelFactory * @returns The model */ createNew( - options: DocumentRegistry.IModelOptions + options: DocumentRegistry.IModelOptions, ): JupyterGISModel { const model = new JupyterGISModel({ sharedModel: options.sharedModel, languagePreference: options.languagePreference, annotationModel: this._annotationModel, - settingRegistry: this._settingRegistry + settingRegistry: this._settingRegistry, }); model.initSettings(); return model; diff --git a/python/jupytergis_core/src/jgisplugin/plugins.ts b/python/jupytergis_core/src/jgisplugin/plugins.ts index c51d0074c..9ea457c56 100644 --- a/python/jupytergis_core/src/jgisplugin/plugins.ts +++ b/python/jupytergis_core/src/jgisplugin/plugins.ts @@ -1,6 +1,6 @@ import { ICollaborativeDrive, - SharedDocumentFactory + SharedDocumentFactory, } from '@jupyter/collaborative-drive'; import { CommandIDs, logoIcon, logoMiniIcon } from '@jupytergis/base'; import { @@ -11,16 +11,16 @@ import { IJupyterGISDocTracker, IJupyterGISWidget, JupyterGISDoc, - SCHEMA_VERSION + SCHEMA_VERSION, } from '@jupytergis/schema'; import { JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, } from '@jupyterlab/application'; import { ICommandPalette, IThemeManager, - WidgetTracker + WidgetTracker, } from '@jupyterlab/apputils'; import { IEditorServices } from '@jupyterlab/codeeditor'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; @@ -54,7 +54,7 @@ const activate = async ( settingRegistry: ISettingRegistry, launcher: ILauncher | null, palette: ICommandPalette | null, - drive: ICollaborativeDrive | null + drive: ICollaborativeDrive | null, ): Promise => { if (PageConfig.getOption('jgis_expose_maps')) { window.jupytergisMaps = {}; @@ -81,7 +81,7 @@ const activate = async ( contentFactory, rendermime, mimeTypeService: editorServices.mimeTypeService, - consoleTracker + consoleTracker, }); // Registering the widget factory @@ -93,14 +93,14 @@ const activate = async ( modelName: MODEL_NAME, name: 'JSON Editor', primaryFileType: app.docRegistry.getFileType('json'), - fileTypes: [CONTENT_TYPE] + fileTypes: [CONTENT_TYPE], }); app.docRegistry.addWidgetFactory(mimeDocumentFactory); // Creating and registering the model factory for our custom DocumentModel const modelFactory = new JupyterGISModelFactory({ annotationModel, - settingRegistry + settingRegistry, }); app.docRegistry.addModelFactory(modelFactory); @@ -112,7 +112,7 @@ const activate = async ( extensions: ['.jgis', '.JGIS'], fileFormat: 'text', contentType: CONTENT_TYPE, - icon: logoMiniIcon + icon: logoMiniIcon, }); const jGISSharedModelFactory: SharedDocumentFactory = () => { @@ -121,7 +121,7 @@ const activate = async ( if (drive) { drive.sharedModelFactory.registerDocumentFactory( CONTENT_TYPE, - jGISSharedModelFactory + jGISSharedModelFactory, ); } @@ -131,7 +131,7 @@ const activate = async ( tracker.save(widget); }); themeManager.themeChanged.connect((_, changes) => - widget.model.themeChanged.emit(changes) + widget.model.themeChanged.emit(changes), ); app.shell.activateById('jupytergis::leftControlPanel'); app.shell.activateById('jupytergis::rightControlPanel'); @@ -163,22 +163,22 @@ const activate = async ( let model = await app.serviceManager.contents.newUntitled({ path: cwd, type: 'file', - ext: '.jGIS' + ext: '.jGIS', }); model = await app.serviceManager.contents.save(model.path, { ...model, format: 'text', size: undefined, - content: `{\n\t"schemaVersion": "${SCHEMA_VERSION}",\n\t"layers": {},\n\t"sources": {},\n\t"options": {"latitude": 0, "longitude": 0, "zoom": 0, "bearing": 0, "pitch": 0, "projection": "EPSG:3857"},\n\t"layerTree": [],\n\t"metadata": {}\n}` + content: `{\n\t"schemaVersion": "${SCHEMA_VERSION}",\n\t"layers": {},\n\t"sources": {},\n\t"options": {"latitude": 0, "longitude": 0, "zoom": 0, "bearing": 0, "pitch": 0, "projection": "EPSG:3857"},\n\t"layerTree": [],\n\t"metadata": {}\n}`, }); // Open the newly created file with the 'Editor' return app.commands.execute('docmanager:open', { path: model.path, - factory: FACTORY + factory: FACTORY, }); - } + }, }); // Add the command to the launcher @@ -186,7 +186,7 @@ const activate = async ( launcher.add({ command: CommandIDs.createNew, category: 'Other', - rank: 1 + rank: 1, }); } @@ -195,44 +195,44 @@ const activate = async ( palette.addItem({ command: CommandIDs.createNew, args: { isPalette: true }, - category: PALETTE_CATEGORY + category: PALETTE_CATEGORY, }); palette.addItem({ command: CommandIDs.openLayerBrowser, - category: 'JupyterGIS' + category: 'JupyterGIS', }); // Layers and Sources palette.addItem({ command: CommandIDs.newRasterEntry, - category: 'JupyterGIS' + category: 'JupyterGIS', }); palette.addItem({ command: CommandIDs.newVectorTileEntry, - category: 'JupyterGIS' + category: 'JupyterGIS', }); palette.addItem({ command: CommandIDs.newGeoJSONEntry, - category: 'JupyterGIS' + category: 'JupyterGIS', }); palette.addItem({ command: CommandIDs.newHillshadeEntry, - category: 'JupyterGIS' + category: 'JupyterGIS', }); // Layer and group actions palette.addItem({ command: CommandIDs.moveLayerToNewGroup, - category: 'JupyterGIS' + category: 'JupyterGIS', }); palette.addItem({ command: CommandIDs.buffer, - category: 'JupyterGIS' + category: 'JupyterGIS', }); } }; @@ -249,11 +249,11 @@ const jGISPlugin: JupyterFrontEndPlugin = { IRenderMimeRegistry, IConsoleTracker, IAnnotationToken, - ISettingRegistry + ISettingRegistry, ], optional: [ILauncher, ICommandPalette, ICollaborativeDrive], autoStart: true, - activate + activate, }; export default jGISPlugin; diff --git a/python/jupytergis_core/src/layerBrowserRegistry.ts b/python/jupytergis_core/src/layerBrowserRegistry.ts index 0c92b4cf2..4ecec1366 100644 --- a/python/jupytergis_core/src/layerBrowserRegistry.ts +++ b/python/jupytergis_core/src/layerBrowserRegistry.ts @@ -1,6 +1,6 @@ import { IJGISLayerBrowserRegistry, - IRasterLayerGalleryEntry + IRasterLayerGalleryEntry, } from '@jupytergis/schema'; /** diff --git a/python/jupytergis_core/src/plugin.ts b/python/jupytergis_core/src/plugin.ts index bf18c7ece..2dfec7bc2 100644 --- a/python/jupytergis_core/src/plugin.ts +++ b/python/jupytergis_core/src/plugin.ts @@ -10,11 +10,11 @@ import { IJGISLayerBrowserRegistryToken, IJupyterGISDocTracker, IJupyterGISTracker, - IJupyterGISWidget + IJupyterGISWidget, } from '@jupytergis/schema'; import { JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, } from '@jupyterlab/application'; import { WidgetTracker } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; @@ -36,14 +36,14 @@ export const trackerPlugin: JupyterFrontEndPlugin = { activate: ( app: JupyterFrontEnd, translator: ITranslator, - mainMenu?: IMainMenu + mainMenu?: IMainMenu, ): IJupyterGISTracker => { const tracker = new WidgetTracker({ - namespace: NAME_SPACE + namespace: NAME_SPACE, }); console.log('jupytergis:core:tracker is activated!'); return tracker; - } + }, }; export const formSchemaRegistryPlugin: JupyterFrontEndPlugin = @@ -54,11 +54,11 @@ export const formSchemaRegistryPlugin: JupyterFrontEndPlugin { const registry = new JupyterGISFormSchemaRegistry(docmanager); return registry; - } + }, }; export const externalCommandRegistryPlugin: JupyterFrontEndPlugin = @@ -70,7 +70,7 @@ export const externalCommandRegistryPlugin: JupyterFrontEndPlugin { const registry = new JupyterGISExternalCommandRegistry(); return registry; - } + }, }; export const layerBrowserRegistryPlugin: JupyterFrontEndPlugin = @@ -84,7 +84,7 @@ export const layerBrowserRegistryPlugin: JupyterFrontEndPlugin = { @@ -94,12 +94,12 @@ export const annotationPlugin: JupyterFrontEndPlugin = { provides: IAnnotationToken, activate: (app: JupyterFrontEnd, tracker: IJupyterGISTracker) => { const annotationModel = new AnnotationModel({ - model: tracker.currentWidget?.model + model: tracker.currentWidget?.model, }); tracker.currentChanged.connect((_, changed) => { annotationModel.model = changed?.model || undefined; }); return annotationModel; - } + }, }; diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index a1d32f9a7..094ad3028 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -8,7 +8,7 @@ import { createDefaultLayerRegistry, rasterSubMenu, vectorSubMenu, - logoMiniIcon + logoMiniIcon, } from '@jupytergis/base'; import { IAnnotationModel, @@ -20,12 +20,12 @@ import { IJGISLayerItem, IJupyterGISDocTracker, IJupyterGISTracker, - IJupyterGISWidget + IJupyterGISWidget, } from '@jupytergis/schema'; import { ILayoutRestorer, JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, } from '@jupyterlab/application'; import { WidgetTracker } from '@jupyterlab/apputils'; import { ICompletionProviderManager } from '@jupyterlab/completer'; @@ -45,7 +45,7 @@ const plugin: JupyterFrontEndPlugin = { IJupyterGISDocTracker, IJGISFormSchemaRegistryToken, IJGISLayerBrowserRegistryToken, - IStateDB + IStateDB, ], optional: [IMainMenu, ITranslator, ICompletionProviderManager], activate: ( @@ -56,7 +56,7 @@ const plugin: JupyterFrontEndPlugin = { state: IStateDB, mainMenu?: IMainMenu, translator?: ITranslator, - completionProviderManager?: ICompletionProviderManager + completionProviderManager?: ICompletionProviderManager, ): void => { console.log('jupytergis:lab:main-menu is activated!'); translator = translator ?? nullTranslator; @@ -78,51 +78,51 @@ const plugin: JupyterFrontEndPlugin = { formSchemaRegistry, layerBrowserRegistry, state, - completionProviderManager + completionProviderManager, ); app.contextMenu.addItem({ selector: '.jp-gis-source.jp-gis-sourceUnused', rank: 1, - command: CommandIDs.removeSource + command: CommandIDs.removeSource, }); app.contextMenu.addItem({ selector: '.jp-gis-source', rank: 1, - command: CommandIDs.renameSource + command: CommandIDs.renameSource, }); // LAYERS and LAYER GROUPS context menu app.contextMenu.addItem({ command: CommandIDs.symbology, selector: '.jp-gis-layerItem', - rank: 1 + rank: 1, }); // Separator app.contextMenu.addItem({ type: 'separator', selector: '.jp-gis-layerPanel', - rank: 1 + rank: 1, }); app.contextMenu.addItem({ command: CommandIDs.removeLayer, selector: '.jp-gis-layerItem', - rank: 2 + rank: 2, }); app.contextMenu.addItem({ command: CommandIDs.renameLayer, selector: '.jp-gis-layerItem', - rank: 2 + rank: 2, }); app.contextMenu.addItem({ command: CommandIDs.zoomToLayer, selector: '.jp-gis-layerItem', - rank: 2 + rank: 2, }); // Create the Download submenu @@ -131,7 +131,7 @@ const plugin: JupyterFrontEndPlugin = { downloadSubmenu.id = 'jp-gis-contextmenu-download'; downloadSubmenu.addItem({ - command: CommandIDs.downloadGeoJSON + command: CommandIDs.downloadGeoJSON, }); // Add the Download submenu to the context menu @@ -139,7 +139,7 @@ const plugin: JupyterFrontEndPlugin = { type: 'submenu', selector: '.jp-gis-layerItem', rank: 2, - submenu: downloadSubmenu + submenu: downloadSubmenu, }); // Create the Processing submenu @@ -150,18 +150,18 @@ const plugin: JupyterFrontEndPlugin = { processingSubmenu.id = 'jp-gis-contextmenu-processing'; processingSubmenu.addItem({ - command: CommandIDs.buffer + command: CommandIDs.buffer, }); processingSubmenu.addItem({ - command: CommandIDs.dissolve + command: CommandIDs.dissolve, }); app.contextMenu.addItem({ type: 'submenu', selector: '.jp-gis-layerItem', rank: 2, - submenu: processingSubmenu + submenu: processingSubmenu, }); const moveLayerSubmenu = new Menu({ commands: app.commands }); @@ -174,30 +174,30 @@ const plugin: JupyterFrontEndPlugin = { type: 'submenu', selector: '.jp-gis-layerItem', rank: 2, - submenu: moveLayerSubmenu + submenu: moveLayerSubmenu, }); app.contextMenu.opened.connect(() => - buildGroupsMenu(app.contextMenu, tracker) + buildGroupsMenu(app.contextMenu, tracker), ); app.contextMenu.addItem({ command: CommandIDs.removeGroup, selector: '.jp-gis-layerGroupHeader', - rank: 2 + rank: 2, }); app.contextMenu.addItem({ command: CommandIDs.renameGroup, selector: '.jp-gis-layerGroupHeader', - rank: 2 + rank: 2, }); // Separator app.contextMenu.addItem({ type: 'separator', selector: '.jp-gis-layerPanel', - rank: 2 + rank: 2, }); const newLayerSubMenu = new Menu({ commands: app.commands }); @@ -206,24 +206,24 @@ const plugin: JupyterFrontEndPlugin = { newLayerSubMenu.addItem({ type: 'submenu', - submenu: rasterSubMenu(app.commands) + submenu: rasterSubMenu(app.commands), }); newLayerSubMenu.addItem({ type: 'submenu', - submenu: vectorSubMenu(app.commands) + submenu: vectorSubMenu(app.commands), }); app.contextMenu.addItem({ type: 'submenu', selector: '.jp-gis-layerPanel', rank: 3, - submenu: newLayerSubMenu + submenu: newLayerSubMenu, }); if (mainMenu) { populateMenus(mainMenu, isEnabled); } - } + }, }; const controlPanel: JupyterFrontEndPlugin = { @@ -234,7 +234,7 @@ const controlPanel: JupyterFrontEndPlugin = { IJupyterGISDocTracker, IJGISFormSchemaRegistryToken, IStateDB, - IAnnotationToken + IAnnotationToken, ], activate: ( app: JupyterFrontEnd, @@ -242,7 +242,7 @@ const controlPanel: JupyterFrontEndPlugin = { tracker: IJupyterGISTracker, formSchemaRegistry: IJGISFormSchemaRegistry, state: IStateDB, - annotationModel: IAnnotationModel + annotationModel: IAnnotationModel, ) => { const controlModel = new ControlPanelModel({ tracker }); @@ -250,7 +250,7 @@ const controlPanel: JupyterFrontEndPlugin = { model: controlModel, tracker, state, - commands: app.commands + commands: app.commands, }); leftControlPanel.id = 'jupytergis::leftControlPanel'; leftControlPanel.title.caption = 'JupyterGIS Control Panel'; @@ -260,7 +260,7 @@ const controlPanel: JupyterFrontEndPlugin = { model: controlModel, tracker, formSchemaRegistry, - annotationModel + annotationModel, }); rightControlPanel.id = 'jupytergis::rightControlPanel'; rightControlPanel.title.caption = 'JupyterGIS Control Panel'; @@ -272,7 +272,7 @@ const controlPanel: JupyterFrontEndPlugin = { } app.shell.add(leftControlPanel, 'left', { rank: 2000 }); app.shell.add(rightControlPanel, 'right', { rank: 2000 }); - } + }, }; /** @@ -282,11 +282,11 @@ function populateMenus(mainMenu: IMainMenu, isEnabled: () => boolean): void { // Add undo/redo hooks to the edit menu. mainMenu.editMenu.undoers.redo.add({ id: CommandIDs.redo, - isEnabled + isEnabled, }); mainMenu.editMenu.undoers.undo.add({ id: CommandIDs.undo, - isEnabled + isEnabled, }); } @@ -295,7 +295,7 @@ function populateMenus(mainMenu: IMainMenu, isEnabled: () => boolean): void { */ function buildGroupsMenu( contextMenu: ContextMenu, - tracker: WidgetTracker + tracker: WidgetTracker, ) { if (!tracker.currentWidget?.model) { return; @@ -307,7 +307,7 @@ function buildGroupsMenu( contextMenu.menu.items.find( item => item.type === 'submenu' && - item.submenu?.id === 'jp-gis-contextmenu-movelayer' + item.submenu?.id === 'jp-gis-contextmenu-movelayer', )?.submenu ?? null; // Bail early if the submenu isn't found @@ -346,18 +346,18 @@ function buildGroupsMenu( submenu.addItem({ command: CommandIDs.moveLayersToGroup, - args: { label: '' } + args: { label: '' }, }); groupNames.forEach(name => { submenu.addItem({ command: CommandIDs.moveLayersToGroup, - args: { label: name } + args: { label: name }, }); }); submenu.addItem({ - command: CommandIDs.moveLayerToNewGroup + command: CommandIDs.moveLayerToNewGroup, }); } diff --git a/python/jupytergis_lab/src/notebookrenderer.ts b/python/jupytergis_lab/src/notebookrenderer.ts index cea775ad3..e86b9d751 100644 --- a/python/jupytergis_lab/src/notebookrenderer.ts +++ b/python/jupytergis_lab/src/notebookrenderer.ts @@ -3,18 +3,18 @@ import { JupyterGISOutputWidget, JupyterGISPanel, JupyterGISTracker, - ToolbarWidget + ToolbarWidget, } from '@jupytergis/base'; import { IJGISExternalCommandRegistry, IJGISExternalCommandRegistryToken, IJupyterGISDoc, IJupyterGISDocTracker, - JupyterGISModel + JupyterGISModel, } from '@jupytergis/schema'; import { JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, } from '@jupyterlab/application'; import { showErrorMessage } from '@jupyterlab/apputils'; import { ConsolePanel } from '@jupyterlab/console'; @@ -29,7 +29,7 @@ import { IJupyterYWidget, IJupyterYWidgetManager, JupyterYDoc, - JupyterYModel + JupyterYModel, } from 'yjs-widgets'; export interface ICommMetadata { @@ -87,13 +87,13 @@ export class YJupyterGISLuminoWidget extends Panel { toolbar = new ToolbarWidget({ commands, model, - externalCommands: externalCommands?.getCommands() || [] + externalCommands: externalCommands?.getCommands() || [], }); } this._jgisWidget = new JupyterGISOutputWidget({ model, content, - toolbar + toolbar, }); this.addWidget(this._jgisWidget); tracker?.add(this._jgisWidget); @@ -116,14 +116,14 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { IJGISExternalCommandRegistryToken, IJupyterGISDocTracker, IJupyterYWidgetManager, - ICollaborativeDrive + ICollaborativeDrive, ], activate: ( app: JupyterFrontEnd, externalCommandRegistry?: IJGISExternalCommandRegistry, jgisTracker?: JupyterGISTracker, yWidgetManager?: IJupyterYWidgetManager, - drive?: ICollaborativeDrive + drive?: ICollaborativeDrive, ): void => { if (!yWidgetManager) { console.error('Missing IJupyterYWidgetManager token!'); @@ -140,10 +140,10 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { if (!drive) { showErrorMessage( 'Error using the JupyterGIS Python API', - 'You cannot use the JupyterGIS Python API without a collaborative drive. You need to install a package providing collaboration features (e.g. jupyter-collaboration).' + 'You cannot use the JupyterGIS Python API without a collaborative drive. You need to install a package providing collaboration features (e.g. jupyter-collaboration).', ); throw new Error( - 'Failed to create the YDoc without a collaborative drive' + 'Failed to create the YDoc without a collaborative drive', ); } @@ -167,14 +167,14 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { } catch (e) { await app.serviceManager.contents.save(localPath, { content: btoa('{}'), - format: 'base64' + format: 'base64', }); } } else { // If the user did not provide a path, do not create localPath = PathExt.join( PathExt.dirname(currentWidgetPath), - 'unsaved_project' + 'unsaved_project', ); } @@ -182,10 +182,10 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { path: localPath, format: fileFormat, contentType, - collaborative: true + collaborative: true, })!; this.jupyterGISModel = new JupyterGISModel({ - sharedModel: sharedModel as IJupyterGISDoc + sharedModel: sharedModel as IJupyterGISDoc, }); this.jupyterGISModel.contentsManager = app.serviceManager.contents; @@ -204,7 +204,7 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { commands: app.commands, model: yModel.jupyterGISModel, externalCommands: externalCommandRegistry, - tracker: jgisTracker + tracker: jgisTracker, }); this._jgisWidget = widget.jgisWidget; @@ -226,7 +226,7 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin = { yWidgetManager.registerWidget( '@jupytergis:widget', YJupyterGISModelFactory, - YJupyterGISWidget + YJupyterGISWidget, ); - } + }, }; diff --git a/python/jupytergis_qgis/src/modelfactory.ts b/python/jupytergis_qgis/src/modelfactory.ts index b804bd3d6..15c70f29e 100644 --- a/python/jupytergis_qgis/src/modelfactory.ts +++ b/python/jupytergis_qgis/src/modelfactory.ts @@ -1,7 +1,7 @@ import { IJupyterGISDoc, JupyterGISModel, - IAnnotationModel + IAnnotationModel, } from '@jupytergis/schema'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; @@ -82,13 +82,13 @@ export class JupyterGISModelFactoryBase * @returns The model */ createNew( - options: DocumentRegistry.IModelOptions + options: DocumentRegistry.IModelOptions, ): JupyterGISModel { const model = new JupyterGISModel({ sharedModel: options.sharedModel, languagePreference: options.languagePreference, annotationModel: this._annotationModel, - settingRegistry: this._settingRegistry + settingRegistry: this._settingRegistry, }); return model; } diff --git a/python/jupytergis_qgis/src/plugins.ts b/python/jupytergis_qgis/src/plugins.ts index 6aa347ade..00008cdec 100644 --- a/python/jupytergis_qgis/src/plugins.ts +++ b/python/jupytergis_qgis/src/plugins.ts @@ -1,12 +1,12 @@ import { ICollaborativeDrive, - SharedDocumentFactory + SharedDocumentFactory, } from '@jupyter/collaborative-drive'; import { JupyterGISDocumentWidget, logoMiniIcon, logoMiniIconQGZ, - requestAPI + requestAPI, } from '@jupytergis/base'; import { JupyterGISDocumentWidgetFactory } from '@jupytergis/jupytergis-core'; import { @@ -16,11 +16,11 @@ import { IJupyterGISDocTracker, IJupyterGISWidget, IAnnotationModel, - IAnnotationToken + IAnnotationToken, } from '@jupytergis/schema'; import { JupyterFrontEnd, - JupyterFrontEndPlugin + JupyterFrontEndPlugin, } from '@jupyterlab/application'; import { Dialog, @@ -29,7 +29,7 @@ import { InputDialog, WidgetTracker, showDialog, - showErrorMessage + showErrorMessage, } from '@jupyterlab/apputils'; import { IEditorServices } from '@jupyterlab/codeeditor'; import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console'; @@ -80,21 +80,21 @@ const activate = async ( consoleTracker: IConsoleTracker, annotationModel: IAnnotationModel, settingRegistry: ISettingRegistry, - commandPalette: ICommandPalette | null + commandPalette: ICommandPalette | null, ): Promise => { const fcCheck = await requestAPI<{ installed: boolean }>( 'jupytergis_qgis/backend-check', { method: 'POST', - body: JSON.stringify({}) - } + body: JSON.stringify({}), + }, ); const { installed } = fcCheck; const backendCheck = () => { if (!installed) { showErrorMessage( 'QGIS is not installed', - 'QGIS is required to open QGIS files' + 'QGIS is required to open QGIS files', ); } return installed; @@ -112,7 +112,7 @@ const activate = async ( contentFactory, rendermime, mimeTypeService: editorServices.mimeTypeService, - consoleTracker + consoleTracker, }); const QGZWidgetFactory = new JupyterGISDocumentWidgetFactory({ name: 'JupyterGIS QGZ Factory', @@ -127,7 +127,7 @@ const activate = async ( contentFactory, rendermime, mimeTypeService: editorServices.mimeTypeService, - consoleTracker + consoleTracker, }); // Registering the widget factory @@ -136,10 +136,10 @@ const activate = async ( // Creating and registering the model factory for our custom DocumentModel app.docRegistry.addModelFactory( - new QGSModelFactory({ annotationModel, settingRegistry }) + new QGSModelFactory({ annotationModel, settingRegistry }), ); app.docRegistry.addModelFactory( - new QGZModelFactory({ annotationModel, settingRegistry }) + new QGZModelFactory({ annotationModel, settingRegistry }), ); // register the filetype app.docRegistry.addFileType({ @@ -149,7 +149,7 @@ const activate = async ( extensions: ['.qgs', '.QGS'], fileFormat: 'base64', contentType: 'QGS', - icon: logoMiniIcon + icon: logoMiniIcon, }); app.docRegistry.addFileType({ name: 'QGZ', @@ -158,7 +158,7 @@ const activate = async ( extensions: ['.qgz', '.QGZ'], fileFormat: 'base64', contentType: 'QGZ', - icon: logoMiniIconQGZ + icon: logoMiniIconQGZ, }); const QGISSharedModelFactory: SharedDocumentFactory = () => { @@ -166,16 +166,16 @@ const activate = async ( }; drive.sharedModelFactory.registerDocumentFactory( 'QGS', - QGISSharedModelFactory + QGISSharedModelFactory, ); drive.sharedModelFactory.registerDocumentFactory( 'QGZ', - QGISSharedModelFactory + QGISSharedModelFactory, ); const widgetCreatedCallback = ( sender: any, - widget: JupyterGISDocumentWidget + widget: JupyterGISDocumentWidget, ) => { widget.title.icon = logoMiniIconQGZ; // Notify the instance tracker if restore data needs to update. @@ -183,7 +183,7 @@ const activate = async ( tracker.save(widget); }); themeManager.themeChanged.connect((_, changes) => - widget.model.themeChanged.emit(changes) + widget.model.themeChanged.emit(changes), ); tracker.add(widget); @@ -222,7 +222,7 @@ const activate = async ( await InputDialog.getText({ label: 'File name', placeholder: PathExt.basename(sourcePath, sourceExtension), - title: 'Export the project to QGZ file' + title: 'Export the project to QGZ file', }) ).value; } @@ -248,7 +248,7 @@ const activate = async ( layers: model.layers, sources: model.sources, layerTree: model.layerTree.slice().reverse(), - options: model.options + options: model.options, }; // Check if the file exists @@ -259,7 +259,7 @@ const activate = async ( if (fileExist) { const overwrite = await showDialog({ title: 'Export the project to QGZ file', - body: `The file ${filepath} already exists.\nDo you want to overwrite it ?` + body: `The file ${filepath} already exists.\nDo you want to overwrite it ?`, }); if (!overwrite.button.accept) { return; @@ -271,16 +271,16 @@ const activate = async ( method: 'POST', body: JSON.stringify({ path: absolutePath, - virtual_file: virtualFile - }) - } + virtual_file: virtualFile, + }), + }, ); if (!response.exported) { showErrorMessage( 'Export the project to QGZ file', response.logs.errors.length ? response.logs.errors.join('\n') - : 'Unknown error' + : 'Unknown error', ); } else if (response.logs.warnings.length) { const bodyElement = document.createElement('pre'); @@ -289,16 +289,16 @@ const activate = async ( await showDialog({ title: 'Export the project to QGZ file', body, - buttons: [Dialog.okButton()] + buttons: [Dialog.okButton()], }); } - } + }, }); if (commandPalette) { commandPalette.addItem({ command: CommandIDs.exportQgis, - category: 'JupyterGIS' + category: 'JupyterGIS', }); } } @@ -318,9 +318,9 @@ export const qgisplugin: JupyterFrontEndPlugin = { IRenderMimeRegistry, IConsoleTracker, IAnnotationToken, - ISettingRegistry + ISettingRegistry, ], optional: [ICommandPalette], autoStart: true, - activate + activate, }; diff --git a/ui-tests/tests/annotations.spec.ts b/ui-tests/tests/annotations.spec.ts index 58d604599..d6d7e8f6a 100644 --- a/ui-tests/tests/annotations.spec.ts +++ b/ui-tests/tests/annotations.spec.ts @@ -8,7 +8,7 @@ test.describe('#annotations', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); test.beforeEach(async ({ page }) => { @@ -27,8 +27,8 @@ test.describe('#annotations', () => { button: 'right', position: { x: 253, - y: 194 - } + y: 194, + }, }); await page.getByText('Add annotation').click(); await page @@ -47,12 +47,12 @@ test.describe('#annotations', () => { // Check map await expect( - page.getByLabel('annotation-test.jGIS').getByRole('paragraph') + page.getByLabel('annotation-test.jGIS').getByRole('paragraph'), ).toContainText('this is a test'); // Check side panel await expect( - page.getByLabel('Annotations', { exact: true }).getByRole('paragraph') + page.getByLabel('Annotations', { exact: true }).getByRole('paragraph'), ).toContainText('this is a test'); // Delete @@ -68,7 +68,7 @@ test.describe('#annotations', () => { .getByLabel('annotation-test.jGIS') .locator('div') .filter({ hasText: /^AHthis is a test$/ }) - .nth(2) + .nth(2), ).not.toBeVisible(); }); }); diff --git a/ui-tests/tests/contextmenu.spec.ts b/ui-tests/tests/contextmenu.spec.ts index b8557f7bc..41e45167e 100644 --- a/ui-tests/tests/contextmenu.spec.ts +++ b/ui-tests/tests/contextmenu.spec.ts @@ -7,7 +7,7 @@ test.describe('context menu', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); test.beforeEach(async ({ page }) => { @@ -77,11 +77,11 @@ test.describe('context menu', () => { }); test('clicking remove layer should remove the layer from the tree', async ({ - page + page, }) => { // Create new layer first await page.getByLabel('Layers', { exact: true }).click({ - button: 'right' + button: 'right', }); await page.getByText('Add Layer').hover(); await page.getByText('Add Raster Layer', { exact: true }).hover(); @@ -90,7 +90,7 @@ test.describe('context menu', () => { await page .locator('input#root_url') .type( - 'https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}.pbf' + 'https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}.pbf', ); await page.getByRole('dialog').getByRole('button', { name: 'Ok' }).click(); @@ -99,7 +99,7 @@ test.describe('context menu', () => { expect(page.getByText(layerTitle)).toBeVisible(); await page.getByText(layerTitle).click({ - button: 'right' + button: 'right', }); await page.getByRole('menu').getByText('Remove Layer').click(); @@ -108,7 +108,7 @@ test.describe('context menu', () => { }); test('clicking remove group should remove the group from the tree', async ({ - page + page, }) => { const firstItem = page .getByLabel('Layers', { exact: true }) diff --git a/ui-tests/tests/export.spec.ts b/ui-tests/tests/export.spec.ts index bc133e003..ffd24ab8e 100644 --- a/ui-tests/tests/export.spec.ts +++ b/ui-tests/tests/export.spec.ts @@ -7,7 +7,7 @@ test.describe('#export', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); @@ -35,7 +35,7 @@ test.describe('#export', () => { await dialog.locator('.jp-mod-reject').click(); await page.filebrowser.refresh(); expect( - await page.filebrowser.contents.fileExists('testDir/france-hiking.qgz') + await page.filebrowser.contents.fileExists('testDir/france-hiking.qgz'), ).toBeFalsy(); }); @@ -48,7 +48,7 @@ test.describe('#export', () => { await dialog.locator('.jp-mod-accept').click(); await page.filebrowser.refresh(); expect( - await page.filebrowser.contents.fileExists('testDir/france-hiking.qgz') + await page.filebrowser.contents.fileExists('testDir/france-hiking.qgz'), ).toBeTruthy(); }); @@ -63,7 +63,7 @@ test.describe('#export', () => { await dialog.locator('.jp-mod-accept').click(); await page.filebrowser.refresh(); expect( - await page.filebrowser.contents.fileExists(`testDir/${filename}.qgz`) + await page.filebrowser.contents.fileExists(`testDir/${filename}.qgz`), ).toBeTruthy(); }); }); diff --git a/ui-tests/tests/filters.spec.ts b/ui-tests/tests/filters.spec.ts index 513576cba..ce3cef02a 100644 --- a/ui-tests/tests/filters.spec.ts +++ b/ui-tests/tests/filters.spec.ts @@ -8,7 +8,7 @@ test.describe('#filters', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); test.beforeEach(async ({ page }) => { @@ -42,7 +42,7 @@ test.describe('#filters', () => { expect(await main.screenshot()).toMatchSnapshot({ name: 'two-filter.png', - maxDiffPixelRatio: 0.01 + maxDiffPixelRatio: 0.01, }); // Remove filter @@ -50,7 +50,7 @@ test.describe('#filters', () => { expect(await main.screenshot()).toMatchSnapshot({ name: 'one-filter.png', - maxDiffPixelRatio: 0.01 + maxDiffPixelRatio: 0.01, }); // Clear filters @@ -58,7 +58,7 @@ test.describe('#filters', () => { expect(await main.screenshot()).toMatchSnapshot({ name: 'no-filter.png', - maxDiffPixelRatio: 0.01 + maxDiffPixelRatio: 0.01, }); }); }); diff --git a/ui-tests/tests/geojson-layers.spec.ts b/ui-tests/tests/geojson-layers.spec.ts index 010fef6ef..55bba1f1b 100644 --- a/ui-tests/tests/geojson-layers.spec.ts +++ b/ui-tests/tests/geojson-layers.spec.ts @@ -2,7 +2,7 @@ import { IJupyterLabPageFixture, expect, galata, - test + test, } from '@jupyterlab/galata'; import { Locator } from '@playwright/test'; import path from 'path'; @@ -12,7 +12,7 @@ const FILENAME = 'empty-france.jGIS'; const openGIS = async ( page: IJupyterLabPageFixture, tmpPath: string, - filename: string + filename: string, ): Promise => { const panel = await page.activity.getPanelLocator(filename); if (panel !== null && (await panel.count())) { @@ -21,7 +21,7 @@ const openGIS = async ( await page.filebrowser.open(`/${tmpPath}/${filename}`); await page.waitForCondition( - async () => await page.activity.isTabActive(filename) + async () => await page.activity.isTabActive(filename), ); return (await page.activity.getPanelLocator(filename)) as Locator; }; @@ -31,11 +31,11 @@ test.describe('#geoJSONLayer', () => { const content = galata.newContentsHelper(request); await content.uploadFile( path.resolve(__dirname, `./gis-files/${FILENAME}`), - `/${tmpPath}/${FILENAME}` + `/${tmpPath}/${FILENAME}`, ); await content.uploadFile( path.resolve(__dirname, `./gis-files/france_regions.json`), - `/${tmpPath}/france_regions.json` + `/${tmpPath}/france_regions.json`, ); }); diff --git a/ui-tests/tests/layer-browser.spec.ts b/ui-tests/tests/layer-browser.spec.ts index 3ff768cbc..6ecc4fb72 100644 --- a/ui-tests/tests/layer-browser.spec.ts +++ b/ui-tests/tests/layer-browser.spec.ts @@ -2,7 +2,7 @@ import { IJupyterLabPageFixture, expect, galata, - test + test, } from '@jupyterlab/galata'; import { Locator } from '@playwright/test'; import path from 'path'; @@ -16,8 +16,8 @@ const TEST_REGISTRY = { html_attribution: '© OpenStreetMap contributors', attribution: '(C) OpenStreetMap contributors', - name: 'OpenStreetMap.Mapnik' - } + name: 'OpenStreetMap.Mapnik', + }, }, Strava: { All: { @@ -28,7 +28,7 @@ const TEST_REGISTRY = { 'Map tiles by Strava 2021', html_attribution: 'Map tiles by Strava 2021', - name: 'Strava.All' + name: 'Strava.All', }, Ride: { thumbnailPath: 'rasterlayer_gallery/Strava-Ride.png', @@ -38,7 +38,7 @@ const TEST_REGISTRY = { 'Map tiles by Strava 2021', html_attribution: 'Map tiles by Strava 2021', - name: 'Strava.Ride' + name: 'Strava.Ride', }, Run: { thumbnailPath: 'rasterlayer_gallery/Strava-Run.png', @@ -48,7 +48,7 @@ const TEST_REGISTRY = { 'Map tiles by Strava 2021', html_attribution: 'Map tiles by Strava 2021', - name: 'Strava.Run' + name: 'Strava.Run', }, Water: { thumbnailPath: 'rasterlayer_gallery/Strava-Water.png', @@ -58,7 +58,7 @@ const TEST_REGISTRY = { 'Map tiles by Strava 2021', html_attribution: 'Map tiles by Strava 2021', - name: 'Strava.Water' + name: 'Strava.Water', }, Winter: { thumbnailPath: 'rasterlayer_gallery/Strava-Winter.png', @@ -68,13 +68,13 @@ const TEST_REGISTRY = { 'Map tiles by Strava 2021', html_attribution: 'Map tiles by Strava 2021', - name: 'Strava.Winter' - } - } + name: 'Strava.Winter', + }, + }, }; async function openLayerBrowser( - page: IJupyterLabPageFixture + page: IJupyterLabPageFixture, ): Promise { const layerBrowser = page.locator('#jupytergis\\:\\:layerBrowser'); @@ -89,7 +89,7 @@ async function getGridTiles(page: IJupyterLabPageFixture): Promise { const layerBrowser = await openLayerBrowser(page); const gridTiles = layerBrowser.locator( - '.jGIS-layer-browser-container .jGIS-layer-browser-grid .jGIS-layer-browser-tile' + '.jGIS-layer-browser-container .jGIS-layer-browser-grid .jGIS-layer-browser-tile', ); return gridTiles; @@ -101,7 +101,7 @@ test.describe('#layerBrowser', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); @@ -127,7 +127,7 @@ test.describe('#layerBrowser', () => { const layerBrowser = await openLayerBrowser(page); const gridTiles = layerBrowser.locator( - '.jGIS-layer-browser-container .jGIS-layer-browser-grid .jGIS-layer-browser-tile' + '.jGIS-layer-browser-container .jGIS-layer-browser-grid .jGIS-layer-browser-tile', ); const numberOfTiles = await gridTiles.count(); @@ -148,7 +148,7 @@ test.describe('#layerBrowser', () => { }); test('clicking category filter twice should clear filter', async ({ - page + page, }) => { const gridTiles = await getGridTiles(page); const numberOfTiles = await gridTiles.count(); diff --git a/ui-tests/tests/left-panel.spec.ts b/ui-tests/tests/left-panel.spec.ts index 66432e45f..7f948430d 100644 --- a/ui-tests/tests/left-panel.spec.ts +++ b/ui-tests/tests/left-panel.spec.ts @@ -2,7 +2,7 @@ import { IJupyterLabPageFixture, expect, galata, - test + test, } from '@jupyterlab/galata'; import { Locator } from '@playwright/test'; import path from 'path'; @@ -29,7 +29,7 @@ async function openLayerTree(page: IJupyterLabPageFixture): Promise { } async function getOpenLayerIds( - page: IJupyterLabPageFixture + page: IJupyterLabPageFixture, ): Promise { return await page.evaluate(() => { const olMap = Object.values(window.jupytergisMaps)[0]; @@ -41,7 +41,7 @@ async function getOpenLayerIds( } async function getOpenLayerVisibility( - page: IJupyterLabPageFixture + page: IJupyterLabPageFixture, ): Promise { return await page.evaluate(() => { const olMap = Object.values(window.jupytergisMaps)[0]; @@ -80,7 +80,7 @@ test.describe('#layerPanel', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); test.beforeEach(async ({ page }) => { @@ -105,18 +105,18 @@ test.describe('#layerPanel', () => { test('raster layer should have icons', async ({ page }) => { const layerTree = await openLayerTree(page); const layerIcons = layerTree.locator( - '.jp-gis-layer .jp-gis-layerIcon svg' + '.jp-gis-layer .jp-gis-layerIcon svg', ); const visToggleIcon = layerIcons.nth(0); const rasterIcon = layerIcons.nth(1); await expect(visToggleIcon).toHaveAttribute( 'data-icon', - 'jupytergis::visibility' + 'jupytergis::visibility', ); await expect(rasterIcon).toHaveAttribute( 'data-icon', - 'jupytergis::raster' + 'jupytergis::raster', ); }); @@ -177,7 +177,7 @@ test.describe('#layerPanel', () => { // Wait for the map to be loaded; await page.waitForCondition( - async () => (await getOpenLayerIds(page)).length === 3 + async () => (await getOpenLayerIds(page)).length === 3, ); // Wait for the map to be displayed. @@ -230,7 +230,7 @@ test.describe('#layerPanel', () => { await page.mouse.move( firstItemBox!.x + 10, - firstItemBox!.y + firstItemBox!.height - 10 + firstItemBox!.y + firstItemBox!.height - 10, ); // We need to force hover await layerItems @@ -242,7 +242,7 @@ test.describe('#layerPanel', () => { }); test('should move the top raster layer using drag and drop', async ({ - page + page, }) => { const layerTree = await openLayerTree(page); const layers = layerTree.locator('.jp-gis-layer'); @@ -250,7 +250,7 @@ test.describe('#layerPanel', () => { // Wait for the map to be loaded; await page.waitForCondition( - async () => (await getOpenLayerIds(page)).length === 3 + async () => (await getOpenLayerIds(page)).length === 3, ); const layerIds = await getOpenLayerIds(page); @@ -265,7 +265,7 @@ test.describe('#layerPanel', () => { await page.mouse.down(); await page.mouse.move( lowLayerBox!.x + 10, - lowLayerBox!.y + lowLayerBox!.height + 10 + lowLayerBox!.y + lowLayerBox!.height + 10, ); await page.mouse.up(); diff --git a/ui-tests/tests/lite.spec.ts b/ui-tests/tests/lite.spec.ts index 565794e5f..8990de604 100644 --- a/ui-tests/tests/lite.spec.ts +++ b/ui-tests/tests/lite.spec.ts @@ -11,7 +11,7 @@ test.describe('UI Test', () => { test.beforeEach(async ({ page }) => { const unrelatedErrors = [ // This error is related to plotly dependency, installed with qgis. - "@jupyter-widgets/base doesn't exist in shared scope default" + "@jupyter-widgets/base doesn't exist in shared scope default", ]; page.setViewportSize({ width: 1920, height: 1080 }); page.on('console', message => { @@ -33,13 +33,13 @@ test.describe('UI Test', () => { for (const file of fileList) { test(`Should be able to render ${file} without error`, async ({ - browser + browser, }) => { const context = await browser.newContext(); const page = await context.newPage(); await page.goto(`lab/index.html?path=${file}`, { - waitUntil: 'domcontentloaded' + waitUntil: 'domcontentloaded', }); await page.locator('div.jGIS-Spinner').waitFor({ state: 'hidden' }); @@ -49,7 +49,7 @@ test.describe('UI Test', () => { } const main = await page.waitForSelector('.jp-MainAreaWidget', { - state: 'visible' + state: 'visible', }); await page.waitForTimeout(10000); @@ -58,7 +58,7 @@ test.describe('UI Test', () => { if (main) { expect(await main.screenshot()).toMatchSnapshot({ name: `Render-${file}.png`, - maxDiffPixelRatio: 0.01 + maxDiffPixelRatio: 0.01, }); } }); @@ -69,11 +69,11 @@ test.describe('UI Test', () => { const context = await browser.newContext(); const page = await context.newPage(); await page.goto('lab/index.html?path=jgis.ipynb', { - waitUntil: 'domcontentloaded' + waitUntil: 'domcontentloaded', }); const Notebook = await page.waitForSelector('.jp-Notebook', { - state: 'visible' + state: 'visible', }); await Notebook.click(); @@ -87,15 +87,15 @@ test.describe('UI Test', () => { const jgisWidget = await page.waitForSelector( '.jupytergis-notebook-widget', { - state: 'visible' - } + state: 'visible', + }, ); await page.waitForTimeout(10000); expect(await jgisWidget.screenshot()).toMatchSnapshot({ name: 'Render-notebook.png', - maxDiffPixelRatio: 0.01 + maxDiffPixelRatio: 0.01, }); }); }); diff --git a/ui-tests/tests/notebook.spec.ts b/ui-tests/tests/notebook.spec.ts index 01c05095a..7b8321419 100644 --- a/ui-tests/tests/notebook.spec.ts +++ b/ui-tests/tests/notebook.spec.ts @@ -7,7 +7,7 @@ const FILENAME = 'eq.json'; const testCellOutputs = async ( page: IJupyterLabPageFixture, tmpPath: string, - theme: 'JupyterLab Light' | 'JupyterLab Dark' + theme: 'JupyterLab Light' | 'JupyterLab Dark', ) => { const paths = klaw(path.resolve(__dirname, './notebooks'), { nodir: true }); const notebooks = paths.map(item => path.basename(item.path)); @@ -30,7 +30,7 @@ const testCellOutputs = async ( const getCaptureImageName = ( contextPrefix: string, notebook: string, - id: number + id: number, ): string => { return `${contextPrefix}-${notebook}-cell-${id}.png`; }; @@ -44,12 +44,12 @@ const testCellOutputs = async ( results.push(await cell.screenshot()); numCellImages++; } - } + }, }); for (let c = 0; c < numCellImages; ++c) { expect(results[c]).toMatchSnapshot( - getCaptureImageName(contextPrefix, notebook, c) + getCaptureImageName(contextPrefix, notebook, c), ); } @@ -65,25 +65,25 @@ test.describe('Notebook API Visual Regression', () => { await page.contents.uploadDirectory( path.resolve(__dirname, './notebooks'), - tmpPath + tmpPath, ); await page.contents.uploadFile( path.resolve(__dirname, `./gis-files/${FILENAME}`), - `/${tmpPath}/${FILENAME}` + `/${tmpPath}/${FILENAME}`, ); await page.filebrowser.openDirectory(tmpPath); }); test('Light theme: Cell outputs should be correct', async ({ page, - tmpPath + tmpPath, }) => { await testCellOutputs(page, tmpPath, 'JupyterLab Light'); }); test('Dark theme: Cell outputs should be correct', async ({ page, - tmpPath + tmpPath, }) => { await testCellOutputs(page, tmpPath, 'JupyterLab Dark'); }); diff --git a/ui-tests/tests/ui.spec.ts b/ui-tests/tests/ui.spec.ts index 2953e8257..7a7dbced9 100644 --- a/ui-tests/tests/ui.spec.ts +++ b/ui-tests/tests/ui.spec.ts @@ -12,14 +12,14 @@ test.describe('UI Test', () => { await content.deleteDirectory('/testDir'); await content.uploadDirectory( path.resolve(__dirname, './gis-files'), - '/testDir' + '/testDir', ); }); let errors = 0; test.beforeEach(async ({ page }) => { const unrelatedErrors = [ // This error is related to plotly dependency, installed with qgis. - "@jupyter-widgets/base doesn't exist in shared scope default" + "@jupyter-widgets/base doesn't exist in shared scope default", ]; page.setViewportSize({ width: 1920, height: 1080 }); page.on('console', message => { @@ -41,7 +41,7 @@ test.describe('UI Test', () => { for (const file of fileList) { test(`Should be able to render ${file} without error`, async ({ - page + page, }) => { await page.goto(); const fullPath = `testDir/${file}`; From d88bdefccd0ead3a4b04e1fbdf3a76973bb55c2d Mon Sep 17 00:00:00 2001 From: Gauss-Taylor-Euler <137942464+Gauss-Taylor-Euler@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:50:04 +0200 Subject: [PATCH 05/17] Solving https://github.com/geojupyter/jupytergis/issues/461 (#736) --- packages/base/src/panelview/leftpanel.tsx | 13 +++++++++++++ packages/base/src/panelview/rightpanel.tsx | 9 +++++++++ packages/schema/src/interfaces.ts | 2 ++ packages/schema/src/model.ts | 8 ++++++++ python/jupytergis_core/src/factory.ts | 3 +++ 5 files changed, 35 insertions(+) diff --git a/packages/base/src/panelview/leftpanel.tsx b/packages/base/src/panelview/leftpanel.tsx index 57d7564db..81b35e019 100644 --- a/packages/base/src/panelview/leftpanel.tsx +++ b/packages/base/src/panelview/leftpanel.tsx @@ -1,4 +1,5 @@ import { + IJupyterGISModel, IJupyterGISTracker, ISelection, JupyterGISDoc, @@ -67,11 +68,21 @@ export class LeftPanelWidget extends SidePanel { filterPanel.title.label = 'Filters'; this.addWidget(filterPanel); + this._handleFileChange = () => { + header.title.label = this._currentModel?.filePath || '-'; + }; + options.tracker.currentChanged.connect((_, changed) => { if (changed) { + if (this._currentModel) { + this._currentModel.pathChanged.disconnect(this._handleFileChange); + } + this._currentModel = changed.model; header.title.label = changed.model.filePath; + this._currentModel.pathChanged.connect(this._handleFileChange); } else { header.title.label = '-'; + this._currentModel = null; } }); } @@ -199,6 +210,8 @@ export class LeftPanelWidget extends SidePanel { this._commands.notifyCommandChanged(CommandIDs.temporalController); } + private _handleFileChange: () => void; + private _currentModel: IJupyterGISModel | null; private _lastSelectedNodeId: string; private _model: IControlPanelModel; private _state: IStateDB; diff --git a/packages/base/src/panelview/rightpanel.tsx b/packages/base/src/panelview/rightpanel.tsx index 758e9a023..49d985c25 100644 --- a/packages/base/src/panelview/rightpanel.tsx +++ b/packages/base/src/panelview/rightpanel.tsx @@ -48,6 +48,10 @@ export class RightPanelWidget extends SidePanel { identifyPanel.addClass('jgis-scrollable'); this.addWidget(identifyPanel); + this._handleFileChange = () => { + header.title.label = this._currentModel?.filePath || '-'; + }; + this._model.documentChanged.connect((_, changed) => { if (changed) { if (changed.model.sharedModel.editable) { @@ -64,8 +68,12 @@ export class RightPanelWidget extends SidePanel { options.tracker.currentChanged.connect(async (_, changed) => { if (changed) { + if (this._currentModel) { + this._currentModel.pathChanged.disconnect(this._handleFileChange); + } this._currentModel = changed.model; header.title.label = this._currentModel.filePath; + this._currentModel.pathChanged.connect(this._handleFileChange); this._annotationModel.model = options.tracker.currentWidget?.model || undefined; // await changed.context.ready; @@ -82,6 +90,7 @@ export class RightPanelWidget extends SidePanel { } private _currentModel: IJupyterGISModel | null; + private _handleFileChange: () => void; private _model: IControlPanelModel; private _annotationModel: IAnnotationModel; } diff --git a/packages/schema/src/interfaces.ts b/packages/schema/src/interfaces.ts index b11785a27..0f931df73 100644 --- a/packages/schema/src/interfaces.ts +++ b/packages/schema/src/interfaces.ts @@ -183,6 +183,8 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel { contentsManager: Contents.IManager | undefined; filePath: string; + pathChanged: ISignal; + getSettings(): IJupyterGISSettings; getContent(): IJGISContent; getLayers(): IJGISLayers; diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index f87f0b147..b77086578 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -56,6 +56,7 @@ export class JupyterGISModel implements IJupyterGISModel { ); this.annotationModel = annotationModel; this.settingRegistry = settingRegistry; + this._pathChanged = new Signal(this); } /** @@ -103,6 +104,10 @@ export class JupyterGISModel implements IJupyterGISModel { return this._stateChanged; } + get pathChanged(): ISignal { + return this._pathChanged; + } + get themeChanged(): Signal< this, IChangedArgs @@ -316,6 +321,7 @@ export class JupyterGISModel implements IJupyterGISModel { */ set filePath(path: string) { this._filePath = path; + this._pathChanged.emit(path); } getLayers(): IJGISLayers { @@ -762,6 +768,8 @@ export class JupyterGISModel implements IJupyterGISModel { private _userChanged = new Signal(this); private _usersMap?: Map; + private _pathChanged: Signal; + private _disposed = new Signal(this); private _contentChanged = new Signal(this); private _stateChanged = new Signal>(this); diff --git a/python/jupytergis_core/src/factory.ts b/python/jupytergis_core/src/factory.ts index 2e3b04732..a1a16979e 100644 --- a/python/jupytergis_core/src/factory.ts +++ b/python/jupytergis_core/src/factory.ts @@ -59,6 +59,9 @@ export class JupyterGISDocumentWidgetFactory extends ABCWidgetFactory< } const { model } = context; model.filePath = context.localPath; + context.pathChanged.connect(() => { + model.filePath = context.localPath; + }); if (this._contentsManager) { model.contentsManager = this._contentsManager; } From 79292a36341719b34e49f576972db3d4b21e1832 Mon Sep 17 00:00:00 2001 From: Gauss-Taylor-Euler <137942464+Gauss-Taylor-Euler@users.noreply.github.com> Date: Fri, 6 Jun 2025 23:21:28 +0200 Subject: [PATCH 06/17] Processing: Centroids of a vector layer (#740) --- packages/base/src/commands.ts | 28 +++++++++++++++++++ packages/base/src/constants.ts | 1 + .../base/src/dialogs/ProcessingFormDialog.tsx | 3 +- packages/base/src/processing.ts | 7 +++-- .../src/schema/processing/centroids.json | 13 +++++++++ packages/schema/src/types.ts | 1 + .../jupytergis_core/src/jgisplugin/plugins.ts | 10 +++++++ python/jupytergis_lab/src/index.ts | 4 +++ 8 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 packages/schema/src/schema/processing/centroids.json diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 7e3f627cc..14209cb0f 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -381,6 +381,34 @@ export function addCommands( ); }, }); + commands.addCommand(CommandIDs.centroids, { + label: trans.__('Centroids'), + isEnabled: () => selectedLayerIsOfType(['VectorLayer'], tracker), + execute: async () => { + await processSelectedLayer( + tracker, + formSchemaRegistry, + 'Centroids', + { + sqlQueryFn: (layerName, _) => ` + SELECT ST_Centroid(geometry) AS geometry, * + FROM "${layerName}" + `, + gdalFunction: 'ogr2ogr', + options: (sqlQuery: string) => [ + '-f', + 'GeoJSON', + '-dialect', + 'SQLITE', + '-sql', + sqlQuery, + 'output.geojson', + ], + }, + app, + ); + }, + }); commands.addCommand(CommandIDs.newGeoJSONEntry, { label: trans.__('New GeoJSON layer'), diff --git a/packages/base/src/constants.ts b/packages/base/src/constants.ts index 9506c768c..46e3ce234 100644 --- a/packages/base/src/constants.ts +++ b/packages/base/src/constants.ts @@ -40,6 +40,7 @@ export namespace CommandIDs { // Processing commands export const buffer = 'jupytergis:buffer'; export const dissolve = 'jupytergis:dissolve'; + export const centroids = 'jupytergis:centroids'; // Layer and group actions export const renameLayer = 'jupytergis:renameLayer'; diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 81d191cf9..04e47da69 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -22,7 +22,7 @@ export interface IProcessingFormDialogOptions extends IBaseFormProps { parentType: 'dialog' | 'panel', ) => void; model: IJupyterGISModel; - processingType: 'Buffer' | 'Dissolve' | 'Export'; + processingType: 'Buffer' | 'Dissolve' | 'Export' | 'Centroids'; } /** @@ -56,6 +56,7 @@ const ProcessingFormWrapper = (props: IProcessingFormWrapperProps) => { break; case 'Buffer': case 'Export': + case 'Centroids': default: FormComponent = BaseForm; } diff --git a/packages/base/src/processing.ts b/packages/base/src/processing.ts index c5d693eb6..fe588d4d7 100644 --- a/packages/base/src/processing.ts +++ b/packages/base/src/processing.ts @@ -91,7 +91,7 @@ export type GdalFunctions = export async function processSelectedLayer( tracker: JupyterGISTracker, formSchemaRegistry: IJGISFormSchemaRegistry, - processingType: 'Buffer' | 'Dissolve', + processingType: 'Buffer' | 'Dissolve' | 'Centroids', processingOptions: { sqlQueryFn: (layerName: string, param: any) => string; gdalFunction: GdalFunctions; @@ -151,6 +151,9 @@ export async function processSelectedLayer( case 'Dissolve': processParam = formValues.dissolveField; break; + case 'Centroids': + processParam = null; + break; default: console.error(`Unsupported processing type: ${processingType}`); return; @@ -192,7 +195,7 @@ export async function executeSQLProcessing( gdalFunction: GdalFunctions, options: string[], layerNamePrefix: string, - processingType: 'Buffer' | 'Dissolve', + processingType: 'Buffer' | 'Dissolve' | 'Centroids', embedOutputLayer: boolean, tracker: JupyterGISTracker, app: JupyterFrontEnd, diff --git a/packages/schema/src/schema/processing/centroids.json b/packages/schema/src/schema/processing/centroids.json new file mode 100644 index 000000000..4e6b373a5 --- /dev/null +++ b/packages/schema/src/schema/processing/centroids.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "description": "Centroids", + "title": "ICentroids", + "required": ["inputLayer"], + "additionalProperties": false, + "properties": { + "inputLayer": { + "type": "string", + "description": "The input layer for buffering." + } + } +} diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts index ff7d3b556..fc5ba30c1 100644 --- a/packages/schema/src/types.ts +++ b/packages/schema/src/types.ts @@ -22,6 +22,7 @@ export * from './_interface/project/layers/heatmapLayer'; // Processing export * from './_interface/processing/buffer'; export * from './_interface/processing/dissolve'; +export * from './_interface/processing/centroids'; // exportLayer export * from './_interface/export/exportGeojson'; diff --git a/python/jupytergis_core/src/jgisplugin/plugins.ts b/python/jupytergis_core/src/jgisplugin/plugins.ts index 9ea457c56..95584b7e0 100644 --- a/python/jupytergis_core/src/jgisplugin/plugins.ts +++ b/python/jupytergis_core/src/jgisplugin/plugins.ts @@ -234,6 +234,16 @@ const activate = async ( command: CommandIDs.buffer, category: 'JupyterGIS', }); + + palette.addItem({ + command: CommandIDs.dissolve, + category: 'JupyterGIS', + }); + + palette.addItem({ + command: CommandIDs.centroids, + category: 'JupyterGIS', + }); } }; diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index 094ad3028..5089e4768 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -157,6 +157,10 @@ const plugin: JupyterFrontEndPlugin = { command: CommandIDs.dissolve, }); + processingSubmenu.addItem({ + command: CommandIDs.centroids, + }); + app.contextMenu.addItem({ type: 'submenu', selector: '.jp-gis-layerItem', From 11d74e5debcc7088b99b481243d7dadf8dfb60be Mon Sep 17 00:00:00 2001 From: martinRenou Date: Mon, 9 Jun 2025 10:09:25 +0200 Subject: [PATCH 07/17] Fix LayoutRestorer entries (#743) --- python/jupytergis_lab/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index 5089e4768..7d17bd821 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -271,8 +271,8 @@ const controlPanel: JupyterFrontEndPlugin = { rightControlPanel.title.icon = logoMiniIcon; if (restorer) { - restorer.add(leftControlPanel, NAME_SPACE); - restorer.add(rightControlPanel, NAME_SPACE); + restorer.add(leftControlPanel, `${NAME_SPACE}-left`); + restorer.add(rightControlPanel, `${NAME_SPACE}-right`); } app.shell.add(leftControlPanel, 'left', { rank: 2000 }); app.shell.add(rightControlPanel, 'right', { rank: 2000 }); From c9491e8e135a00f7a04dc915079992369326687d Mon Sep 17 00:00:00 2001 From: Matthias Meschede Date: Tue, 10 Jun 2025 00:11:37 +0200 Subject: [PATCH 08/17] new feature request template (#746) --- .github/ISSUE_TEMPLATE/4-feature-request.yml | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/4-feature-request.yml diff --git a/.github/ISSUE_TEMPLATE/4-feature-request.yml b/.github/ISSUE_TEMPLATE/4-feature-request.yml new file mode 100644 index 000000000..39f1fbd39 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4-feature-request.yml @@ -0,0 +1,28 @@ +name: '🚀 Feature Request' +description: 'New features you would like to see.' +labels: + - 'enhancement' +body: + - type: 'textarea' + attributes: + label: 'Use case' + description: | + Please describe for which use case this feature would help. + validations: + required: true + + - type: 'textarea' + attributes: + label: 'Preferred solution' + description: | + Please describe your preferred solution if you have any. + validations: + required: false + + - type: 'textarea' + attributes: + label: 'Alternative solutions' + description: | + Please describe alternative solutions if you have any. + validations: + required: false From e2d915f55481a7da836cfe9b61270efe758e9e0c Mon Sep 17 00:00:00 2001 From: Gauss-Taylor-Euler <137942464+Gauss-Taylor-Euler@users.noreply.github.com> Date: Tue, 10 Jun 2025 00:12:54 +0200 Subject: [PATCH 09/17] Processing: Bounding boxes of a vector layer(#734) (#744) * Processing: Bounding boxes of a vector layer(#734) * Change Bounding Boxes and Centroids labels to correspond to qgis naming convention --- packages/base/src/commands.ts | 29 +++++++++++++++++++ packages/base/src/constants.ts | 1 + .../base/src/dialogs/ProcessingFormDialog.tsx | 8 ++++- packages/base/src/processing.ts | 7 +++-- .../src/schema/processing/boundingBoxes.json | 13 +++++++++ .../src/schema/processing/centroids.json | 2 +- packages/schema/src/types.ts | 1 + .../jupytergis_core/src/jgisplugin/plugins.ts | 5 ++++ python/jupytergis_lab/src/index.ts | 4 +++ 9 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 packages/schema/src/schema/processing/boundingBoxes.json diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 14209cb0f..8b25b15ea 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -410,6 +410,35 @@ export function addCommands( }, }); + commands.addCommand(CommandIDs.boundingBoxes, { + label: trans.__('Bounding Boxes'), + isEnabled: () => selectedLayerIsOfType(['VectorLayer'], tracker), + execute: async () => { + await processSelectedLayer( + tracker, + formSchemaRegistry, + 'BoundingBoxes', + { + sqlQueryFn: (layerName, _) => ` + SELECT ST_Envelope(geometry) AS geometry, * + FROM "${layerName}" + `, + gdalFunction: 'ogr2ogr', + options: (sqlQuery: string) => [ + '-f', + 'GeoJSON', + '-dialect', + 'SQLITE', + '-sql', + sqlQuery, + 'output.geojson', + ], + }, + app, + ); + }, + }); + commands.addCommand(CommandIDs.newGeoJSONEntry, { label: trans.__('New GeoJSON layer'), isEnabled: () => { diff --git a/packages/base/src/constants.ts b/packages/base/src/constants.ts index 46e3ce234..608912a96 100644 --- a/packages/base/src/constants.ts +++ b/packages/base/src/constants.ts @@ -41,6 +41,7 @@ export namespace CommandIDs { export const buffer = 'jupytergis:buffer'; export const dissolve = 'jupytergis:dissolve'; export const centroids = 'jupytergis:centroids'; + export const boundingBoxes = 'jupytergis:boundingBoxes'; // Layer and group actions export const renameLayer = 'jupytergis:renameLayer'; diff --git a/packages/base/src/dialogs/ProcessingFormDialog.tsx b/packages/base/src/dialogs/ProcessingFormDialog.tsx index 04e47da69..50aef6920 100644 --- a/packages/base/src/dialogs/ProcessingFormDialog.tsx +++ b/packages/base/src/dialogs/ProcessingFormDialog.tsx @@ -22,7 +22,12 @@ export interface IProcessingFormDialogOptions extends IBaseFormProps { parentType: 'dialog' | 'panel', ) => void; model: IJupyterGISModel; - processingType: 'Buffer' | 'Dissolve' | 'Export' | 'Centroids'; + processingType: + | 'Buffer' + | 'Dissolve' + | 'Export' + | 'Centroids' + | 'BoundingBoxes'; } /** @@ -57,6 +62,7 @@ const ProcessingFormWrapper = (props: IProcessingFormWrapperProps) => { case 'Buffer': case 'Export': case 'Centroids': + case 'BoundingBoxes': default: FormComponent = BaseForm; } diff --git a/packages/base/src/processing.ts b/packages/base/src/processing.ts index fe588d4d7..16284559b 100644 --- a/packages/base/src/processing.ts +++ b/packages/base/src/processing.ts @@ -91,7 +91,7 @@ export type GdalFunctions = export async function processSelectedLayer( tracker: JupyterGISTracker, formSchemaRegistry: IJGISFormSchemaRegistry, - processingType: 'Buffer' | 'Dissolve' | 'Centroids', + processingType: 'Buffer' | 'Dissolve' | 'Centroids' | 'BoundingBoxes', processingOptions: { sqlQueryFn: (layerName: string, param: any) => string; gdalFunction: GdalFunctions; @@ -154,6 +154,9 @@ export async function processSelectedLayer( case 'Centroids': processParam = null; break; + case 'BoundingBoxes': + processParam = null; + break; default: console.error(`Unsupported processing type: ${processingType}`); return; @@ -195,7 +198,7 @@ export async function executeSQLProcessing( gdalFunction: GdalFunctions, options: string[], layerNamePrefix: string, - processingType: 'Buffer' | 'Dissolve' | 'Centroids', + processingType: 'Buffer' | 'Dissolve' | 'Centroids' | 'BoundingBoxes', embedOutputLayer: boolean, tracker: JupyterGISTracker, app: JupyterFrontEnd, diff --git a/packages/schema/src/schema/processing/boundingBoxes.json b/packages/schema/src/schema/processing/boundingBoxes.json new file mode 100644 index 000000000..17074c709 --- /dev/null +++ b/packages/schema/src/schema/processing/boundingBoxes.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "description": "BoundingBoxes", + "title": "IBoundingBoxes", + "required": ["inputLayer"], + "additionalProperties": false, + "properties": { + "inputLayer": { + "type": "string", + "description": "The input layer for bounding boxes." + } + } +} diff --git a/packages/schema/src/schema/processing/centroids.json b/packages/schema/src/schema/processing/centroids.json index 4e6b373a5..383152699 100644 --- a/packages/schema/src/schema/processing/centroids.json +++ b/packages/schema/src/schema/processing/centroids.json @@ -7,7 +7,7 @@ "properties": { "inputLayer": { "type": "string", - "description": "The input layer for buffering." + "description": "The input layer for centroids." } } } diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts index fc5ba30c1..7c49464da 100644 --- a/packages/schema/src/types.ts +++ b/packages/schema/src/types.ts @@ -23,6 +23,7 @@ export * from './_interface/project/layers/heatmapLayer'; export * from './_interface/processing/buffer'; export * from './_interface/processing/dissolve'; export * from './_interface/processing/centroids'; +export * from './_interface/processing/boundingBoxes'; // exportLayer export * from './_interface/export/exportGeojson'; diff --git a/python/jupytergis_core/src/jgisplugin/plugins.ts b/python/jupytergis_core/src/jgisplugin/plugins.ts index 95584b7e0..e669b58a5 100644 --- a/python/jupytergis_core/src/jgisplugin/plugins.ts +++ b/python/jupytergis_core/src/jgisplugin/plugins.ts @@ -244,6 +244,11 @@ const activate = async ( command: CommandIDs.centroids, category: 'JupyterGIS', }); + + palette.addItem({ + command: CommandIDs.boundingBoxes, + category: 'JupyterGIS', + }); } }; diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index 7d17bd821..ec34eb6e9 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -161,6 +161,10 @@ const plugin: JupyterFrontEndPlugin = { command: CommandIDs.centroids, }); + processingSubmenu.addItem({ + command: CommandIDs.boundingBoxes, + }); + app.contextMenu.addItem({ type: 'submenu', selector: '.jp-gis-layerItem', From 14f95307ac8fcbbee956b037ac865a4c33ddafff Mon Sep 17 00:00:00 2001 From: Greg Mooney Date: Wed, 11 Jun 2025 13:59:55 +0200 Subject: [PATCH 10/17] Enhance proxy (#748) * Enhance proxy * Test fix * Use os environ for exempt domains --- .../jupytergis_core/handler.py | 326 ++++++++++++++++-- 1 file changed, 301 insertions(+), 25 deletions(-) diff --git a/python/jupytergis_core/jupytergis_core/handler.py b/python/jupytergis_core/jupytergis_core/handler.py index 3e66160f8..695bdbe51 100644 --- a/python/jupytergis_core/jupytergis_core/handler.py +++ b/python/jupytergis_core/jupytergis_core/handler.py @@ -1,45 +1,321 @@ -from os import environ +import json +import logging +import os +import time +from dataclasses import dataclass +from typing import Any, Dict, Optional, Set +from urllib.parse import urlparse +import tornado from jupyter_server.base.handlers import APIHandler from jupyter_server.utils import url_path_join -import tornado -import requests +from tornado.httpclient import AsyncHTTPClient, HTTPRequest, HTTPResponse + + +@dataclass +class ProxyConfig: + """Configuration for the proxy handler.""" + + default_timeout: int + max_redirects: int + max_body_size: int + rate_limit_requests: int + rate_limit_window: int + cors_origin: str + exempt_domains: Set[str] + + +def load_config() -> ProxyConfig: + """Load configuration from environment variables with defaults.""" + return ProxyConfig( + default_timeout=int(os.environ.get("JGIS_TIMEOUT", "30")), + max_redirects=int(os.environ.get("JGIS_MAX_REDIRECTS", "3")), + max_body_size=int(os.environ.get("JGIS_MAX_BODY_SIZE", str(10 * 1024 * 1024))), + rate_limit_requests=int(os.environ.get("JGIS_RATE_LIMIT_REQUESTS", "100")), + rate_limit_window=int(os.environ.get("JGIS_RATE_LIMIT_WINDOW", "60")), + cors_origin=os.environ.get("JGIS_CORS_ORIGIN", "*"), + exempt_domains=os.environ.get( + "JGIS_EXEMPT_DOMAINS", + { + "https://geodes.cnes.fr", + "https://gdh-portal-prod.cnes.fr", + "https://geodes-portal.cnes.fr/api/stac/", + }, + ), + ) + + +# Configure logging +logger = logging.getLogger(__name__) + + +class ProxyError(Exception): + """Base exception for proxy-related errors.""" + + pass + + +class ValidationError(ProxyError): + """Raised when request validation fails.""" + + pass + + +class RateLimitError(ProxyError): + """Raised when rate limit is exceeded.""" + + pass class ProxyHandler(APIHandler): + """Secure proxy handler with enhanced validation and async processing.""" + + def initialize(self) -> None: + """Initialize the handler with configuration and HTTP client.""" + self.proxy_config = load_config() + self._request_timestamps = [] + self.http_client = AsyncHTTPClient( + defaults={ + "connect_timeout": self.proxy_config.default_timeout, + "request_timeout": self.proxy_config.default_timeout, + "max_redirects": self.proxy_config.max_redirects, + "max_body_size": self.proxy_config.max_body_size, + } + ) + + def _check_rate_limit(self) -> None: + """Check if the current request exceeds rate limits. + + Raises: + RateLimitError: If rate limit is exceeded + """ + current_time = time.time() + window_start = current_time - self.proxy_config.rate_limit_window + + # Remove old timestamps + self._request_timestamps = [ + ts for ts in self._request_timestamps if ts > window_start + ] + + if len(self._request_timestamps) >= self.proxy_config.rate_limit_requests: + raise RateLimitError("Rate limit exceeded") + + self._request_timestamps.append(current_time) + @tornado.web.authenticated - def get(self): - url = self.get_argument("url") - print(f"Proxy request received for: {url}") + async def get(self) -> None: + """Process GET requests with validation and error handling.""" + await self._handle_request("GET") + + @tornado.web.authenticated + async def post(self) -> None: + """Process POST requests with validation and error handling.""" + await self._handle_request("POST") + + async def _handle_request(self, method: str) -> None: + """Central request handling method. + + Args: + method: The HTTP method to use (GET or POST) + + Raises: + tornado.web.HTTPError: If the request fails validation or processing + """ try: - response = requests.get(url) - response.raise_for_status() + # Check rate limit + self._check_rate_limit() + + # Validate and parse input + url = self._validate_url(self.get_argument("url")) + body = await self._validate_body(method) + + logger.info("Proxying %s request to: %s", method, url) + + # Make async HTTP request + response = await self._make_request(url, method, body) + + # Forward response + self._set_response_headers(response) + self.finish(response.body) - self.set_header("Access-Control-Allow-Origin", "*") - self.set_header( - "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" + except RateLimitError as e: + logger.warning("Rate limit exceeded: %s", e) + self.set_status(429) + self.finish( + json.dumps( + { + "error": "Rate limit exceeded", + "code": "rate_limit_error", + "message": str(e), + } + ) ) - self.set_header( - "Access-Control-Allow-Headers", - "X-Requested-With, Content-Type, Authorization", + + except ValidationError as e: + logger.warning("Validation error: %s", e) + self.set_status(400) + self.finish( + json.dumps( + { + "error": "Validation error", + "code": "validation_error", + "message": str(e), + } + ) ) - self.set_header("Content-Type", response.headers["Content-Type"]) + except tornado.web.HTTPError as e: + logger.warning("Client error: %s", e) + raise - self.finish(response.content) - except requests.exceptions.RequestException as e: - self.set_status(500) - self.finish(str(e)) + except Exception as e: + logger.exception("Proxy request failed") + self._handle_error_response(e) + def _validate_url(self, url: str) -> str: + """Validate and sanitize target URL. -def setup_handlers(web_app): - host_pattern = ".*$" + Args: + url: The URL to validate + + Returns: + The validated URL + + Raises: + ValidationError: If the URL is invalid + """ + parsed = urlparse(url) + + if parsed.scheme not in ("http", "https"): + raise ValidationError("Invalid protocol") + + return url + + async def _validate_body(self, method: str) -> Optional[str]: + """Validate and prepare request body. + + Args: + method: The HTTP method being used + + Returns: + The validated and prepared request body, or None for GET requests + + Raises: + ValidationError: If the body is invalid + """ + if method == "POST": + try: + body = self.get_json_body() + if not body or not isinstance(body, Dict): + raise ValidationError("Invalid JSON body") + + # Validate body size + body_str = json.dumps(body) + if len(body_str.encode("utf-8")) > self.proxy_config.max_body_size: + raise ValidationError("Request body too large") + + return body_str + except json.JSONDecodeError as e: + raise ValidationError("Malformed JSON payload") from e + + return None + + async def _make_request( + self, url: str, method: str, body: Optional[str] = None + ) -> HTTPResponse: + """Execute proxy request with safety controls. + + Args: + url: The target URL + method: The HTTP method to use + body: Optional request body + + Returns: + The HTTP response + + Raises: + tornado.web.HTTPError: If the request fails + """ + try: + parsed_url = urlparse(url) + host = parsed_url.netloc.split(":")[0] # Remove port if present + + # Disable SSL verification for exempt domains + validate_cert = host not in self.proxy_config.exempt_domains + logger.info("validate_cert: %s", validate_cert) + + request = HTTPRequest( + url=url, + method=method, + body=body, + headers={"Content-Type": "application/json"} if body else None, + validate_cert=validate_cert, + allow_nonstandard_methods=False, + decompress_response=True, + ) + + return await self.http_client.fetch(request) + + except tornado.httpclient.HTTPClientError as e: + logger.error("Upstream error: %d %s", e.code, e.message) + raise tornado.web.HTTPError(e.code, "Upstream service error") from e + + except tornado.httpclient.HTTPError as e: + logger.error("Network error: %s", str(e)) + raise tornado.web.HTTPError(503, "Service unavailable") from e + + def _set_response_headers(self, response: HTTPResponse) -> None: + """Set secure CORS and content headers. + + Args: + response: The HTTP response to get headers from + """ + self.set_header("Access-Control-Allow-Origin", self.proxy_config.cors_origin) + self.set_header("Access-Control-Allow-Methods", "GET, POST") + self.set_header( + "Access-Control-Allow-Headers", + "Content-Type, Authorization, X-Requested-With", + ) + self.set_header("Content-Security-Policy", "default-src 'none'") + self.set_header( + "Content-Type", response.headers.get("Content-Type", "application/json") + ) + def _handle_error_response(self, error: Exception) -> None: + """Standardized error response handling. + + Args: + error: The exception that occurred + """ + self.set_status(500) + self.finish( + json.dumps( + { + "error": "Internal server error", + "code": "internal_error", + "message": str(error), + } + ) + ) + + +def setup_handlers(web_app: Any) -> None: + """Register handlers with configuration validation. + + Args: + web_app: The Jupyter web application instance + """ + host_pattern = ".*$" base_url = web_app.settings["base_url"] - proxy_route_pattern = url_path_join(base_url, "jupytergis_core", "proxy") - print(f"Setting up proxy handler at: {proxy_route_pattern}") - handlers = [(proxy_route_pattern, ProxyHandler)] - if environ.get("JGIS_EXPOSE_MAPS", False): + # Configure proxy route + proxy_route = url_path_join(base_url, "jupytergis_core", "proxy") + handlers = [(proxy_route, ProxyHandler)] + + # Add feature flags + if os.environ.get("JGIS_EXPOSE_MAPS", False): + web_app.settings.setdefault("page_config_data", {}) web_app.settings["page_config_data"]["jgis_expose_maps"] = True + web_app.add_handlers(host_pattern, handlers) + logger.info("JupyterGIS proxy endpoint initialized at: %s", proxy_route) From 9ca82818daecd5b1db6815b7febf9b44c6df9eae Mon Sep 17 00:00:00 2001 From: Greg Mooney Date: Wed, 11 Jun 2025 14:13:51 +0200 Subject: [PATCH 11/17] Create shared components (#749) * Create some shared components * Add tabs; Add CSS * Button CSS * Use newer button * Add components for date picker * Add pagination component * Iterate on paginator * Tiny tweaks * Use the correct package.json * lint * Woops * Use jupyter css vars * Add sr-only class * Lint * Clean up --- packages/base/package.json | 9 + .../base/src/shared/components/Button.tsx | 27 + .../base/src/shared/components/Calendar.tsx | 88 ++ .../base/src/shared/components/Pagination.tsx | 112 ++ .../base/src/shared/components/Popover.tsx | 43 + packages/base/src/shared/components/Tabs.tsx | 58 ++ .../src/shared/components/ToggleGroup.tsx | 76 ++ packages/base/src/shared/components/utils.ts | 5 + packages/base/style/base.css | 16 + packages/base/style/shared/button.css | 163 +++ packages/base/style/shared/pagination.css | 167 +++ packages/base/style/shared/popover.css | 53 + packages/base/style/shared/tabs.css | 57 ++ packages/base/style/shared/toggle.css | 85 ++ yarn.lock | 960 ++++++++++++++++-- 15 files changed, 1844 insertions(+), 75 deletions(-) create mode 100644 packages/base/src/shared/components/Button.tsx create mode 100644 packages/base/src/shared/components/Calendar.tsx create mode 100644 packages/base/src/shared/components/Pagination.tsx create mode 100644 packages/base/src/shared/components/Popover.tsx create mode 100644 packages/base/src/shared/components/Tabs.tsx create mode 100644 packages/base/src/shared/components/ToggleGroup.tsx create mode 100644 packages/base/src/shared/components/utils.ts create mode 100644 packages/base/style/shared/button.css create mode 100644 packages/base/style/shared/pagination.css create mode 100644 packages/base/style/shared/popover.css create mode 100644 packages/base/style/shared/tabs.css create mode 100644 packages/base/style/shared/toggle.css diff --git a/packages/base/package.json b/packages/base/package.json index 8600705a0..c13842e5d 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -64,22 +64,31 @@ "@lumino/widgets": "^2.0.0", "@mapbox/vector-tile": "^2.0.3", "@naisutech/react-tree": "^3.0.1", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tabs": "^1.1.12", + "@radix-ui/react-toggle-group": "^1.1.10", "@rjsf/core": "^4.2.0", "@rjsf/validator-ajv8": "^5.23.1", "ajv": "^8.14.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "colormap": "^2.3.2", "d3-color": "^3.1.0", "date-fns": "^4.1.0", "gdal3.js": "^2.8.1", "geojson-vt": "^4.0.2", "geotiff": "^2.1.3", + "lucide-react": "^0.513.0", "ol": "^10.1.0", "ol-pmtiles": "^0.5.0", + "ol-stac": "^1.0.0-rc.10", "pbf": "^4.0.1", "pmtiles": "^3.0.7", "proj4": "^2.14.0", "proj4-list": "^1.0.4", "react": "^18.0.1", + "react-day-picker": "8.10.1", "shpjs": "^6.1.0", "styled-components": "^5.3.6", "three": "^0.135.0", diff --git a/packages/base/src/shared/components/Button.tsx b/packages/base/src/shared/components/Button.tsx new file mode 100644 index 000000000..5f31dd039 --- /dev/null +++ b/packages/base/src/shared/components/Button.tsx @@ -0,0 +1,27 @@ +import { Slot } from '@radix-ui/react-slot'; +import * as React from 'react'; + +interface IButtonProps extends React.ButtonHTMLAttributes { + asChild?: boolean; + variant?: 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'icon'; + size?: 'sm' | 'lg' | 'icon'; +} + +const Button = React.forwardRef( + ({ variant, className, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + }, +); +Button.displayName = 'Button'; + +export { Button }; +export type { IButtonProps as ButtonProps }; diff --git a/packages/base/src/shared/components/Calendar.tsx b/packages/base/src/shared/components/Calendar.tsx new file mode 100644 index 000000000..1c0851018 --- /dev/null +++ b/packages/base/src/shared/components/Calendar.tsx @@ -0,0 +1,88 @@ +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import * as React from 'react'; +import { DayPicker } from 'react-day-picker'; +import 'react-day-picker/dist/style.css'; + +export type CalendarProps = React.ComponentProps; + +function Calendar({ showOutsideDays = true, ...props }: CalendarProps) { + return ( + , + IconRight: ({ ...props }) => , + }} + modifiersStyles={{ + selected: { + backgroundColor: 'var(--jp-layout-color2)', + color: 'var(--jp-ui-font-color0)', + borderRadius: '0.275rem', + }, + }} + styles={{ + root: { + width: 'max-content', + margin: 0, + color: 'var(--jp-ui-font-color0)', + background: 'var(--jp-layout-color0)', + border: '1px solid var(--jp-border-color0)', + borderRadius: 'var(--jp-border-radius)', + padding: '0.5rem', + position: 'relative', + }, + table: { + paddingTop: '1rem', + }, + head_cell: { + color: 'var(--jp-ui-font-color0)', + fontSize: '0.8rem', + fontWeight: 400, + }, + day: { + backgroundColor: 'var(--jp-layout-color0)', + display: 'flex', + justifyContent: 'center', + border: 'none', + padding: '0.5rem', + margin: 'auto', + fontSize: '0.8rem', + }, + caption: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + nav_button_previous: { + color: 'var(--jp-ui-font-color0)', + background: 'transparent', + border: '0.5px solid var(--jp-border-color0)', + position: 'absolute', + top: '0.5rem', + left: '0.5rem', + borderRadius: 'var(--jp-border-radius)', + padding: '0.175rem', + width: 'max-content', + height: 'max-content', + }, + nav_button_next: { + color: 'var(--jp-ui-font-color0)', + background: 'transparent', + border: '0.5px solid var(--jp-border-color0)', + position: 'absolute', + top: '0.5rem', + right: '0.5rem', + borderRadius: 'var(--jp-border-radius)', + padding: '0.175rem', + width: 'max-content', + height: 'max-content', + }, + }} + {...props} + /> + ); +} +Calendar.displayName = 'Calendar'; + +export default Calendar; diff --git a/packages/base/src/shared/components/Pagination.tsx b/packages/base/src/shared/components/Pagination.tsx new file mode 100644 index 000000000..c2a97313b --- /dev/null +++ b/packages/base/src/shared/components/Pagination.tsx @@ -0,0 +1,112 @@ +import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'; +import * as React from 'react'; + +import { Button, ButtonProps } from './Button'; + +const Pagination = ({ ...props }: React.ComponentProps<'nav'>) => ( +
+ )}
+ {componentToRender} ); diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx index c68dd6997..5d6c3ca02 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx @@ -8,11 +8,12 @@ import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopCo import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; import { IStopRow, - ISymbologyDialogProps, + ISymbologyTabbedDialogProps, } from '@/src/dialogs/symbology/symbologyDialog'; import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; import { getNumericFeatureAttributes } from '@/src/tools'; +import { SymbologyTab } from '@/src/types'; const Categorized = ({ model, @@ -20,7 +21,8 @@ const Categorized = ({ okSignalPromise, cancel, layerId, -}: ISymbologyDialogProps) => { + symbologyTab, +}: ISymbologyTabbedDialogProps) => { const selectedValueRef = useRef(); const stopRowsRef = useRef(); const colorRampOptionsRef = useRef(); @@ -31,6 +33,13 @@ const Categorized = ({ ReadonlyJSONObject | undefined >(); const [features, setFeatures] = useState>>({}); + const [manualStyle, setManualStyle] = useState({ + fillColor: '#3399CC', + strokeColor: '#3399CC', + strokeWidth: 1.25, + radius: 5, + }); + const manualStyleRef = useRef(manualStyle); if (!layerId) { return; @@ -60,6 +69,42 @@ const Categorized = ({ }; }, []); + useEffect(() => { + if (layer?.parameters?.color) { + const fillColor = layer.parameters.color['fill-color']; + const circleFillColor = layer.parameters.color['circle-fill-color']; + const strokeColor = layer.parameters.color['stroke-color']; + const circleStrokeColor = layer.parameters.color['circle-stroke-color']; + + const isSimpleColor = (val: any) => + typeof val === 'string' && /^#?[0-9A-Fa-f]{3,8}$/.test(val); + + setManualStyle({ + fillColor: isSimpleColor(fillColor) + ? fillColor + : isSimpleColor(circleFillColor) + ? circleFillColor + : '#3399CC', + + strokeColor: isSimpleColor(strokeColor) + ? strokeColor + : isSimpleColor(circleStrokeColor) + ? circleStrokeColor + : '#3399CC', + + strokeWidth: + layer.parameters.color['stroke-width'] || + layer.parameters.color['circle-stroke-width'] || + 1.25, + radius: layer.parameters.color['circle-radius'] || 5, + }); + } + }, [layerId]); + + useEffect(() => { + manualStyleRef.current = manualStyle; + }, [manualStyle]); + useEffect(() => { // We only want number values here const numericFeatures = getNumericFeatureAttributes(featureProperties); @@ -108,23 +153,34 @@ const Categorized = ({ return; } - const colorExpr: ExpressionValue[] = []; - colorExpr.push('case'); + const newStyle = { ...layer.parameters.color }; - stopRowsRef.current?.map(stop => { - colorExpr.push(['==', ['get', selectedValueRef.current], stop.stop]); - colorExpr.push(stop.output); - }); + if (stopRowsRef.current && stopRowsRef.current.length > 0) { + // Classification applied (for color) + const expr: ExpressionValue[] = ['case']; - // fallback value - colorExpr.push([0, 0, 0, 0.0]); + stopRowsRef.current.forEach(stop => { + expr.push(['==', ['get', selectedValueRef.current], stop.stop]); + expr.push(stop.output); + }); - const newStyle = { ...layer.parameters.color }; - newStyle['fill-color'] = colorExpr; + if (symbologyTab === 'color') { + expr.push([0, 0, 0, 0.0]); // fallback color - newStyle['stroke-color'] = colorExpr; + newStyle['fill-color'] = expr; + newStyle['circle-fill-color'] = expr; + newStyle['stroke-color'] = expr; + newStyle['circle-stroke-color'] = expr; + } + } else { + newStyle['fill-color'] = manualStyleRef.current.fillColor; + newStyle['circle-fill-color'] = manualStyleRef.current.fillColor; + } - newStyle['circle-fill-color'] = colorExpr; + newStyle['stroke-width'] = manualStyleRef.current.strokeWidth; + newStyle['circle-stroke-width'] = manualStyleRef.current.strokeWidth; + newStyle['circle-radius'] = manualStyleRef.current.radius; + newStyle['circle-stroke-color'] = manualStyleRef.current.strokeColor; const symbologyState = { renderType: 'Categorized', @@ -132,10 +188,12 @@ const Categorized = ({ colorRamp: colorRampOptionsRef.current?.selectedRamp, nClasses: colorRampOptionsRef.current?.numberOfShades, mode: colorRampOptionsRef.current?.selectedMode, + symbologyTab, }; layer.parameters.symbologyState = symbologyState; layer.parameters.color = newStyle; + if (layer.type === 'HeatmapLayer') { layer.type = 'VectorLayer'; } @@ -144,6 +202,39 @@ const Categorized = ({ cancel(); }; + const handleReset = (method: SymbologyTab) => { + if (!layer?.parameters) { + return; + } + + const newStyle = { ...layer.parameters.color }; + + if (method === 'color') { + console.log('delecol'); + + delete newStyle['fill-color']; + delete newStyle['stroke-color']; + delete newStyle['circle-fill-color']; + delete newStyle['circle-stroke-color']; + setStopRows([]); + + // Reset color classification options + if (layer.parameters.symbologyState) { + layer.parameters.symbologyState.colorRamp = undefined; + layer.parameters.symbologyState.nClasses = undefined; + layer.parameters.symbologyState.mode = undefined; + } + } + + if (method === 'radius') { + delete newStyle['circle-radius']; + } + + layer.parameters.color = newStyle; + + model.sharedModel.updateLayer(layerId, layer); + }; + return (
- - +
+ {/* Inputs depending on active tab */} + {symbologyTab === 'color' && ( + <> +
+ + { + handleReset('color'); + setManualStyle(prev => ({ + ...prev, + fillColor: e.target.value, + })); + }} + /> +
+
+ + { + setManualStyle(prev => ({ + ...prev, + strokeColor: e.target.value, + })); + }} + /> +
+
+ + { + setManualStyle(prev => ({ + ...prev, + strokeWidth: +e.target.value, + })); + }} + /> +
+ + )} + + {symbologyTab === 'radius' && ( +
+ + { + setManualStyle(prev => ({ + ...prev, + radius: +e.target.value, + })); + }} + /> +
+ )} +
+ +
+ + +
); }; diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx index 9aa5515fc..84548d123 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx @@ -10,19 +10,20 @@ import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopCo import { useGetProperties } from '@/src/dialogs/symbology/hooks/useGetProperties'; import { IStopRow, - ISymbologyDialogProps, + ISymbologyTabbedDialogProps, } from '@/src/dialogs/symbology/symbologyDialog'; import { Utils, VectorUtils } from '@/src/dialogs/symbology/symbologyUtils'; import ValueSelect from '@/src/dialogs/symbology/vector_layer/components/ValueSelect'; import { getNumericFeatureAttributes } from '@/src/tools'; -const Graduated = ({ +const Graduated: React.FC = ({ model, state, okSignalPromise, cancel, layerId, -}: ISymbologyDialogProps) => { + symbologyTab, +}) => { const modeOptions = [ 'quantile', 'equal interval', @@ -32,18 +33,29 @@ const Graduated = ({ ]; const selectedValueRef = useRef(); - const selectedMethodRef = useRef(); - const stopRowsRef = useRef(); + const symbologyTabRef = useRef(); + const colorStopRowsRef = useRef([]); + const radiusStopRowsRef = useRef([]); const colorRampOptionsRef = useRef(); const [selectedValue, setSelectedValue] = useState(''); - const [selectedMethod, setSelectedMethod] = useState('color'); - const [stopRows, setStopRows] = useState([]); - const [methodOptions, setMethodOptions] = useState(['color']); const [features, setFeatures] = useState>>({}); + const [colorStopRows, setColorStopRows] = useState([]); + const [radiusStopRows, setRadiusStopRows] = useState([]); const [colorRampOptions, setColorRampOptions] = useState< ColorRampOptions | undefined >(); + const [colorManualStyle, setColorManualStyle] = useState({ + fillColor: '#3399CC', + strokeColor: '#3399CC', + strokeWidth: 1.25, + }); + const [radiusManualStyle, setRadiusManualStyle] = useState({ + radius: 5, + }); + + const colorManualStyleRef = useRef(colorManualStyle); + const radiusManualStyleRef = useRef(radiusManualStyle); if (!layerId) { return; @@ -59,20 +71,7 @@ const Graduated = ({ }); useEffect(() => { - let stopOutputPairs: IStopRow[] = []; - const layerParams = layer.parameters as IVectorLayer; - const method = layerParams.symbologyState?.method ?? 'color'; - - if (method === 'color') { - stopOutputPairs = VectorUtils.buildColorInfo(layer); - } - - if (method === 'radius') { - stopOutputPairs = VectorUtils.buildRadiusInfo(layer); - } - updateStopRowsBasedOnMethod(); - - setStopRows(stopOutputPairs); + updateStopRowsBasedOnLayer(); okSignalPromise.promise.then(okSignal => { okSignal.connect(handleOk, this); @@ -86,23 +85,57 @@ const Graduated = ({ }, []); useEffect(() => { - updateStopRowsBasedOnMethod(); - }, [selectedMethod]); + if (layer?.parameters?.color) { + const fillColor = layer.parameters.color['fill-color']; + const circleFillColor = layer.parameters.color['circle-fill-color']; + const strokeColor = layer.parameters.color['stroke-color']; + const circleStrokeColor = layer.parameters.color['circle-stroke-color']; + + const isSimpleColor = (val: any) => + typeof val === 'string' && /^#?[0-9A-Fa-f]{3,8}$/.test(val); + + setColorManualStyle({ + fillColor: isSimpleColor(fillColor) + ? fillColor + : isSimpleColor(circleFillColor) + ? circleFillColor + : '#3399CC', + strokeColor: isSimpleColor(strokeColor) + ? strokeColor + : isSimpleColor(circleStrokeColor) + ? circleStrokeColor + : '#3399CC', + strokeWidth: + layer.parameters.color['stroke-width'] || + layer.parameters.color['circle-stroke-width'] || + 1.25, + }); + setRadiusManualStyle({ + radius: layer.parameters.color['circle-radius'] || 5, + }); + } + }, [layerId]); useEffect(() => { + colorStopRowsRef.current = colorStopRows; + radiusStopRowsRef.current = radiusStopRows; selectedValueRef.current = selectedValue; - selectedMethodRef.current = selectedMethod; - stopRowsRef.current = stopRows; + symbologyTabRef.current = symbologyTab; colorRampOptionsRef.current = colorRampOptions; - }, [selectedValue, selectedMethod, stopRows, colorRampOptions]); + }, [ + colorStopRows, + radiusStopRows, + selectedValue, + symbologyTab, + colorRampOptions, + ]); useEffect(() => { - // Set up method options - if (layer?.parameters?.type === 'circle') { - const options = ['color', 'radius']; - setMethodOptions(options); - } + colorManualStyleRef.current = colorManualStyle; + radiusManualStyleRef.current = radiusManualStyle; + }, [colorManualStyle, radiusManualStyle]); + useEffect(() => { // We only want number values here const numericFeatures = getNumericFeatureAttributes(featureProperties); @@ -111,28 +144,17 @@ const Graduated = ({ const layerParams = layer.parameters as IVectorLayer; const value = layerParams.symbologyState?.value ?? Object.keys(numericFeatures)[0]; - const method = layerParams.symbologyState?.method ?? 'color'; setSelectedValue(value); - setSelectedMethod(method); }, [featureProperties]); - const updateStopRowsBasedOnMethod = () => { + const updateStopRowsBasedOnLayer = () => { if (!layer) { return; } - let stopOutputPairs: IStopRow[] = []; - - if (selectedMethod === 'color') { - stopOutputPairs = VectorUtils.buildColorInfo(layer); - } - - if (selectedMethod === 'radius') { - stopOutputPairs = VectorUtils.buildRadiusInfo(layer); - } - - setStopRows(stopOutputPairs); + setColorStopRows(VectorUtils.buildColorInfo(layer)); + setRadiusStopRows(VectorUtils.buildRadiusInfo(layer)); }; const handleOk = () => { @@ -140,41 +162,57 @@ const Graduated = ({ return; } - const colorExpr: ExpressionValue[] = []; - colorExpr.push('interpolate'); - colorExpr.push(['linear']); - colorExpr.push(['get', selectedValueRef.current]); - - stopRowsRef.current?.map(stop => { - colorExpr.push(stop.stop); - colorExpr.push(stop.output); - }); - const newStyle = { ...layer.parameters.color }; - if (selectedMethodRef.current === 'color') { + // Apply color symbology + if (colorStopRowsRef.current.length > 0) { + const colorExpr: ExpressionValue[] = [ + 'interpolate', + ['linear'], + ['get', selectedValueRef.current], + ]; + colorStopRowsRef.current.forEach(stop => { + colorExpr.push(stop.stop); + colorExpr.push(stop.output); + }); newStyle['fill-color'] = colorExpr; - - newStyle['stroke-color'] = colorExpr; - newStyle['circle-fill-color'] = colorExpr; + } else { + newStyle['fill-color'] = undefined; + newStyle['circle-fill-color'] = undefined; } - if (selectedMethodRef.current === 'radius') { - newStyle['circle-radius'] = colorExpr; + newStyle['stroke-color'] = colorManualStyleRef.current.strokeColor; + newStyle['circle-stroke-color'] = colorManualStyleRef.current.strokeColor; + newStyle['stroke-width'] = colorManualStyleRef.current.strokeWidth; + newStyle['circle-stroke-width'] = colorManualStyleRef.current.strokeWidth; + + // Apply radius symbology + if (radiusStopRowsRef.current.length > 0) { + const radiusExpr: ExpressionValue[] = [ + 'interpolate', + ['linear'], + ['get', selectedValueRef.current], + ]; + radiusStopRowsRef.current.forEach(stop => { + radiusExpr.push(stop.stop); + radiusExpr.push(stop.output); + }); + newStyle['circle-radius'] = radiusExpr; + } else { + newStyle['circle-radius'] = radiusManualStyleRef.current.radius; } - const symbologyState = { + layer.parameters.color = newStyle; + layer.parameters.symbologyState = { renderType: 'Graduated', value: selectedValueRef.current, - method: selectedMethodRef.current, + method: symbologyTabRef.current, colorRamp: colorRampOptionsRef.current?.selectedRamp, nClasses: colorRampOptionsRef.current?.numberOfShades, mode: colorRampOptionsRef.current?.selectedMode, }; - layer.parameters.symbologyState = symbologyState; - layer.parameters.color = newStyle; if (layer.type === 'HeatmapLayer') { layer.type = 'VectorLayer'; } @@ -234,20 +272,40 @@ const Graduated = ({ return; } - let stopOutputPairs = []; - if (selectedMethod === 'radius') { - for (let i = 0; i < +numberOfShades; i++) { - stopOutputPairs.push({ stop: stops[i], output: stops[i] }); - } + const stopOutputPairs = + symbologyTab === 'radius' + ? stops.map(v => ({ stop: v, output: v })) + : Utils.getValueColorPairs(stops, selectedRamp, +numberOfShades); + + if (symbologyTab === 'radius') { + setRadiusStopRows(stopOutputPairs); } else { - stopOutputPairs = Utils.getValueColorPairs( - stops, - selectedRamp, - +numberOfShades, - ); + setColorStopRows(stopOutputPairs); + } + }; + + const handleReset = (method: string) => { + if (!layer?.parameters) { + return; + } + + const newStyle = { ...layer.parameters.color }; + + if (method === 'color') { + delete newStyle['fill-color']; + delete newStyle['stroke-color']; + delete newStyle['circle-fill-color']; + setColorStopRows([]); + setColorRampOptions(undefined); } - setStopRows(stopOutputPairs); + if (method === 'radius') { + delete newStyle['circle-radius']; + setRadiusStopRows([]); + } + + layer.parameters.color = newStyle; + model.sharedModel.updateLayer(layerId, layer); }; return ( @@ -257,35 +315,86 @@ const Graduated = ({ selectedValue={selectedValue} setSelectedValue={setSelectedValue} /> -
- - { + handleReset('color'); + setColorManualStyle({ + ...colorManualStyle, + fillColor: e.target.value, + }); + }} + /> +
+
+ + { + setColorManualStyle({ + ...colorManualStyle, + strokeColor: e.target.value, + }); + }} + /> +
+
+ + { + setColorManualStyle({ + ...colorManualStyle, + strokeWidth: +e.target.value, + }); + }} + /> +
+ + )} + {symbologyTab === 'radius' && ( +
+ + - {method} - - ))} - + value={radiusManualStyle.radius} + onChange={e => { + handleReset('radius'); + setRadiusManualStyle({ + ...radiusManualStyle, + radius: +e.target.value, + }); + }} + /> +
+ )}
+ ); diff --git a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx index 30f46dc8a..fa09bbd13 100644 --- a/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx +++ b/packages/base/src/dialogs/symbology/vector_layer/types/SimpleSymbol.tsx @@ -1,7 +1,7 @@ import { FlatStyle } from 'ol/style/flat'; import React, { useEffect, useRef, useState } from 'react'; -import { ISymbologyDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; +import { ISymbologyTabbedDialogProps } from '@/src/dialogs/symbology/symbologyDialog'; import { IParsedStyle, parseColor } from '@/src/tools'; const SimpleSymbol = ({ @@ -10,7 +10,8 @@ const SimpleSymbol = ({ okSignalPromise, cancel, layerId, -}: ISymbologyDialogProps) => { + symbologyTab, +}: ISymbologyTabbedDialogProps) => { const styleRef = useRef(); const [style, setStyle] = useState({ @@ -104,22 +105,8 @@ const SimpleSymbol = ({ cancel(); }; - return ( -
-
- - - setStyle(prevState => ({ - ...prevState, - radius: +event.target.value, - })) - } - /> -
+ const renderColorTab = () => ( + <>
+ + ); + + const renderRadiusTab = () => ( +
+ + setStyle(prev => ({ ...prev, radius: +e.target.value }))} + /> +
+ ); + + return ( +
+ {symbologyTab === 'color' ? renderColorTab() : renderRadiusTab()}
); }; diff --git a/packages/base/src/types.ts b/packages/base/src/types.ts index c64013820..639dd71b0 100644 --- a/packages/base/src/types.ts +++ b/packages/base/src/types.ts @@ -22,6 +22,8 @@ export interface IControlPanelModel { sharedModel: IJupyterGISDoc | undefined; } +export type SymbologyTab = 'color' | 'radius'; + /** * Add jupytergisMaps object to the global variables. */ diff --git a/python/jupytergis_lab/style/base.css b/python/jupytergis_lab/style/base.css index dfe6ecc62..c33a8f9db 100644 --- a/python/jupytergis_lab/style/base.css +++ b/python/jupytergis_lab/style/base.css @@ -790,3 +790,46 @@ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child { cursor: not-allowed; pointer-events: auto; } + +.jp-gis-stop-container-wrapper { + display: flex; + flex-direction: row; + gap: 2rem; +} + +.jp-gis-stop-container-wrapper > * { + flex: 1; +} + +.jp-gis-stop-container-wrapper > *:only-child { + flex: 1 1 100%; +} + +.jp-gis-symbology-tabs { + display: flex; + border-bottom: 1px solid #ccc; + margin: 12px 0; +} + +.jp-gis-tab { + flex: 1; + text-align: center; + padding: 10px 16px; + border: none; + border-bottom: 2px solid transparent; + cursor: pointer; + font-size: var(--jp-ui-font-size2); + color: var(--jp-ui-font-color1); + background-color: var(--jp-layout-color1); +} + +.jp-gis-tab:not(.active):hover { + background-color: var(--jp-layout-color2); +} + +.jp-gis-tab.active { + background-color: var(--jp-layout-color2); + color: var(--jp-brand-color1); + border-bottom: 2px solid var(--jp-brand-color1); + font-weight: 500; +} From 6cd31821c47e0ff30ee3d786877d504104285fa4 Mon Sep 17 00:00:00 2001 From: elifsu Date: Wed, 11 Jun 2025 14:28:44 +0200 Subject: [PATCH 13/17] Wait for options to load before generating scene --- packages/base/src/mainview/mainView.tsx | 65 +++++++++++++++++++++---- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index d78155ddd..2704be60b 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -178,13 +178,16 @@ export class MainView extends React.Component { async componentDidMount(): Promise { window.addEventListener('resize', this._handleWindowResize); - const options = this._model.getOptions(); + const options = await this._waitForOptionsToLoad(200); const center = options.longitude !== undefined && options.latitude !== undefined ? fromLonLat([options.longitude!, options.latitude!]) : [0, 0]; const zoom = options.zoom !== undefined ? options.zoom! : 1; await this.generateScene(center, zoom); + if (this._Map){ + this.updateOptions(options); + } this.addContextMenu(); this._mainViewModel.initSignal(); if (window.jupytergisMaps !== undefined && this._documentPath) { @@ -324,14 +327,6 @@ export class MainView extends React.Component { ...updatedOptions, }); - this.setState(old => ({ - viewProjection: { - ...old.viewProjection, - code: projection.getCode(), - units: projection.getUnits() - } - })); - // Calculate scale if (resolution) { // DPI and inches per meter values taken from OpenLayers @@ -1432,6 +1427,48 @@ export class MainView extends React.Component { }); } + private _waitForOptionsToLoad(timeout: number): Promise { + return new Promise(resolve => { + let timerId: number; + + const endWaiting = () => { + clearTimeout(timerId); + resolve(this._model.getOptions()); + }; + + const handler = () => { + const options = this._model.getOptions(); + + // When widget is built for the second time, some extra options are added + // So we ignore some options when we check if options are loaded or not + const ignore = new Set(['extent', 'useExtent']); + + const realKeys = Object.entries(options) + .filter(([k, v]) => { + if (ignore.has(k)) { + return false; + } + if (typeof v === 'string') { + return v.length > 0; + } + if (typeof v === 'number') { + return v !== 0; + } + return v != null; + }) + .map(([k]) => k); + + if (realKeys.length > 0) { + endWaiting(); + } + }; + + timerId = window.setTimeout(endWaiting, timeout); + handler(); + }); + } + + /** * Remove a layer from the map. * @@ -1550,6 +1587,9 @@ export class MainView extends React.Component { }; private _onSharedOptionsChanged(): void { + if (!this._Map) { + return; + } if (!this._isPositionInitialized) { const options = this._model.getOptions(); this.updateOptions(options); @@ -1574,6 +1614,13 @@ export class MainView extends React.Component { if (projection !== undefined && currentProjection !== projection) { const newProjection = getProjection(projection); if (newProjection) { + this.setState(old => ({ + viewProjection: { + ...old.viewProjection, + code: newProjection.getCode(), + units: newProjection.getUnits() + } + })); view = new View({ projection: newProjection }); } else { console.warn(`Invalid projection: ${projection}`); From 00c17c22300126c386ba0164d27124a361834f4b Mon Sep 17 00:00:00 2001 From: elifsu Date: Thu, 12 Jun 2025 09:47:50 +0200 Subject: [PATCH 14/17] Make sure projection is applied to map with layers --- packages/base/src/mainview/mainView.tsx | 240 ++++++++++++------------ 1 file changed, 119 insertions(+), 121 deletions(-) diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index 2704be60b..dc8b65461 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -185,9 +185,8 @@ export class MainView extends React.Component { : [0, 0]; const zoom = options.zoom !== undefined ? options.zoom! : 1; await this.generateScene(center, zoom); - if (this._Map){ - this.updateOptions(options); - } + this.updateOptions(options); + this.addContextMenu(); this._mainViewModel.initSignal(); if (window.jupytergisMaps !== undefined && this._documentPath) { @@ -202,18 +201,18 @@ export class MainView extends React.Component { window.removeEventListener('resize', this._handleWindowResize); this._mainViewModel.viewSettingChanged.disconnect( this._onViewChanged, - this, + this ); this._model.themeChanged.disconnect(this._handleThemeChange, this); this._model.sharedOptionsChanged.disconnect( this._onSharedOptionsChanged, - this, + this ); this._model.clientStateChanged.disconnect( this._onClientSharedStateChanged, - this, + this ); this._mainViewModel.dispose(); @@ -226,14 +225,14 @@ export class MainView extends React.Component { layers: [], view: new View({ center, - zoom, + zoom }), - controls: [new ScaleLine()], + controls: [new ScaleLine()] }); // Add map interactions const dragAndDropInteraction = new DragAndDrop({ - formatConstructors: [GeoJSON], + formatConstructors: [GeoJSON] }); dragAndDropInteraction.on('addfeatures', event => { @@ -242,7 +241,7 @@ export class MainView extends React.Component { const sourceModel: IJGISSource = { type: 'GeoJSONSource', name: 'Drag and Drop source', - parameters: { path: event.file.name }, + parameters: { path: event.file.name } }; const layerId = UUID.uuid4(); @@ -259,8 +258,8 @@ export class MainView extends React.Component { color: '#FF0000', opacity: 1.0, type: 'line', - source: sourceId, - }, + source: sourceId + } }; this.addLayer(layerId, layerModel, this.getLayerIDs().length); @@ -289,9 +288,9 @@ export class MainView extends React.Component { } this._model.syncViewport( { coordinates: { x: center[0], y: center[1] }, zoom }, - this._mainViewModel.id, + this._mainViewModel.id ); - }), + }) ); this._Map.on('postrender', () => { @@ -317,14 +316,14 @@ export class MainView extends React.Component { longitude: latLng[0], bearing, projection: projection.getCode(), - zoom, + zoom }; updatedOptions.extent = view.calculateExtent(); this._model.setOptions({ ...currentOptions, - ...updatedOptions, + ...updatedOptions }); // Calculate scale @@ -336,7 +335,7 @@ export class MainView extends React.Component { this.setState(old => ({ ...old, - scale, + scale })); } }); @@ -349,7 +348,7 @@ export class MainView extends React.Component { if (JupyterGISModel.getOrderedLayerIds(this._model).length !== 0) { await this._updateLayersImpl( - JupyterGISModel.getOrderedLayerIds(this._model), + JupyterGISModel.getOrderedLayerIds(this._model) ); const options = this._model.getOptions(); this.updateOptions(options); @@ -363,13 +362,15 @@ export class MainView extends React.Component { this._contextMenu.open(event); }); + const projection = getProjection(this._model.getOptions().projection) ?? view.getProjection(); + this.setState(old => ({ ...old, loading: false, viewProjection: { - code: view.getProjection().getCode(), - units: view.getProjection().getUnits(), - }, + code: projection.getCode(), + units: projection.getUnits() + } })); } } @@ -379,28 +380,28 @@ export class MainView extends React.Component { image: new Circle({ radius: 5, fill: new Fill({ - color: '#C52707', + color: '#C52707' }), stroke: new Stroke({ color: '#171717', - width: 2, - }), - }), + width: 2 + }) + }) }); const lineStyle = new Style({ stroke: new Stroke({ color: '#171717', - width: 2, - }), + width: 2 + }) }); const polygonStyle = new Style({ fill: new Fill({ color: '#C5270780' }), stroke: new Stroke({ color: '#171717', - width: 2, - }), + width: 2 + }) }); const styleFunction = (feature: FeatureLike) => { @@ -435,7 +436,7 @@ export class MainView extends React.Component { condition: (event: MapBrowserEvent) => { return singleClick(event) && this._model.isIdentifying; }, - style: styleFunction, + style: styleFunction }); selectInteraction.on('select', event => { @@ -446,7 +447,7 @@ export class MainView extends React.Component { this._model.syncIdentifiedFeatures( identifiedFeatures, - this._mainViewModel.id, + this._mainViewModel.id ); }); @@ -466,19 +467,19 @@ export class MainView extends React.Component { label: 'New annotation', contents: [], parent: this._Map.getViewport().id, - open: true, + open: true }); }, label: 'Add annotation', isEnabled: () => { return !!this._Map; - }, + } }); this._contextMenu.addItem({ command: CommandIDs.addAnnotation, selector: '.ol-viewport', - rank: 1, + rank: 1 }); }; @@ -505,14 +506,14 @@ export class MainView extends React.Component { minZoom: sourceParameters.minZoom, maxZoom: sourceParameters.maxZoom, tileSize: 256, - url: url, + url: url }); } else { newSource = new PMTilesRasterSource({ interpolate: sourceParameters.interpolate, attributions: sourceParameters.attribution, tileSize: 256, - url: url, + url: url }); } @@ -524,7 +525,7 @@ export class MainView extends React.Component { newSource = new ImageTileSource({ interpolate: sourceParameters.interpolate, url: this.computeSourceUrl(source), - attributions: sourceParameters.attribution, + attributions: sourceParameters.attribution }); break; @@ -541,12 +542,12 @@ export class MainView extends React.Component { minZoom: sourceParameters.minZoom, maxZoom: sourceParameters.maxZoom, url: url, - format: new MVT({ featureClass: RenderFeature }), + format: new MVT({ featureClass: RenderFeature }) }); } else { newSource = new PMTilesVectorSource({ attributions: sourceParameters.attribution, - url: url, + url: url }); } @@ -558,17 +559,17 @@ export class MainView extends React.Component { (await loadFile({ filepath: source.parameters?.path, type: 'GeoJSONSource', - model: this._model, + model: this._model })); const format = new GeoJSON({ - featureProjection: this._Map.getView().getProjection(), + featureProjection: this._Map.getView().getProjection() }); // TODO: Don't hardcode projection const featureArray = format.readFeatures(data, { dataProjection: 'EPSG:4326', - featureProjection: this._Map.getView().getProjection(), + featureProjection: this._Map.getView().getProjection() }); const featureCollection = new Collection(featureArray); @@ -578,7 +579,7 @@ export class MainView extends React.Component { }); newSource = new VectorSource({ - features: featureCollection, + features: featureCollection }); break; @@ -589,7 +590,7 @@ export class MainView extends React.Component { const geojson = await loadFile({ filepath: parameters.path, type: 'ShapefileSource', - model: this._model, + model: this._model }); const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson; @@ -599,8 +600,8 @@ export class MainView extends React.Component { newSource = new VectorSource({ features: format.readFeatures(geojsonData, { dataProjection: 'EPSG:4326', - featureProjection: this._Map.getView().getProjection(), - }), + featureProjection: this._Map.getView().getProjection() + }) }); break; } @@ -610,16 +611,16 @@ export class MainView extends React.Component { // Convert lon/lat array to extent // Get lon/lat from source coordinates const leftSide = Math.min( - ...sourceParameters.coordinates.map(corner => corner[0]), + ...sourceParameters.coordinates.map(corner => corner[0]) ); const bottomSide = Math.min( - ...sourceParameters.coordinates.map(corner => corner[1]), + ...sourceParameters.coordinates.map(corner => corner[1]) ); const rightSide = Math.max( - ...sourceParameters.coordinates.map(corner => corner[0]), + ...sourceParameters.coordinates.map(corner => corner[0]) ); const topSide = Math.max( - ...sourceParameters.coordinates.map(corner => corner[1]), + ...sourceParameters.coordinates.map(corner => corner[1]) ); // Convert lon/lat to OpenLayer coordinates @@ -637,14 +638,14 @@ export class MainView extends React.Component { const imageUrl = await loadFile({ filepath: sourceParameters.path, type: 'ImageSource', - model: this._model, + model: this._model }); newSource = new Static({ interpolate: sourceParameters.interpolate, imageExtent: extent, url: imageUrl, - crossOrigin: '', + crossOrigin: '' }); break; @@ -671,30 +672,30 @@ export class MainView extends React.Component { ...addNoData(sourceInfo), min: sourceInfo.min, max: sourceInfo.max, - url: sourceInfo.url, + url: sourceInfo.url }; } else { const geotiff = await loadFile({ filepath: sourceInfo.url ?? '', type: 'GeoTiffSource', - model: this._model, + model: this._model }); return { ...addNoData(sourceInfo), min: sourceInfo.min, max: sourceInfo.max, geotiff, - url: URL.createObjectURL(geotiff.file), + url: URL.createObjectURL(geotiff.file) }; } - }), + }) ); newSource = new GeoTIFFSource({ interpolate: sourceParameters.interpolate, sources, normalize: sourceParameters.normalize, - wrapX: sourceParameters.wrapX, + wrapX: sourceParameters.wrapX }); break; @@ -790,7 +791,7 @@ export class MainView extends React.Component { if (!layer) { console.warn( - `Layer with ID ${layerId} does not exist in the shared model.`, + `Layer with ID ${layerId} does not exist in the shared model.` ); continue; } @@ -829,7 +830,7 @@ export class MainView extends React.Component { */ private async _buildMapLayer( id: string, - layer: IJGISLayer, + layer: IJGISLayer ): Promise { const sourceId = layer.parameters?.source; const source = this._model.sharedModel.getLayerSource(sourceId); @@ -858,7 +859,7 @@ export class MainView extends React.Component { newMapLayer = new TileLayer({ opacity: layerParameters.opacity, visible: layer.visible, - source: this._sources[layerParameters.source], + source: this._sources[layerParameters.source] }); break; @@ -870,7 +871,7 @@ export class MainView extends React.Component { opacity: layerParameters.opacity, visible: layer.visible, source: this._sources[layerParameters.source], - style: this.vectorLayerStyleRuleBuilder(layer), + style: this.vectorLayerStyleRuleBuilder(layer) }); break; @@ -881,7 +882,7 @@ export class MainView extends React.Component { newMapLayer = new VectorTileLayer({ opacity: layerParameters.opacity, source: this._sources[layerParameters.source], - style: this.vectorLayerStyleRuleBuilder(layer), + style: this.vectorLayerStyleRuleBuilder(layer) }); break; @@ -893,8 +894,8 @@ export class MainView extends React.Component { opacity: 0.3, source: this._sources[layerParameters.source], style: { - color: ['color', this.hillshadeMath()], - }, + color: ['color', this.hillshadeMath()] + } }); break; @@ -904,7 +905,7 @@ export class MainView extends React.Component { newMapLayer = new ImageLayer({ opacity: layerParameters.opacity, - source: this._sources[layerParameters.source], + source: this._sources[layerParameters.source] }); break; @@ -915,7 +916,7 @@ export class MainView extends React.Component { // This is to handle python sending a None for the color const layerOptions: any = { opacity: layerParameters.opacity, - source: this._sources[layerParameters.source], + source: this._sources[layerParameters.source] }; if (layerParameters.color) { @@ -933,7 +934,7 @@ export class MainView extends React.Component { source: this._sources[layerParameters.source], blur: layerParameters.blur ?? 15, radius: layerParameters.radius ?? 8, - gradient: layerParameters.color, + gradient: layerParameters.color }); break; } @@ -968,7 +969,7 @@ export class MainView extends React.Component { // Check if the projection exists in proj4list if (!proj4list[projectionCode]) { console.warn( - `Projection code '${projectionCode}' not found in proj4list`, + `Projection code '${projectionCode}' not found in proj4list` ); return; } @@ -978,7 +979,7 @@ export class MainView extends React.Component { register(proj4); } catch (error: any) { console.warn( - `Failed to register projection '${projectionCode}'. Error: ${error.message}`, + `Failed to register projection '${projectionCode}'. Error: ${error.message}` ); return; } @@ -1011,7 +1012,7 @@ export class MainView extends React.Component { } catch (error: any) { if ( this.state.loadingErrors.find( - item => item.id === id && item.error === error.message, + item => item.id === id && item.error === error.message ) ) { this._loadingLayers.delete(id); @@ -1020,13 +1021,13 @@ export class MainView extends React.Component { await showErrorMessage( `Error Adding ${layer.name}`, - `Failed to add ${layer.name}: ${error.message || 'invalid file path'}`, + `Failed to add ${layer.name}: ${error.message || 'invalid file path'}` ); this.setState(old => ({ ...old, loadingLayer: false })); this.state.loadingErrors.push({ id, error: error.message || 'invalid file path', - index, + index }); this._loadingLayers.delete(id); } @@ -1045,11 +1046,11 @@ export class MainView extends React.Component { 'circle-radius': 5, 'circle-fill-color': 'rgba(255,255,255,0.4)', 'circle-stroke-width': 1.25, - 'circle-stroke-color': '#3399CC', + 'circle-stroke-color': '#3399CC' }; const defaultRules: Rule = { - style: defaultStyle, + style: defaultStyle }; const layerStyle = { ...defaultRules }; @@ -1072,7 +1073,7 @@ export class MainView extends React.Component { // Arguments for "Any" and 'All' need to be wrapped in brackets filterExpr = [ layer.filters.logicalOp, - ...layer.filters.appliedFilters.map(buildCondition), + ...layer.filters.appliedFilters.map(buildCondition) ]; } @@ -1114,7 +1115,7 @@ export class MainView extends React.Component { ['*', 255 * 256, red], ['*', 255, green], ['*', 255 / 256, blue], - -32768, + -32768 ]; } // Generates a shaded relief image given elevation data. Uses a 3x3 @@ -1134,7 +1135,7 @@ export class MainView extends React.Component { const cosIncidence = [ '+', ['*', ['sin', sunEl], ['cos', slope]], - ['*', ['cos', sunEl], ['sin', slope], ['cos', ['-', sunAz, aspect]]], + ['*', ['cos', sunEl], ['sin', slope], ['cos', ['-', sunAz, aspect]]] ]; const scaled = ['*', 255, cosIncidence]; @@ -1151,7 +1152,7 @@ export class MainView extends React.Component { id: string, layer: IJGISLayer, mapLayer: Layer, - oldLayer?: IDict, + oldLayer?: IDict ): Promise { const sourceId = layer.parameters?.source; const source = this._model.sharedModel.getLayerSource(sourceId); @@ -1176,7 +1177,7 @@ export class MainView extends React.Component { mapLayer.setOpacity(layerParams.opacity || 1); (mapLayer as VectorLayer).setStyle( - this.vectorLayerStyleRuleBuilder(layer), + this.vectorLayerStyleRuleBuilder(layer) ); break; @@ -1187,7 +1188,7 @@ export class MainView extends React.Component { mapLayer.setOpacity(layerParams.opacity || 1); (mapLayer as VectorTileLayer).setStyle( - this.vectorLayerStyleRuleBuilder(layer), + this.vectorLayerStyleRuleBuilder(layer) ); break; @@ -1204,7 +1205,7 @@ export class MainView extends React.Component { if (layer?.parameters?.color) { (mapLayer as WebGlTileLayer).setStyle({ - color: layer.parameters.color, + color: layer.parameters.color }); } break; @@ -1217,7 +1218,7 @@ export class MainView extends React.Component { heatmap.setBlur(layerParams.blur ?? 15); heatmap.setRadius(layerParams.radius ?? 8); heatmap.setGradient( - layerParams.color ?? ['#00f', '#0ff', '#0f0', '#ff0', '#f00'], + layerParams.color ?? ['#00f', '#0ff', '#0f0', '#ff0', '#f00'] ); this.handleTemporalController(id, layer); @@ -1276,8 +1277,8 @@ export class MainView extends React.Component { ...old, filterStates: { ...this.state.filterStates, - [selectedLayerId]: activeFilter, - }, + [selectedLayerId]: activeFilter + } })); source.addFeatures(filteredFeatures); @@ -1300,13 +1301,13 @@ export class MainView extends React.Component { view.fit(extent, { padding: [50, 50, 50, 50], duration: 1000, - maxZoom: 16, + maxZoom: 16 }); } private highlightFeatureOnMap( sender: IJupyterGISModel, - featureOrGeometry: any, + featureOrGeometry: any ): void { const geometry = featureOrGeometry?.geometry || @@ -1323,12 +1324,12 @@ export class MainView extends React.Component { const parsedGeometry = isOlGeometry ? geometry : new GeoJSON().readGeometry(geometry, { - featureProjection: this._Map.getView().getProjection(), + featureProjection: this._Map.getView().getProjection() }); const olFeature = new Feature({ geometry: parsedGeometry, - ...(geometry !== featureOrGeometry ? featureOrGeometry : {}), + ...(geometry !== featureOrGeometry ? featureOrGeometry : {}) }); if (!this._highlightLayer) { @@ -1343,38 +1344,38 @@ export class MainView extends React.Component { image: new Circle({ radius: 6, fill: new Fill({ color: 'rgba(255, 255, 0, 0.8)' }), - stroke: new Stroke({ color: '#ff0', width: 2 }), - }), + stroke: new Stroke({ color: '#ff0', width: 2 }) + }) }); case 'LineString': case 'MultiLineString': return new Style({ stroke: new Stroke({ color: 'rgba(255, 255, 0, 0.8)', - width: 3, - }), + width: 3 + }) }); case 'Polygon': case 'MultiPolygon': return new Style({ stroke: new Stroke({ color: '#f00', - width: 2, + width: 2 }), fill: new Fill({ - color: 'rgba(255, 255, 0, 0.8)', - }), + color: 'rgba(255, 255, 0, 0.8)' + }) }); default: return new Style({ stroke: new Stroke({ color: '#000', - width: 2, - }), + width: 2 + }) }); } }, - zIndex: 999, + zIndex: 999 }); this._Map.addLayer(this._highlightLayer); } @@ -1483,7 +1484,7 @@ export class MainView extends React.Component { private _onClientSharedStateChanged = ( sender: IJupyterGISModel, - clients: Map, + clients: Map ): void => { const localState = this._model.localState; if (!localState) { @@ -1541,7 +1542,7 @@ export class MainView extends React.Component { if (pointer) { const pixel = this._Map.getPixelFromCoordinate([ pointer.coordinates.x, - pointer.coordinates.y, + pointer.coordinates.y ]); const lonLat = toLonLat([pointer.coordinates.x, pointer.coordinates.y]); @@ -1552,13 +1553,13 @@ export class MainView extends React.Component { displayName: client.user.display_name, color: client.user.color, coordinates: { x: pixel[0], y: pixel[1] }, - lonLat: { longitude: lonLat[0], latitude: lonLat[1] }, + lonLat: { longitude: lonLat[0], latitude: lonLat[1] } }; } else { currentClientPointer = { ...currentClientPointer, coordinates: { x: pixel[0], y: pixel[1] }, - lonLat: { longitude: lonLat[0], latitude: lonLat[1] }, + lonLat: { longitude: lonLat[0], latitude: lonLat[1] } }; } @@ -1577,19 +1578,16 @@ export class MainView extends React.Component { if (isTemporalControllerActive !== this.state.displayTemporalController) { this.setState(old => ({ ...old, - displayTemporalController: isTemporalControllerActive, + displayTemporalController: isTemporalControllerActive })); this._mainViewModel.commands.notifyCommandChanged( - CommandIDs.temporalController, + CommandIDs.temporalController ); } }; private _onSharedOptionsChanged(): void { - if (!this._Map) { - return; - } if (!this._isPositionInitialized) { const options = this._model.getOptions(); this.updateOptions(options); @@ -1605,7 +1603,7 @@ export class MainView extends React.Component { latitude, longitude, zoom, - bearing, + bearing } = options; let view = this._Map.getView(); const currentProjection = view.getProjection().getCode(); @@ -1637,7 +1635,7 @@ export class MainView extends React.Component { } else { const centerCoord = fromLonLat( [longitude || 0, latitude || 0], - view.getProjection(), + view.getProjection() ); this._moveToPosition({ x: centerCoord[0], y: centerCoord[1] }, zoom || 0); @@ -1652,7 +1650,7 @@ export class MainView extends React.Component { private _onViewChanged( sender: ObservableMap, - change: IObservableMap.IChangedArgs, + change: IObservableMap.IChangedArgs ): void { // TODO SOMETHING } @@ -1730,7 +1728,7 @@ export class MainView extends React.Component { private _onLayersChanged( _: IJupyterGISDoc, - change: IJGISLayerDocChange, + change: IJGISLayerDocChange ): void { // Avoid concurrency update on layers on first load, if layersTreeChanged and // LayersChanged are triggered simultaneously. @@ -1768,7 +1766,7 @@ export class MainView extends React.Component { private _onLayerTreeChange( sender?: IJupyterGISDoc, - change?: IJGISLayerTreeDocChange, + change?: IJGISLayerTreeDocChange ): void { this._ready = false; // We can't properly use the change, because of the nested groups in the the shared @@ -1778,7 +1776,7 @@ export class MainView extends React.Component { private _onSourcesChange( _: IJupyterGISDoc, - change: IJGISSourceDocChange, + change: IJGISSourceDocChange ): void { if (!this._ready) { return; @@ -1798,7 +1796,7 @@ export class MainView extends React.Component { private _onSharedModelStateChange = ( _: any, - change: IJupyterGISDocChange, + change: IJupyterGISDocChange ) => { const changedState = change.stateChange?.map(value => value.name); if (!changedState?.includes('path')) { @@ -1818,7 +1816,7 @@ export class MainView extends React.Component { private _onSharedMetadataChanged = ( _: IJupyterGISModel, - changes: MapChange, + changes: MapChange ) => { const newState = { ...this.state.annotations }; changes.forEach((val, key) => { @@ -1995,7 +1993,7 @@ export class MainView extends React.Component { this._model.syncIdentifiedFeatures( [bandValues], - this._mainViewModel.id, + this._mainViewModel.id ); const coordinate = this._Map.getCoordinateFromPixel(e.pixel); @@ -2038,7 +2036,7 @@ export class MainView extends React.Component { private _handleGeolocationChanged( sender: any, - newPosition: JgisCoordinates, + newPosition: JgisCoordinates ): void { const view = this._Map.getView(); const zoom = view.getZoom(); @@ -2046,7 +2044,7 @@ export class MainView extends React.Component { this._flyToPosition(newPosition, zoom); } else { throw new Error( - 'Could not move to geolocation, because current zoom is not defined.', + 'Could not move to geolocation, because current zoom is not defined.' ); } } @@ -2078,7 +2076,7 @@ export class MainView extends React.Component { id={key} style={{ left: screenPosition.x, - top: screenPosition.y, + top: screenPosition.y }} className={'jGIS-Popup-Wrapper'} > @@ -2104,7 +2102,7 @@ export class MainView extends React.Component { style={{ border: this.state.remoteUser ? `solid 3px ${this.state.remoteUser.color}` - : 'unset', + : 'unset' }} > @@ -2115,7 +2113,7 @@ export class MainView extends React.Component { ref={this.divRef} style={{ width: '100%', - height: '100%', + height: '100%' }} /> From 37b1fa93385c818868a18600214dc1c89cdd0f6b Mon Sep 17 00:00:00 2001 From: elifsu Date: Thu, 12 Jun 2025 14:04:32 +0200 Subject: [PATCH 15/17] Lint --- packages/base/src/mainview/mainView.tsx | 254 ++++++++++++------------ 1 file changed, 131 insertions(+), 123 deletions(-) diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index dc8b65461..650fd8f28 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -178,14 +178,14 @@ export class MainView extends React.Component { async componentDidMount(): Promise { window.addEventListener('resize', this._handleWindowResize); - const options = await this._waitForOptionsToLoad(200); + const options = await this._waitForOptionsToLoad(); const center = options.longitude !== undefined && options.latitude !== undefined ? fromLonLat([options.longitude!, options.latitude!]) : [0, 0]; const zoom = options.zoom !== undefined ? options.zoom! : 1; await this.generateScene(center, zoom); - this.updateOptions(options); + await this.updateOptions(options); this.addContextMenu(); this._mainViewModel.initSignal(); @@ -201,18 +201,18 @@ export class MainView extends React.Component { window.removeEventListener('resize', this._handleWindowResize); this._mainViewModel.viewSettingChanged.disconnect( this._onViewChanged, - this + this, ); this._model.themeChanged.disconnect(this._handleThemeChange, this); this._model.sharedOptionsChanged.disconnect( this._onSharedOptionsChanged, - this + this, ); this._model.clientStateChanged.disconnect( this._onClientSharedStateChanged, - this + this, ); this._mainViewModel.dispose(); @@ -225,14 +225,14 @@ export class MainView extends React.Component { layers: [], view: new View({ center, - zoom + zoom, }), - controls: [new ScaleLine()] + controls: [new ScaleLine()], }); // Add map interactions const dragAndDropInteraction = new DragAndDrop({ - formatConstructors: [GeoJSON] + formatConstructors: [GeoJSON], }); dragAndDropInteraction.on('addfeatures', event => { @@ -241,7 +241,7 @@ export class MainView extends React.Component { const sourceModel: IJGISSource = { type: 'GeoJSONSource', name: 'Drag and Drop source', - parameters: { path: event.file.name } + parameters: { path: event.file.name }, }; const layerId = UUID.uuid4(); @@ -258,8 +258,8 @@ export class MainView extends React.Component { color: '#FF0000', opacity: 1.0, type: 'line', - source: sourceId - } + source: sourceId, + }, }; this.addLayer(layerId, layerModel, this.getLayerIDs().length); @@ -288,9 +288,9 @@ export class MainView extends React.Component { } this._model.syncViewport( { coordinates: { x: center[0], y: center[1] }, zoom }, - this._mainViewModel.id + this._mainViewModel.id, ); - }) + }), ); this._Map.on('postrender', () => { @@ -306,7 +306,8 @@ export class MainView extends React.Component { const center = view.getCenter() || [0, 0]; const zoom = view.getZoom() || 0; - const projection = view.getProjection(); + const projection = + getProjection(currentOptions.projection) ?? view.getProjection(); const latLng = toLonLat(center, projection); const bearing = view.getRotation(); const resolution = view.getResolution(); @@ -316,14 +317,14 @@ export class MainView extends React.Component { longitude: latLng[0], bearing, projection: projection.getCode(), - zoom + zoom, }; updatedOptions.extent = view.calculateExtent(); this._model.setOptions({ ...currentOptions, - ...updatedOptions + ...updatedOptions, }); // Calculate scale @@ -335,7 +336,7 @@ export class MainView extends React.Component { this.setState(old => ({ ...old, - scale + scale, })); } }); @@ -348,7 +349,7 @@ export class MainView extends React.Component { if (JupyterGISModel.getOrderedLayerIds(this._model).length !== 0) { await this._updateLayersImpl( - JupyterGISModel.getOrderedLayerIds(this._model) + JupyterGISModel.getOrderedLayerIds(this._model), ); const options = this._model.getOptions(); this.updateOptions(options); @@ -362,15 +363,17 @@ export class MainView extends React.Component { this._contextMenu.open(event); }); - const projection = getProjection(this._model.getOptions().projection) ?? view.getProjection(); + const projection = + getProjection(this._model.getOptions().projection) ?? + view.getProjection(); this.setState(old => ({ ...old, loading: false, viewProjection: { code: projection.getCode(), - units: projection.getUnits() - } + units: projection.getUnits(), + }, })); } } @@ -380,28 +383,28 @@ export class MainView extends React.Component { image: new Circle({ radius: 5, fill: new Fill({ - color: '#C52707' + color: '#C52707', }), stroke: new Stroke({ color: '#171717', - width: 2 - }) - }) + width: 2, + }), + }), }); const lineStyle = new Style({ stroke: new Stroke({ color: '#171717', - width: 2 - }) + width: 2, + }), }); const polygonStyle = new Style({ fill: new Fill({ color: '#C5270780' }), stroke: new Stroke({ color: '#171717', - width: 2 - }) + width: 2, + }), }); const styleFunction = (feature: FeatureLike) => { @@ -436,7 +439,7 @@ export class MainView extends React.Component { condition: (event: MapBrowserEvent) => { return singleClick(event) && this._model.isIdentifying; }, - style: styleFunction + style: styleFunction, }); selectInteraction.on('select', event => { @@ -447,7 +450,7 @@ export class MainView extends React.Component { this._model.syncIdentifiedFeatures( identifiedFeatures, - this._mainViewModel.id + this._mainViewModel.id, ); }); @@ -467,19 +470,19 @@ export class MainView extends React.Component { label: 'New annotation', contents: [], parent: this._Map.getViewport().id, - open: true + open: true, }); }, label: 'Add annotation', isEnabled: () => { return !!this._Map; - } + }, }); this._contextMenu.addItem({ command: CommandIDs.addAnnotation, selector: '.ol-viewport', - rank: 1 + rank: 1, }); }; @@ -506,14 +509,14 @@ export class MainView extends React.Component { minZoom: sourceParameters.minZoom, maxZoom: sourceParameters.maxZoom, tileSize: 256, - url: url + url: url, }); } else { newSource = new PMTilesRasterSource({ interpolate: sourceParameters.interpolate, attributions: sourceParameters.attribution, tileSize: 256, - url: url + url: url, }); } @@ -525,7 +528,7 @@ export class MainView extends React.Component { newSource = new ImageTileSource({ interpolate: sourceParameters.interpolate, url: this.computeSourceUrl(source), - attributions: sourceParameters.attribution + attributions: sourceParameters.attribution, }); break; @@ -542,12 +545,12 @@ export class MainView extends React.Component { minZoom: sourceParameters.minZoom, maxZoom: sourceParameters.maxZoom, url: url, - format: new MVT({ featureClass: RenderFeature }) + format: new MVT({ featureClass: RenderFeature }), }); } else { newSource = new PMTilesVectorSource({ attributions: sourceParameters.attribution, - url: url + url: url, }); } @@ -559,17 +562,17 @@ export class MainView extends React.Component { (await loadFile({ filepath: source.parameters?.path, type: 'GeoJSONSource', - model: this._model + model: this._model, })); const format = new GeoJSON({ - featureProjection: this._Map.getView().getProjection() + featureProjection: this._Map.getView().getProjection(), }); // TODO: Don't hardcode projection const featureArray = format.readFeatures(data, { dataProjection: 'EPSG:4326', - featureProjection: this._Map.getView().getProjection() + featureProjection: this._Map.getView().getProjection(), }); const featureCollection = new Collection(featureArray); @@ -579,7 +582,7 @@ export class MainView extends React.Component { }); newSource = new VectorSource({ - features: featureCollection + features: featureCollection, }); break; @@ -590,7 +593,7 @@ export class MainView extends React.Component { const geojson = await loadFile({ filepath: parameters.path, type: 'ShapefileSource', - model: this._model + model: this._model, }); const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson; @@ -600,8 +603,8 @@ export class MainView extends React.Component { newSource = new VectorSource({ features: format.readFeatures(geojsonData, { dataProjection: 'EPSG:4326', - featureProjection: this._Map.getView().getProjection() - }) + featureProjection: this._Map.getView().getProjection(), + }), }); break; } @@ -611,16 +614,16 @@ export class MainView extends React.Component { // Convert lon/lat array to extent // Get lon/lat from source coordinates const leftSide = Math.min( - ...sourceParameters.coordinates.map(corner => corner[0]) + ...sourceParameters.coordinates.map(corner => corner[0]), ); const bottomSide = Math.min( - ...sourceParameters.coordinates.map(corner => corner[1]) + ...sourceParameters.coordinates.map(corner => corner[1]), ); const rightSide = Math.max( - ...sourceParameters.coordinates.map(corner => corner[0]) + ...sourceParameters.coordinates.map(corner => corner[0]), ); const topSide = Math.max( - ...sourceParameters.coordinates.map(corner => corner[1]) + ...sourceParameters.coordinates.map(corner => corner[1]), ); // Convert lon/lat to OpenLayer coordinates @@ -638,14 +641,14 @@ export class MainView extends React.Component { const imageUrl = await loadFile({ filepath: sourceParameters.path, type: 'ImageSource', - model: this._model + model: this._model, }); newSource = new Static({ interpolate: sourceParameters.interpolate, imageExtent: extent, url: imageUrl, - crossOrigin: '' + crossOrigin: '', }); break; @@ -672,30 +675,30 @@ export class MainView extends React.Component { ...addNoData(sourceInfo), min: sourceInfo.min, max: sourceInfo.max, - url: sourceInfo.url + url: sourceInfo.url, }; } else { const geotiff = await loadFile({ filepath: sourceInfo.url ?? '', type: 'GeoTiffSource', - model: this._model + model: this._model, }); return { ...addNoData(sourceInfo), min: sourceInfo.min, max: sourceInfo.max, geotiff, - url: URL.createObjectURL(geotiff.file) + url: URL.createObjectURL(geotiff.file), }; } - }) + }), ); newSource = new GeoTIFFSource({ interpolate: sourceParameters.interpolate, sources, normalize: sourceParameters.normalize, - wrapX: sourceParameters.wrapX + wrapX: sourceParameters.wrapX, }); break; @@ -791,7 +794,7 @@ export class MainView extends React.Component { if (!layer) { console.warn( - `Layer with ID ${layerId} does not exist in the shared model.` + `Layer with ID ${layerId} does not exist in the shared model.`, ); continue; } @@ -830,7 +833,7 @@ export class MainView extends React.Component { */ private async _buildMapLayer( id: string, - layer: IJGISLayer + layer: IJGISLayer, ): Promise { const sourceId = layer.parameters?.source; const source = this._model.sharedModel.getLayerSource(sourceId); @@ -859,7 +862,7 @@ export class MainView extends React.Component { newMapLayer = new TileLayer({ opacity: layerParameters.opacity, visible: layer.visible, - source: this._sources[layerParameters.source] + source: this._sources[layerParameters.source], }); break; @@ -871,7 +874,7 @@ export class MainView extends React.Component { opacity: layerParameters.opacity, visible: layer.visible, source: this._sources[layerParameters.source], - style: this.vectorLayerStyleRuleBuilder(layer) + style: this.vectorLayerStyleRuleBuilder(layer), }); break; @@ -882,7 +885,7 @@ export class MainView extends React.Component { newMapLayer = new VectorTileLayer({ opacity: layerParameters.opacity, source: this._sources[layerParameters.source], - style: this.vectorLayerStyleRuleBuilder(layer) + style: this.vectorLayerStyleRuleBuilder(layer), }); break; @@ -894,8 +897,8 @@ export class MainView extends React.Component { opacity: 0.3, source: this._sources[layerParameters.source], style: { - color: ['color', this.hillshadeMath()] - } + color: ['color', this.hillshadeMath()], + }, }); break; @@ -905,7 +908,7 @@ export class MainView extends React.Component { newMapLayer = new ImageLayer({ opacity: layerParameters.opacity, - source: this._sources[layerParameters.source] + source: this._sources[layerParameters.source], }); break; @@ -916,7 +919,7 @@ export class MainView extends React.Component { // This is to handle python sending a None for the color const layerOptions: any = { opacity: layerParameters.opacity, - source: this._sources[layerParameters.source] + source: this._sources[layerParameters.source], }; if (layerParameters.color) { @@ -934,7 +937,7 @@ export class MainView extends React.Component { source: this._sources[layerParameters.source], blur: layerParameters.blur ?? 15, radius: layerParameters.radius ?? 8, - gradient: layerParameters.color + gradient: layerParameters.color, }); break; } @@ -969,7 +972,7 @@ export class MainView extends React.Component { // Check if the projection exists in proj4list if (!proj4list[projectionCode]) { console.warn( - `Projection code '${projectionCode}' not found in proj4list` + `Projection code '${projectionCode}' not found in proj4list`, ); return; } @@ -979,7 +982,7 @@ export class MainView extends React.Component { register(proj4); } catch (error: any) { console.warn( - `Failed to register projection '${projectionCode}'. Error: ${error.message}` + `Failed to register projection '${projectionCode}'. Error: ${error.message}`, ); return; } @@ -1012,7 +1015,7 @@ export class MainView extends React.Component { } catch (error: any) { if ( this.state.loadingErrors.find( - item => item.id === id && item.error === error.message + item => item.id === id && item.error === error.message, ) ) { this._loadingLayers.delete(id); @@ -1021,13 +1024,13 @@ export class MainView extends React.Component { await showErrorMessage( `Error Adding ${layer.name}`, - `Failed to add ${layer.name}: ${error.message || 'invalid file path'}` + `Failed to add ${layer.name}: ${error.message || 'invalid file path'}`, ); this.setState(old => ({ ...old, loadingLayer: false })); this.state.loadingErrors.push({ id, error: error.message || 'invalid file path', - index + index, }); this._loadingLayers.delete(id); } @@ -1046,11 +1049,11 @@ export class MainView extends React.Component { 'circle-radius': 5, 'circle-fill-color': 'rgba(255,255,255,0.4)', 'circle-stroke-width': 1.25, - 'circle-stroke-color': '#3399CC' + 'circle-stroke-color': '#3399CC', }; const defaultRules: Rule = { - style: defaultStyle + style: defaultStyle, }; const layerStyle = { ...defaultRules }; @@ -1073,7 +1076,7 @@ export class MainView extends React.Component { // Arguments for "Any" and 'All' need to be wrapped in brackets filterExpr = [ layer.filters.logicalOp, - ...layer.filters.appliedFilters.map(buildCondition) + ...layer.filters.appliedFilters.map(buildCondition), ]; } @@ -1115,7 +1118,7 @@ export class MainView extends React.Component { ['*', 255 * 256, red], ['*', 255, green], ['*', 255 / 256, blue], - -32768 + -32768, ]; } // Generates a shaded relief image given elevation data. Uses a 3x3 @@ -1135,7 +1138,7 @@ export class MainView extends React.Component { const cosIncidence = [ '+', ['*', ['sin', sunEl], ['cos', slope]], - ['*', ['cos', sunEl], ['sin', slope], ['cos', ['-', sunAz, aspect]]] + ['*', ['cos', sunEl], ['sin', slope], ['cos', ['-', sunAz, aspect]]], ]; const scaled = ['*', 255, cosIncidence]; @@ -1152,7 +1155,7 @@ export class MainView extends React.Component { id: string, layer: IJGISLayer, mapLayer: Layer, - oldLayer?: IDict + oldLayer?: IDict, ): Promise { const sourceId = layer.parameters?.source; const source = this._model.sharedModel.getLayerSource(sourceId); @@ -1177,7 +1180,7 @@ export class MainView extends React.Component { mapLayer.setOpacity(layerParams.opacity || 1); (mapLayer as VectorLayer).setStyle( - this.vectorLayerStyleRuleBuilder(layer) + this.vectorLayerStyleRuleBuilder(layer), ); break; @@ -1188,7 +1191,7 @@ export class MainView extends React.Component { mapLayer.setOpacity(layerParams.opacity || 1); (mapLayer as VectorTileLayer).setStyle( - this.vectorLayerStyleRuleBuilder(layer) + this.vectorLayerStyleRuleBuilder(layer), ); break; @@ -1205,7 +1208,7 @@ export class MainView extends React.Component { if (layer?.parameters?.color) { (mapLayer as WebGlTileLayer).setStyle({ - color: layer.parameters.color + color: layer.parameters.color, }); } break; @@ -1218,7 +1221,7 @@ export class MainView extends React.Component { heatmap.setBlur(layerParams.blur ?? 15); heatmap.setRadius(layerParams.radius ?? 8); heatmap.setGradient( - layerParams.color ?? ['#00f', '#0ff', '#0f0', '#ff0', '#f00'] + layerParams.color ?? ['#00f', '#0ff', '#0f0', '#ff0', '#f00'], ); this.handleTemporalController(id, layer); @@ -1277,8 +1280,8 @@ export class MainView extends React.Component { ...old, filterStates: { ...this.state.filterStates, - [selectedLayerId]: activeFilter - } + [selectedLayerId]: activeFilter, + }, })); source.addFeatures(filteredFeatures); @@ -1301,13 +1304,13 @@ export class MainView extends React.Component { view.fit(extent, { padding: [50, 50, 50, 50], duration: 1000, - maxZoom: 16 + maxZoom: 16, }); } private highlightFeatureOnMap( sender: IJupyterGISModel, - featureOrGeometry: any + featureOrGeometry: any, ): void { const geometry = featureOrGeometry?.geometry || @@ -1324,12 +1327,12 @@ export class MainView extends React.Component { const parsedGeometry = isOlGeometry ? geometry : new GeoJSON().readGeometry(geometry, { - featureProjection: this._Map.getView().getProjection() + featureProjection: this._Map.getView().getProjection(), }); const olFeature = new Feature({ geometry: parsedGeometry, - ...(geometry !== featureOrGeometry ? featureOrGeometry : {}) + ...(geometry !== featureOrGeometry ? featureOrGeometry : {}), }); if (!this._highlightLayer) { @@ -1344,38 +1347,38 @@ export class MainView extends React.Component { image: new Circle({ radius: 6, fill: new Fill({ color: 'rgba(255, 255, 0, 0.8)' }), - stroke: new Stroke({ color: '#ff0', width: 2 }) - }) + stroke: new Stroke({ color: '#ff0', width: 2 }), + }), }); case 'LineString': case 'MultiLineString': return new Style({ stroke: new Stroke({ color: 'rgba(255, 255, 0, 0.8)', - width: 3 - }) + width: 3, + }), }); case 'Polygon': case 'MultiPolygon': return new Style({ stroke: new Stroke({ color: '#f00', - width: 2 + width: 2, }), fill: new Fill({ - color: 'rgba(255, 255, 0, 0.8)' - }) + color: 'rgba(255, 255, 0, 0.8)', + }), }); default: return new Style({ stroke: new Stroke({ color: '#000', - width: 2 - }) + width: 2, + }), }); } }, - zIndex: 999 + zIndex: 999, }); this._Map.addLayer(this._highlightLayer); } @@ -1428,7 +1431,7 @@ export class MainView extends React.Component { }); } - private _waitForOptionsToLoad(timeout: number): Promise { + private _waitForOptionsToLoad(timeout = 250): Promise { return new Promise(resolve => { let timerId: number; @@ -1442,7 +1445,7 @@ export class MainView extends React.Component { // When widget is built for the second time, some extra options are added // So we ignore some options when we check if options are loaded or not - const ignore = new Set(['extent', 'useExtent']); + const ignore = new Set(['extent', 'useExtent', 'zoom']); const realKeys = Object.entries(options) .filter(([k, v]) => { @@ -1469,7 +1472,6 @@ export class MainView extends React.Component { }); } - /** * Remove a layer from the map. * @@ -1484,7 +1486,7 @@ export class MainView extends React.Component { private _onClientSharedStateChanged = ( sender: IJupyterGISModel, - clients: Map + clients: Map, ): void => { const localState = this._model.localState; if (!localState) { @@ -1542,7 +1544,7 @@ export class MainView extends React.Component { if (pointer) { const pixel = this._Map.getPixelFromCoordinate([ pointer.coordinates.x, - pointer.coordinates.y + pointer.coordinates.y, ]); const lonLat = toLonLat([pointer.coordinates.x, pointer.coordinates.y]); @@ -1553,13 +1555,13 @@ export class MainView extends React.Component { displayName: client.user.display_name, color: client.user.color, coordinates: { x: pixel[0], y: pixel[1] }, - lonLat: { longitude: lonLat[0], latitude: lonLat[1] } + lonLat: { longitude: lonLat[0], latitude: lonLat[1] }, }; } else { currentClientPointer = { ...currentClientPointer, coordinates: { x: pixel[0], y: pixel[1] }, - lonLat: { longitude: lonLat[0], latitude: lonLat[1] } + lonLat: { longitude: lonLat[0], latitude: lonLat[1] }, }; } @@ -1578,11 +1580,11 @@ export class MainView extends React.Component { if (isTemporalControllerActive !== this.state.displayTemporalController) { this.setState(old => ({ ...old, - displayTemporalController: isTemporalControllerActive + displayTemporalController: isTemporalControllerActive, })); this._mainViewModel.commands.notifyCommandChanged( - CommandIDs.temporalController + CommandIDs.temporalController, ); } }; @@ -1596,6 +1598,12 @@ export class MainView extends React.Component { } private async updateOptions(options: IJGISOptions): Promise { + if (!this._Map) { + console.warn( + 'Options are trying to be updated when there is no OL map initialized', + ); + return; + } const { projection, extent, @@ -1603,7 +1611,7 @@ export class MainView extends React.Component { latitude, longitude, zoom, - bearing + bearing, } = options; let view = this._Map.getView(); const currentProjection = view.getProjection().getCode(); @@ -1616,8 +1624,8 @@ export class MainView extends React.Component { viewProjection: { ...old.viewProjection, code: newProjection.getCode(), - units: newProjection.getUnits() - } + units: newProjection.getUnits(), + }, })); view = new View({ projection: newProjection }); } else { @@ -1635,7 +1643,7 @@ export class MainView extends React.Component { } else { const centerCoord = fromLonLat( [longitude || 0, latitude || 0], - view.getProjection() + view.getProjection(), ); this._moveToPosition({ x: centerCoord[0], y: centerCoord[1] }, zoom || 0); @@ -1650,7 +1658,7 @@ export class MainView extends React.Component { private _onViewChanged( sender: ObservableMap, - change: IObservableMap.IChangedArgs + change: IObservableMap.IChangedArgs, ): void { // TODO SOMETHING } @@ -1728,7 +1736,7 @@ export class MainView extends React.Component { private _onLayersChanged( _: IJupyterGISDoc, - change: IJGISLayerDocChange + change: IJGISLayerDocChange, ): void { // Avoid concurrency update on layers on first load, if layersTreeChanged and // LayersChanged are triggered simultaneously. @@ -1766,7 +1774,7 @@ export class MainView extends React.Component { private _onLayerTreeChange( sender?: IJupyterGISDoc, - change?: IJGISLayerTreeDocChange + change?: IJGISLayerTreeDocChange, ): void { this._ready = false; // We can't properly use the change, because of the nested groups in the the shared @@ -1776,7 +1784,7 @@ export class MainView extends React.Component { private _onSourcesChange( _: IJupyterGISDoc, - change: IJGISSourceDocChange + change: IJGISSourceDocChange, ): void { if (!this._ready) { return; @@ -1796,7 +1804,7 @@ export class MainView extends React.Component { private _onSharedModelStateChange = ( _: any, - change: IJupyterGISDocChange + change: IJupyterGISDocChange, ) => { const changedState = change.stateChange?.map(value => value.name); if (!changedState?.includes('path')) { @@ -1816,7 +1824,7 @@ export class MainView extends React.Component { private _onSharedMetadataChanged = ( _: IJupyterGISModel, - changes: MapChange + changes: MapChange, ) => { const newState = { ...this.state.annotations }; changes.forEach((val, key) => { @@ -1993,7 +2001,7 @@ export class MainView extends React.Component { this._model.syncIdentifiedFeatures( [bandValues], - this._mainViewModel.id + this._mainViewModel.id, ); const coordinate = this._Map.getCoordinateFromPixel(e.pixel); @@ -2036,7 +2044,7 @@ export class MainView extends React.Component { private _handleGeolocationChanged( sender: any, - newPosition: JgisCoordinates + newPosition: JgisCoordinates, ): void { const view = this._Map.getView(); const zoom = view.getZoom(); @@ -2044,7 +2052,7 @@ export class MainView extends React.Component { this._flyToPosition(newPosition, zoom); } else { throw new Error( - 'Could not move to geolocation, because current zoom is not defined.' + 'Could not move to geolocation, because current zoom is not defined.', ); } } @@ -2076,7 +2084,7 @@ export class MainView extends React.Component { id={key} style={{ left: screenPosition.x, - top: screenPosition.y + top: screenPosition.y, }} className={'jGIS-Popup-Wrapper'} > @@ -2102,7 +2110,7 @@ export class MainView extends React.Component { style={{ border: this.state.remoteUser ? `solid 3px ${this.state.remoteUser.color}` - : 'unset' + : 'unset', }} > @@ -2113,7 +2121,7 @@ export class MainView extends React.Component { ref={this.divRef} style={{ width: '100%', - height: '100%' + height: '100%', }} /> From 4bcaa79cd9ecf310b6c21ee2bcc3a455a972f45a Mon Sep 17 00:00:00 2001 From: elifsu Date: Thu, 12 Jun 2025 14:05:30 +0200 Subject: [PATCH 16/17] Yarn lock --- yarn.lock | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/yarn.lock b/yarn.lock index dc04ce465..9b4080186 100644 --- a/yarn.lock +++ b/yarn.lock @@ -853,9 +853,11 @@ __metadata: shpjs: ^6.1.0 styled-components: ^5.3.6 three: ^0.135.0 + three-mesh-bvh: ^0.5.17 ts-patch: ^3.3.0 typescript: ^5 typescript-transform-paths: ^3.5.5 + uuid: ^11.0.3 languageName: unknown linkType: soft @@ -11362,6 +11364,15 @@ __metadata: languageName: node linkType: hard +"three-mesh-bvh@npm:^0.5.17": + version: 0.5.24 + resolution: "three-mesh-bvh@npm:0.5.24" + peerDependencies: + three: ">= 0.123.0" + checksum: 5a5e356111756869cfd00870bca2d881d3019b55e71142b5eee544a2e6bcc3546a340b0defa29c3ebe7ed4cfe99e7ee6addd5671bb89852841107189c0f98157 + languageName: node + linkType: hard + "three@npm:^0.135.0": version: 0.135.0 resolution: "three@npm:0.135.0" @@ -11885,6 +11896,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^11.0.3": + version: 11.1.0 + resolution: "uuid@npm:11.1.0" + bin: + uuid: dist/esm/bin/uuid + checksum: 840f19758543c4631e58a29439e51b5b669d5f34b4dd2700b6a1d15c5708c7a6e0c3e2c8c4a2eae761a3a7caa7e9884d00c86c02622ba91137bd3deade6b4b4a + languageName: node + linkType: hard + "uuid@npm:^9.0.0": version: 9.0.1 resolution: "uuid@npm:9.0.1" From 5a6a3b1ece993776bd3ebe6ac93bd0c15bc10398 Mon Sep 17 00:00:00 2001 From: elifsu Date: Thu, 12 Jun 2025 14:52:32 +0200 Subject: [PATCH 17/17] Remove unnecessary waiting function --- packages/base/src/mainview/mainView.tsx | 50 +--------------------- yarn.lock | 57 ++++++++----------------- 2 files changed, 19 insertions(+), 88 deletions(-) diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index 650fd8f28..df066ff1d 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -178,14 +178,13 @@ export class MainView extends React.Component { async componentDidMount(): Promise { window.addEventListener('resize', this._handleWindowResize); - const options = await this._waitForOptionsToLoad(); + const options = this._model.getOptions(); const center = options.longitude !== undefined && options.latitude !== undefined ? fromLonLat([options.longitude!, options.latitude!]) : [0, 0]; const zoom = options.zoom !== undefined ? options.zoom! : 1; await this.generateScene(center, zoom); - await this.updateOptions(options); this.addContextMenu(); this._mainViewModel.initSignal(); @@ -1431,47 +1430,6 @@ export class MainView extends React.Component { }); } - private _waitForOptionsToLoad(timeout = 250): Promise { - return new Promise(resolve => { - let timerId: number; - - const endWaiting = () => { - clearTimeout(timerId); - resolve(this._model.getOptions()); - }; - - const handler = () => { - const options = this._model.getOptions(); - - // When widget is built for the second time, some extra options are added - // So we ignore some options when we check if options are loaded or not - const ignore = new Set(['extent', 'useExtent', 'zoom']); - - const realKeys = Object.entries(options) - .filter(([k, v]) => { - if (ignore.has(k)) { - return false; - } - if (typeof v === 'string') { - return v.length > 0; - } - if (typeof v === 'number') { - return v !== 0; - } - return v != null; - }) - .map(([k]) => k); - - if (realKeys.length > 0) { - endWaiting(); - } - }; - - timerId = window.setTimeout(endWaiting, timeout); - handler(); - }); - } - /** * Remove a layer from the map. * @@ -1598,12 +1556,6 @@ export class MainView extends React.Component { } private async updateOptions(options: IJGISOptions): Promise { - if (!this._Map) { - console.warn( - 'Options are trying to be updated when there is no OL map initialized', - ); - return; - } const { projection, extent, diff --git a/yarn.lock b/yarn.lock index f988b3835..9b4080186 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4254,45 +4254,6 @@ __metadata: languageName: node linkType: hard -"array.prototype.findlastindex@npm:^1.2.5": - version: 1.2.6 - resolution: "array.prototype.findlastindex@npm:1.2.6" - dependencies: - call-bind: ^1.0.8 - call-bound: ^1.0.4 - define-properties: ^1.2.1 - es-abstract: ^1.23.9 - es-errors: ^1.3.0 - es-object-atoms: ^1.1.1 - es-shim-unscopables: ^1.1.0 - checksum: bd2665bd51f674d4e1588ce5d5848a8adb255f414070e8e652585598b801480516df2c6cef2c60b6ea1a9189140411c49157a3f112d52e9eabb4e9fc80936ea6 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.2": - version: 1.3.3 - resolution: "array.prototype.flat@npm:1.3.3" - dependencies: - call-bind: ^1.0.8 - define-properties: ^1.2.1 - es-abstract: ^1.23.5 - es-shim-unscopables: ^1.0.2 - checksum: 5d5a7829ab2bb271a8d30a1c91e6271cef0ec534593c0fe6d2fb9ebf8bb62c1e5326e2fddcbbcbbe5872ca04f5e6b54a1ecf092e0af704fb538da9b2bfd95b40 - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.2": - version: 1.3.3 - resolution: "array.prototype.flatmap@npm:1.3.3" - dependencies: - call-bind: ^1.0.8 - define-properties: ^1.2.1 - es-abstract: ^1.23.5 - es-shim-unscopables: ^1.0.2 - checksum: 11b4de09b1cf008be6031bb507d997ad6f1892e57dc9153583de6ebca0f74ea403fffe0f203461d359de05048d609f3f480d9b46fed4099652d8b62cc972f284 - languageName: node - linkType: hard - "arraybuffer.prototype.slice@npm:^1.0.4": version: 1.0.4 resolution: "arraybuffer.prototype.slice@npm:1.0.4" @@ -11403,6 +11364,15 @@ __metadata: languageName: node linkType: hard +"three-mesh-bvh@npm:^0.5.17": + version: 0.5.24 + resolution: "three-mesh-bvh@npm:0.5.24" + peerDependencies: + three: ">= 0.123.0" + checksum: 5a5e356111756869cfd00870bca2d881d3019b55e71142b5eee544a2e6bcc3546a340b0defa29c3ebe7ed4cfe99e7ee6addd5671bb89852841107189c0f98157 + languageName: node + linkType: hard + "three@npm:^0.135.0": version: 0.135.0 resolution: "three@npm:0.135.0" @@ -11926,6 +11896,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^11.0.3": + version: 11.1.0 + resolution: "uuid@npm:11.1.0" + bin: + uuid: dist/esm/bin/uuid + checksum: 840f19758543c4631e58a29439e51b5b669d5f34b4dd2700b6a1d15c5708c7a6e0c3e2c8c4a2eae761a3a7caa7e9884d00c86c02622ba91137bd3deade6b4b4a + languageName: node + linkType: hard + "uuid@npm:^9.0.0": version: 9.0.1 resolution: "uuid@npm:9.0.1"