Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(context): Import export context #693

Merged
merged 45 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
930cf17
Merge pull request #5 from infra-geo-ouverte/1.0.0-alpha
drekss Aug 9, 2019
e1e5d45
Merge pull request #8 from infra-geo-ouverte/1.0.0-alpha
drekss Aug 13, 2019
aa8c4e3
Merge pull request #12 from infra-geo-ouverte/1.0.0-alpha
drekss Aug 28, 2019
74ca893
Merge pull request #16 from infra-geo-ouverte/master
drekss Sep 29, 2019
e04d3b8
Merge pull request #17 from infra-geo-ouverte/master
drekss Oct 4, 2019
ce783db
Merge pull request #18 from infra-geo-ouverte/master
drekss Oct 11, 2019
af80ed7
Merge pull request #19 from infra-geo-ouverte/master
drekss Oct 29, 2019
197663e
Merge pull request #20 from infra-geo-ouverte/master
drekss Oct 29, 2019
16532c1
Merge pull request #21 from infra-geo-ouverte/master
drekss Oct 30, 2019
f2a365a
Merge pull request #22 from infra-geo-ouverte/master
drekss Oct 31, 2019
776658c
Merge pull request #25 from infra-geo-ouverte/master
drekss Nov 9, 2019
dafec8a
Merge pull request #26 from infra-geo-ouverte/master
drekss Nov 15, 2019
2765fef
Merge pull request #28 from infra-geo-ouverte/master
drekss Dec 5, 2019
1d3547b
Merge pull request #30 from infra-geo-ouverte/master
drekss Dec 18, 2019
2b7387a
Merge pull request #32 from infra-geo-ouverte/master
drekss Feb 28, 2020
72587a3
add params to clusterStyle
May 5, 2020
46d3481
Merge pull request #39 from infra-geo-ouverte/next
drekss May 11, 2020
d309ca3
Merge pull request #40 from infra-geo-ouverte/next
drekss May 25, 2020
83102ba
Merge pull request #41 from infra-geo-ouverte/next
drekss Jun 4, 2020
d098469
Merge pull request #42 from infra-geo-ouverte/next
drekss Jun 10, 2020
aac0c7e
Merge pull request #43 from infra-geo-ouverte/next
drekss Jun 18, 2020
04a2901
Merge pull request #44 from infra-geo-ouverte/next
drekss Jun 30, 2020
b4c8520
Merge pull request #46 from infra-geo-ouverte/next
drekss Jul 7, 2020
2abf2b8
Merge pull request #47 from infra-geo-ouverte/next
drekss Jul 9, 2020
0131c62
context import export
Jul 13, 2020
8aa99c4
fix radio-button
Jul 13, 2020
a8742c7
change interface
Jul 29, 2020
961f08c
enhanced interface
Jul 30, 2020
61a9c08
remove zip type from import context
Jul 30, 2020
1db5e1e
Update context-import-export.component.ts
mbarbeau Jul 30, 2020
27a08f2
Update context-export.service.ts
mbarbeau Jul 30, 2020
34c72f8
Update context-import.service.ts
mbarbeau Jul 30, 2020
5e2a520
Update context-import.utils.ts
mbarbeau Jul 30, 2020
575a8d2
Update index.ts
mbarbeau Jul 30, 2020
3636bc2
Update import-export-tool.component.ts
mbarbeau Jul 30, 2020
77026b0
fix baseLayer export from context
Jul 31, 2020
cca0c98
merge
Jul 31, 2020
79aa984
remove base context condition, splice instead of delete, remove conso…
Aug 3, 2020
e169ac0
remove enhancedContext$
Aug 3, 2020
be9c169
Merge branch 'next' into import-export-context-push
mbarbeau Aug 3, 2020
1eb88a4
refactoring
mbarbeau Aug 4, 2020
a3eb8d3
lint
mbarbeau Aug 4, 2020
b3523ed
refactoring
mbarbeau Aug 4, 2020
94ba9c0
refactoring
mbarbeau Aug 4, 2020
b4d626f
fix id comparaison
mbarbeau Aug 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"singleQuote": true,
"trailingComma": "none",
"prettier.disableLanguages": ["html"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatDividerModule,
MatTabsModule,
MatSelectModule,
MatOptionModule,
MatTooltipModule,
MatCheckboxModule,
MatButtonToggleModule,
} from '@angular/material';
import { IgoLanguageModule } from '@igo2/core';
import { ContextImportExportComponent } from './context-import-export/context-import-export.component';
import { IgoSpinnerModule } from '@igo2/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
imports: [
FormsModule,
ReactiveFormsModule,
CommonModule,
MatButtonModule,
MatButtonToggleModule,
MatDividerModule,
MatTabsModule,
MatSelectModule,
MatOptionModule,
MatFormFieldModule,
MatInputModule,
MatCheckboxModule,
IgoLanguageModule,
IgoSpinnerModule,
MatTooltipModule,
],
exports: [
ContextImportExportComponent
],
declarations: [
ContextImportExportComponent
]
})
export class IgoContextImportExportModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: IgoContextImportExportModule
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<div class="import-export-toggle mat-typography">
<mat-button-toggle-group
[value]="activeImportExport"
(change)="onImportExportChange($event)">
<mat-button-toggle [value]="'import'">
{{'igo.geo.importExportForm.importTabTitle' | translate}}
</mat-button-toggle>
<mat-button-toggle [value]="'export'">
{{'igo.geo.importExportForm.exportTabTitle' | translate}}
</mat-button-toggle>
</mat-button-toggle-group>
</div>

<div *ngIf="activeImportExport === 'import'">
<form class="igo-form">
<div class="igo-form-button-group">
<button mat-raised-button type="button" (click)="fileInput.click()" [disabled]="loading$ | async">
{{'igo.geo.importExportForm.importButton' | translate}}
</button>
<igo-spinner [shown]="loading$ | async"></igo-spinner>
<input
#fileInput
type="file"
[style.display]="'none'"
(click)="fileInput.value = null"
(change)="importFiles($event.target.files)">
</div>
</form>
<section class="mat-typography">
<h4>{{'igo.geo.importExportForm.importClarifications' | translate}}</h4>
<ul>
<li>{{'igo.geo.importExportForm.importSizeMax' | translate: {size: fileSizeMb} }}</li>
</ul>
</section>
</div>


<form class="igo-form" *ngIf="activeImportExport === 'export'" [formGroup]="form">
<div class="igo-input-container">
<mat-form-field class="example-full-width">
<mat-label>{{'igo.context.contextImportExport.export.exportContextName' | translate}}</mat-label>
<input formControlName="name" matInput [value]="">
</mat-form-field>
</div>
<div class="igo-input-container">
<mat-form-field>
<mat-label>{{'igo.context.contextImportExport.export.exportPlaceHolder' | translate}}</mat-label>
<mat-select formControlName="layers" multiple>
<mat-option [value]="1" (click)="selectAll(e)" #e>
{{'igo.context.contextImportExport.export.exportSelectAll' | translate}}
</mat-option>
<mat-divider></mat-divider>
<mat-option *ngFor="let layer of layerList" [value]="layer">{{layer.title}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="igo-form-button-group">
<button
mat-raised-button
type="button"
[disabled]="!form.valid || (loading$ | async)"
(click)="handleExportFormSubmit(form.value)">
{{'igo.geo.importExportForm.exportButton' | translate}}
</button>
<igo-spinner [shown]="loading$ | async"></igo-spinner>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.import-export-toggle {
padding: 10px;
text-align: center;

mat-button-toggle-group {
width: 100%;

mat-button-toggle {
width: 50%;
}
}
}

.igo-input-container {
padding: 10px;

mat-form-field {
width: 100%;
}
}

h4 {
padding: 0 5px;
}

.igo-form {
padding: 15px 5px;
}

.igo-form-button-group {
text-align: center;
padding-top: 10px;
}

igo-spinner {
position: absolute;
padding-left: 10px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { BehaviorSubject } from 'rxjs';

import { MessageService, LanguageService, ConfigService } from '@igo2/core';
import { IgoMap, Layer, VectorLayer } from '@igo2/geo';

import { handleFileExportError } from '../shared/context-export.utils';
import {
handleFileImportSuccess,
handleFileImportError
} from '../shared/context-import.utils';
import { handleFileExportSuccess } from '../shared/context-export.utils';
import { ContextService } from '../../context-manager/shared/context.service';
import { ContextImportService } from '../shared/context-import.service';
import { ContextExportService } from '../shared/context-export.service';
import { DetailedContext } from '../../context-manager/shared/context.interface';

@Component({
selector: 'igo-context-import-export',
templateUrl: './context-import-export.component.html',
styleUrls: ['./context-import-export.component.scss']
})
export class ContextImportExportComponent implements OnInit {
public form: FormGroup;
public layers: VectorLayer[];
public inputProj: string = 'EPSG:4326';
public loading$ = new BehaviorSubject(false);
public forceNaming = false;
public layerList: Layer[];
public res: DetailedContext;
private clientSideFileSizeMax: number;
public fileSizeMb: number;
public activeImportExport: string = 'import';

@Input() map: IgoMap;

constructor(
private contextImportService: ContextImportService,
private contextExportService: ContextExportService,
private languageService: LanguageService,
private messageService: MessageService,
private formBuilder: FormBuilder,
private config: ConfigService,
private contextService: ContextService
) {
this.buildForm();
}

ngOnInit() {
const configFileSizeMb = this.config.getConfig(
'importExport.clientSideFileSizeMaxMb'
);
this.clientSideFileSizeMax =
(configFileSizeMb ? configFileSizeMb : 30) * Math.pow(1024, 2);
this.fileSizeMb = this.clientSideFileSizeMax / Math.pow(1024, 2);
this.layerList = this.contextService.getContextLayers(this.map);
}

importFiles(files: File[]) {
this.loading$.next(true);
for (const file of files) {
this.contextImportService.import(file).subscribe(
(context: DetailedContext) => this.onFileImportSuccess(file, context),
(error: Error) => this.onFileImportError(file, error),
() => {
this.loading$.next(false);
}
);
}
}

handleExportFormSubmit(contextOptions) {
this.loading$.next(true);
this.res = this.contextService.getContextFromLayers(this.map, contextOptions.layers, contextOptions.name);
this.res.imported = true;
this.contextExportService
.export(this.res)
.subscribe(
() => {},
(error: Error) => this.onFileExportError(error),
() => {
this.onFileExportSuccess();
this.loading$.next(false);
}
);
}

private buildForm() {
this.form = this.formBuilder.group({
layers: ['', [Validators.required]],
name: ['', [Validators.required]]
});
}

private onFileImportSuccess(file: File, context: DetailedContext) {
handleFileImportSuccess(
file,
context,
this.messageService,
this.languageService,
this.contextService
);
}

private onFileImportError(file: File, error: Error) {
this.loading$.next(false);
handleFileImportError(
file,
error,
this.messageService,
this.languageService,
this.fileSizeMb
);
}

private onFileExportError(error: Error) {
this.loading$.next(false);
handleFileExportError(error, this.messageService, this.languageService);
}

private onFileExportSuccess() {
handleFileExportSuccess(this.messageService, this.languageService);
}

selectAll(e) {
if (e._selected) {
this.form.controls.layers.setValue(this.layerList);
e._selected = true;
}
if (e._selected === false) {
this.form.controls.layers.setValue([]);
}
}

onImportExportChange(event) {
this.activeImportExport = event.value;
}
}
2 changes: 2 additions & 0 deletions packages/context/src/lib/context-import-export/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './shared';
export * from './context-import-export/context-import-export.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';

import { ConfigService } from '@igo2/core';
import { downloadContent } from '@igo2/utils';

import { DetailedContext } from '../../context-manager/shared/context.interface';
import { ExportNothingToExportError } from './context-export.errors';
import { Observer, Observable } from 'rxjs';

import { Platform } from '@ionic/angular';
import { File } from '@ionic-native/file/ngx';
import { FileOpener } from '@ionic-native/file-opener/ngx';
import { ContextExportService } from './context-export.service';

@Injectable({
providedIn: 'root'
})
export class ContextExportIonicService extends ContextExportService {

constructor(
private config: ConfigService,
private platform: Platform,
private fileOpener: FileOpener,
private file: File
) {
super();
}

protected exportAsync(res: DetailedContext): Observable<void> {
const doExport = (observer: Observer<void>) => {
const nothingToExport = super.nothingToExport(res);
if (nothingToExport === true) {
observer.error(new ExportNothingToExportError());
return;
}

const contextJSON = JSON.stringify(res);

if (this.platform.is('cordova')) {
const directory = this.config.getConfig('ExportDirectory');
this.file.writeFile(directory, `${res.uri}.json`, contextJSON, { replace: true }).then((success) =>
this.fileOpener.open(directory + '/' + `${res.uri}.json`, 'text/plain'));
observer.complete();
} else {
downloadContent(contextJSON, 'text/json;charset=utf-8', `${res.uri}.json`);
observer.complete();
}
};
return new Observable(doExport);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class ExportError extends Error {}

export class ExportInvalidFileError extends ExportError {
constructor() {
super('Invalid context');
Object.setPrototypeOf(this, ExportInvalidFileError.prototype);
}
}

export class ExportNothingToExportError extends ExportError {
constructor() {
super('Nothing to export');
Object.setPrototypeOf(this, ExportNothingToExportError.prototype);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Layer } from '@igo2/geo';

export interface ContextExportOptions {
layer: Layer[];
name: string;
}
Loading