diff --git a/demo/src/app/app.component.html b/demo/src/app/app.component.html
index 900fbae6a9..e07f90cfc4 100644
--- a/demo/src/app/app.component.html
+++ b/demo/src/app/app.component.html
@@ -45,6 +45,7 @@
{{title}}
Catalog
Search
Print
+ Import/Export
Directions
Time filter
OGC filter
diff --git a/demo/src/app/app.module.ts b/demo/src/app/app.module.ts
index 95f7d14188..ab67b41e84 100644
--- a/demo/src/app/app.module.ts
+++ b/demo/src/app/app.module.ts
@@ -39,6 +39,7 @@ import { AppQueryModule } from './geo/query/query.module';
import { AppCatalogModule } from './geo/catalog/catalog.module';
import { AppSearchModule } from './geo/search/search.module';
import { AppPrintModule } from './geo/print/print.module';
+import { AppImportExport } from './geo/import-export/import-export.module';
import { AppDirectionsModule } from './geo/directions/directions.module';
import { AppTimeFilterModule } from './geo/time-filter/time-filter.module';
import { AppOgcFilterModule } from './geo/ogc-filter/ogc-filter.module';
@@ -89,6 +90,7 @@ import { AppComponent } from './app.component';
AppCatalogModule,
AppSearchModule,
AppPrintModule,
+ AppImportExport,
AppDirectionsModule,
AppTimeFilterModule,
AppOgcFilterModule,
diff --git a/demo/src/app/geo/import-export/import-export-routing.module.ts b/demo/src/app/geo/import-export/import-export-routing.module.ts
new file mode 100644
index 0000000000..f1a8040768
--- /dev/null
+++ b/demo/src/app/geo/import-export/import-export-routing.module.ts
@@ -0,0 +1,15 @@
+import { Routes, RouterModule } from '@angular/router';
+import { ModuleWithProviders } from '@angular/core';
+
+import { AppImportExportComponent } from './import-export.component';
+
+const routes: Routes = [
+ {
+ path: 'import-export',
+ component: AppImportExportComponent
+ }
+];
+
+export const AppImportExportRoutingModule: ModuleWithProviders = RouterModule.forChild(
+ routes
+);
diff --git a/demo/src/app/geo/import-export/import-export.component.html b/demo/src/app/geo/import-export/import-export.component.html
new file mode 100644
index 0000000000..849620ce06
--- /dev/null
+++ b/demo/src/app/geo/import-export/import-export.component.html
@@ -0,0 +1,20 @@
+
+ Geo
+ Import / Export
+
+ Dependencies: LanguageService
+
+
+ See the code of this example
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/app/geo/import-export/import-export.component.scss b/demo/src/app/geo/import-export/import-export.component.scss
new file mode 100644
index 0000000000..d481ae2940
--- /dev/null
+++ b/demo/src/app/geo/import-export/import-export.component.scss
@@ -0,0 +1,4 @@
+igo-map-browser {
+ width: 900px;
+ height: 1000px;
+}
diff --git a/demo/src/app/geo/import-export/import-export.component.ts b/demo/src/app/geo/import-export/import-export.component.ts
new file mode 100644
index 0000000000..c2a40234c2
--- /dev/null
+++ b/demo/src/app/geo/import-export/import-export.component.ts
@@ -0,0 +1,43 @@
+import { Component } from '@angular/core';
+
+import { LanguageService } from '@igo2/core';
+import { IgoMap, LayerService } from '@igo2/geo';
+
+@Component({
+ selector: 'app-import-export',
+ templateUrl: './import-export.component.html',
+ styleUrls: ['./import-export.component.scss']
+})
+export class AppImportExportComponent {
+ public map = new IgoMap({
+ controls: {
+ attribution: {
+ collapsed: true
+ }
+ }
+ });
+
+ public view = {
+ center: [-73, 47.2],
+ zoom: 9
+ };
+
+ constructor(
+ private languageService: LanguageService,
+ private layerService: LayerService
+ ) {
+ this.layerService
+ .createAsyncLayer({
+ title: 'Quebec Base Map',
+ sourceOptions: {
+ type: 'wmts',
+ url: '/carto/wmts/1.0.0/wmts',
+ layer: 'carte_gouv_qc_ro',
+ matrixSet: 'EPSG_3857',
+ version: '1.3.0'
+ }
+ })
+ .subscribe(l => this.map.addLayer(l));
+
+ }
+}
diff --git a/demo/src/app/geo/import-export/import-export.module.ts b/demo/src/app/geo/import-export/import-export.module.ts
new file mode 100644
index 0000000000..9541865280
--- /dev/null
+++ b/demo/src/app/geo/import-export/import-export.module.ts
@@ -0,0 +1,22 @@
+import { NgModule } from '@angular/core';
+import { MatCardModule, MatButtonModule } from '@angular/material';
+
+import { IgoMessageModule } from '@igo2/core';
+import { IgoMapModule, IgoImportExportModule } from '@igo2/geo';
+
+import { AppImportExportComponent } from './import-export.component';
+import { AppImportExportRoutingModule } from './import-export-routing.module';
+
+@NgModule({
+ declarations: [AppImportExportComponent],
+ imports: [
+ AppImportExportRoutingModule,
+ MatCardModule,
+ MatButtonModule,
+ IgoMessageModule,
+ IgoMapModule,
+ IgoImportExportModule
+ ],
+ exports: [AppImportExportComponent]
+})
+export class AppImportExport {}
diff --git a/demo/src/environments/environment.ts b/demo/src/environments/environment.ts
index c2125809ab..5ebbe609a7 100644
--- a/demo/src/environments/environment.ts
+++ b/demo/src/environments/environment.ts
@@ -28,6 +28,9 @@ export const environment: Environment = {
language: {
prefix: './locale/'
},
+ importExport: {
+ url: 'https://testgeoegl.msp.gouv.qc.ca/apis/ogre'
+ },
catalog: {
sources: [
{
diff --git a/packages/geo/src/lib/import-export/import-export.module.ts b/packages/geo/src/lib/import-export/import-export.module.ts
index 38b8d2858f..7122aaa17d 100644
--- a/packages/geo/src/lib/import-export/import-export.module.ts
+++ b/packages/geo/src/lib/import-export/import-export.module.ts
@@ -11,7 +11,7 @@ import {
} from '@angular/material';
import { IgoLanguageModule } from '@igo2/core';
-import { IgoKeyValueModule, IgoDrapDropModule } from '@igo2/common';
+import { IgoKeyValueModule, IgoDrapDropModule, IgoSpinnerModule } from '@igo2/common';
import { ImportExportComponent } from './import-export/import-export.component';
import { DropGeoFileDirective } from './shared/drop-geo-file.directive';
@@ -28,6 +28,7 @@ import { DropGeoFileDirective } from './shared/drop-geo-file.directive';
MatFormFieldModule,
MatInputModule,
IgoLanguageModule,
+ IgoSpinnerModule,
IgoKeyValueModule,
IgoDrapDropModule
],
diff --git a/packages/geo/src/lib/import-export/import-export/import-export.component.html b/packages/geo/src/lib/import-export/import-export/import-export.component.html
index 0b4e1bc8e0..8657764df4 100644
--- a/packages/geo/src/lib/import-export/import-export/import-export.component.html
+++ b/packages/geo/src/lib/import-export/import-export/import-export.component.html
@@ -13,9 +13,10 @@
-
+
+ {{'igo.geo.importExportForm.importClarifications' | translate}}
+
+ - {{'igo.geo.importExportForm.importSizeMax' | translate}}
+ - {{'igo.geo.importExportForm.importShpZip' | translate}}
+
@@ -57,10 +64,11 @@
{{'igo.geo.importExportForm.exportButton' | translate}}
+
diff --git a/packages/geo/src/lib/import-export/import-export/import-export.component.scss b/packages/geo/src/lib/import-export/import-export/import-export.component.scss
index 2eda22baf7..8fcdaee323 100644
--- a/packages/geo/src/lib/import-export/import-export/import-export.component.scss
+++ b/packages/geo/src/lib/import-export/import-export/import-export.component.scss
@@ -10,3 +10,8 @@ mat-form-field {
text-align: center;
padding-top: 10px;
}
+
+igo-spinner {
+ position: absolute;
+ padding-left: 10px;
+}
diff --git a/packages/geo/src/lib/import-export/import-export/import-export.component.ts b/packages/geo/src/lib/import-export/import-export/import-export.component.ts
index 55e5a52ad4..57c8868a8a 100644
--- a/packages/geo/src/lib/import-export/import-export/import-export.component.ts
+++ b/packages/geo/src/lib/import-export/import-export/import-export.component.ts
@@ -1,6 +1,6 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
-import { Subscription } from 'rxjs';
+import { Subscription, throwError } from 'rxjs';
import { MessageService, LanguageService } from '@igo2/core';
@@ -14,7 +14,10 @@ import { ExportOptions } from '../shared/export.interface';
import { ExportFormat } from '../shared/export.type';
import { ExportService } from '../shared/export.service';
import { ImportService } from '../shared/import.service';
-import { handleFileImportSuccess, handleFileImportError } from '../shared/import.utils';
+import {
+ handleFileImportSuccess,
+ handleFileImportError
+} from '../shared/import.utils';
@Component({
selector: 'igo-import-export',
@@ -22,11 +25,11 @@ import { handleFileImportSuccess, handleFileImportError } from '../shared/import
styleUrls: ['./import-export.component.scss']
})
export class ImportExportComponent implements OnDestroy, OnInit {
-
public form: FormGroup;
public formats = ExportFormat;
public layers: VectorLayer[];
public inputProj: string = 'EPSG:4326';
+ public loading = false;
private layers$$: Subscription;
@@ -44,10 +47,9 @@ export class ImportExportComponent implements OnDestroy, OnInit {
ngOnInit() {
this.layers$$ = this.map.layers$.subscribe(layers => {
- this.layers = layers
- .filter((layer: Layer) => {
- return layer instanceof VectorLayer && layer.exportable === true;
- }) as VectorLayer[];
+ this.layers = layers.filter((layer: Layer) => {
+ return layer instanceof VectorLayer && layer.exportable === true;
+ }) as VectorLayer[];
});
}
@@ -56,6 +58,7 @@ export class ImportExportComponent implements OnDestroy, OnInit {
}
importFiles(files: File[]) {
+ this.loading = true;
for (const file of files) {
this.importService
.import(file, this.inputProj)
@@ -67,12 +70,13 @@ export class ImportExportComponent implements OnDestroy, OnInit {
}
handleExportFormSubmit(data: ExportOptions) {
+ this.loading = true;
const layer = this.map.getLayerById(data.layer);
const olFeatures = layer.dataSource.ol.getFeatures();
this.exportService
.export(olFeatures, data.format, layer.title, this.map.projection)
.subscribe(
- () => {},
+ () => { this.loading = false;},
(error: Error) => this.onFileExportError(error)
);
}
@@ -85,14 +89,28 @@ export class ImportExportComponent implements OnDestroy, OnInit {
}
private onFileImportSuccess(file: File, features: Feature[]) {
- handleFileImportSuccess(file, features, this.map, this.messageService, this.languageService);
+ this.loading = false;
+ handleFileImportSuccess(
+ file,
+ features,
+ this.map,
+ this.messageService,
+ this.languageService
+ );
}
private onFileImportError(file: File, error: Error) {
- handleFileImportError(file, error, this.messageService, this.languageService);
+ this.loading = false;
+ handleFileImportError(
+ file,
+ error,
+ this.messageService,
+ this.languageService
+ );
}
private onFileExportError(error: Error) {
+ this.loading = false;
handleFileExportError(error, this.messageService, this.languageService);
}
}
diff --git a/packages/geo/src/lib/import-export/shared/export.errors.ts b/packages/geo/src/lib/import-export/shared/export.errors.ts
index 89131ba764..deb0a6eb03 100644
--- a/packages/geo/src/lib/import-export/shared/export.errors.ts
+++ b/packages/geo/src/lib/import-export/shared/export.errors.ts
@@ -2,14 +2,14 @@ export class ExportError extends Error {}
export class ExportInvalidFileError extends ExportError {
constructor() {
- super('Invalid file.');
+ super('Invalid file');
Object.setPrototypeOf(this, ExportInvalidFileError.prototype);
}
}
export class ExportNothingToExportError extends ExportError {
constructor() {
- super('Nothing to export.');
+ super('Nothing to export');
Object.setPrototypeOf(this, ExportNothingToExportError.prototype);
}
}
diff --git a/packages/geo/src/lib/import-export/shared/import.errors.ts b/packages/geo/src/lib/import-export/shared/import.errors.ts
index 9d22a5c02c..4d25b3fa4a 100644
--- a/packages/geo/src/lib/import-export/shared/import.errors.ts
+++ b/packages/geo/src/lib/import-export/shared/import.errors.ts
@@ -2,21 +2,35 @@ export class ImportError extends Error {}
export class ImportInvalidFileError extends ImportError {
constructor() {
- super('Invalid file.');
+ super('Invalid file');
Object.setPrototypeOf(this, ImportInvalidFileError.prototype);
}
}
export class ImportUnreadableFileError extends ImportError {
constructor() {
- super('Failed to read file.');
+ super('Failed to read file');
Object.setPrototypeOf(this, ImportUnreadableFileError.prototype);
}
}
export class ImportNothingToImportError extends ImportError {
constructor() {
- super('Nothing to import.');
+ super('Nothing to import');
+ Object.setPrototypeOf(this, ImportNothingToImportError.prototype);
+ }
+}
+
+export class ImportSizeError extends ImportError {
+ constructor() {
+ super('File is too large');
+ Object.setPrototypeOf(this, ImportNothingToImportError.prototype);
+ }
+}
+
+export class ImportSRSError extends ImportError {
+ constructor() {
+ super('Invalid SRS definition');
Object.setPrototypeOf(this, ImportNothingToImportError.prototype);
}
}
diff --git a/packages/geo/src/lib/import-export/shared/import.service.ts b/packages/geo/src/lib/import-export/shared/import.service.ts
index 979b2541c4..0467d8c4b5 100644
--- a/packages/geo/src/lib/import-export/shared/import.service.ts
+++ b/packages/geo/src/lib/import-export/shared/import.service.ts
@@ -10,7 +10,7 @@ import * as olformat from 'ol/format';
import OlFeature from 'ol/Feature';
import { Feature } from '../../feature/shared/feature.interfaces';
-import { ImportInvalidFileError, ImportUnreadableFileError } from './import.errors';
+import { ImportInvalidFileError, ImportUnreadableFileError, ImportSizeError, ImportSRSError } from './import.errors';
import { computeLayerTitleFromFile, getFileExtension } from './import.utils';
@Injectable({
@@ -71,6 +71,10 @@ export class ImportService {
private importAsync(file: File, projectionIn: string, projectionOut: string): Observable {
const doImport = (observer: Observer) => {
+ if (file.size >= 30000000) {
+ observer.error(new ImportSizeError());
+ return;
+ }
const importer = this.getFileImporter(file);
if (importer === undefined) {
observer.error(new ImportInvalidFileError());
@@ -136,8 +140,16 @@ export class ImportService {
observer.complete();
}
},
- (error: Error) => {
- observer.error(new ImportUnreadableFileError());
+ (error: any) => {
+ error.error.caught = true;
+ const errMsg = error.error.msg;
+ if (errMsg === 'No valid files found') {
+ observer.error(new ImportInvalidFileError());
+ } else if (errMsg.startWith("ERROR 1: Failed to process SRS definition")) {
+ observer.error(new ImportSRSError());
+ } else {
+ observer.error(new ImportUnreadableFileError());
+ }
}
);
}
diff --git a/packages/geo/src/lib/import-export/shared/import.utils.ts b/packages/geo/src/lib/import-export/shared/import.utils.ts
index 423189c3f8..d612fe7429 100644
--- a/packages/geo/src/lib/import-export/shared/import.utils.ts
+++ b/packages/geo/src/lib/import-export/shared/import.utils.ts
@@ -56,7 +56,7 @@ export function handleFileImportSuccess(
languageService: LanguageService
) {
if (features.length === 0) {
- this.handleNothingToImportError(file, messageService, languageService);
+ handleNothingToImportError(file, messageService, languageService);
return;
}
@@ -76,6 +76,21 @@ export function handleFileImportError(
error: Error,
messageService: MessageService,
languageService: LanguageService
+) {
+ const errMapping = {
+ "Invalid file": handleInvalidFileImportError,
+ "File is too large": handleSizeFileImportError,
+ "Failed to read file": handleUnreadbleFileImportError,
+ "Invalid SRS definition": handleSRSImportError
+ }
+ errMapping[error.message](file, error, messageService, languageService);
+}
+
+export function handleInvalidFileImportError(
+ file: File,
+ error: Error,
+ messageService: MessageService,
+ languageService: LanguageService
) {
const translate = languageService.translate;
const title = translate.instant('igo.geo.dropGeoFile.invalid.title');
@@ -86,6 +101,34 @@ export function handleFileImportError(
messageService.error(message, title);
}
+export function handleUnreadbleFileImportError(
+ file: File,
+ error: Error,
+ messageService: MessageService,
+ languageService: LanguageService
+) {
+ const translate = languageService.translate;
+ const title = translate.instant('igo.geo.dropGeoFile.unreadable.title');
+ const message = translate.instant('igo.geo.dropGeoFile.unreadable.text', {
+ value: file.name
+ });
+ messageService.error(message, title);
+}
+
+export function handleSizeFileImportError(
+ file: File,
+ error: Error,
+ messageService: MessageService,
+ languageService: LanguageService
+) {
+ const translate = languageService.translate;
+ const title = translate.instant('igo.geo.dropGeoFile.tooLarge.title');
+ const message = translate.instant('igo.geo.dropGeoFile.tooLarge.text', {
+ value: file.name
+ });
+ messageService.error(message, title);
+}
+
export function handleNothingToImportError(
file: File,
messageService: MessageService,
@@ -100,6 +143,20 @@ export function handleNothingToImportError(
messageService.error(message, title);
}
+export function handleSRSImportError(
+ file: File,
+ messageService: MessageService,
+ languageService: LanguageService
+) {
+ const translate = languageService.translate;
+ const title = translate.instant('igo.geo.dropGeoFile.invalidSRS.title');
+ const message = translate.instant('igo.geo.dropGeoFile.invalidSRS.text', {
+ value: file.name,
+ mimeType: file.type
+ });
+ messageService.error(message, title);
+}
+
export function getFileExtension(file: File): string {
return file.name.split('.').pop().toLowerCase();
}
diff --git a/packages/geo/src/locale/en.geo.json b/packages/geo/src/locale/en.geo.json
index 5d7a46e3ff..386e30e8e9 100644
--- a/packages/geo/src/locale/en.geo.json
+++ b/packages/geo/src/locale/en.geo.json
@@ -30,6 +30,14 @@
"unreadable": {
"text": "Unreadable file",
"title": "The file '{{value}}' is unreadable"
+ },
+ "tooLarge": {
+ "text": "The file '{{value}}' is too large (Max: 30 mb)",
+ "title": "File too large"
+ },
+ "invalidSRS": {
+ "text": "The projection is valid. It must start with EPSG:",
+ "title": "Invalid projection"
}
},
"export": {
@@ -49,7 +57,10 @@
"exportTabTitle": "Export",
"importButton": "Import",
"importProjPlaceholder": "Coordinate system",
- "importTabTitle": "Import"
+ "importTabTitle": "Import",
+ "importClarifications": "Clarifications",
+ "importSizeMax": "The file size limit is 30 mb.",
+ "importShpZip": "Shapefiles must be zipped."
},
"operators": {
"And": "And",
diff --git a/packages/geo/src/locale/fr.geo.json b/packages/geo/src/locale/fr.geo.json
index 959e009b28..2900f8cf56 100644
--- a/packages/geo/src/locale/fr.geo.json
+++ b/packages/geo/src/locale/fr.geo.json
@@ -20,7 +20,7 @@
"title": "Fichier invalide"
},
"empty": {
- "text": "Le fichier '{{value}}' est vide, impossible d'importer.",
+ "text": "Le fichier '{{value}}' est vide, impossible d'importer",
"title": "Fichier vide"
},
"success": {
@@ -30,6 +30,14 @@
"unreadable": {
"text": "Le fichier '{{value}}' est impossible à lire",
"title": "Fichier illisible"
+ },
+ "tooLarge": {
+ "text": "Le fichier '{{value}}' est trop volumineux (Maximun: 30 mb)",
+ "title": "Fichier trop volumineux"
+ },
+ "invalidSRS": {
+ "text": "La projection est valide. Elle doit commencer par EPSG:",
+ "title": "Projection invalid"
}
},
"export": {
@@ -49,7 +57,10 @@
"exportTabTitle": "Exporter",
"importButton": "Importer",
"importProjPlaceholder": "Système de coordonnées",
- "importTabTitle": "Importer"
+ "importTabTitle": "Importer",
+ "importClarifications": "Précisions",
+ "importSizeMax": "La taille limite du fichier est de 30 mb.",
+ "importShpZip": "Les shapefiles doivent être compressés (zippés)"
},
"operators": {
"And": "Et",