Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@
"dist/common/assets/fonts/material-design-icons/material-icons.css",
"node_modules/codemirror/lib/codemirror.css",
"node_modules/ol/ol.css",
"./node_modules/vis-timeline/dist/vis-timeline-graph2d.min.css"
"./node_modules/vis-timeline/dist/vis-timeline-graph2d.min.css",
"node_modules/workflow-editor/src/workflow_editor/static/widget.css",
"node_modules/@fortawesome/fontawesome-free/css/all.min.css"
],
"scripts": ["node_modules/vis-timeline/peer/esm/vis-timeline-graph2d.min.js"],
"vendorChunk": true,
Expand Down
257 changes: 257 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"@egjs/hammerjs": "^2.0.17",
"@fortawesome/fontawesome-free": "^5.15.4",
"@geoengine/openapi-client": "0.0.10",
"codemirror": "~5.65.16",
"d3": "~7.9.0",
Expand All @@ -76,6 +77,7 @@
"vis-data": "7.1.9",
"vis-timeline": "7.7.3",
"vis-util": "5.0.7",
"workflow-editor": "git+https://github.com/1lutz/workflow-editor.git",
"xss": "1.0.15",
"zone.js": "~0.14.4"
},
Expand Down
5 changes: 4 additions & 1 deletion projects/core/src/lib/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ import {MapResolutionExtentOverlayComponent} from './map/map-info/map-resolution
import {DownloadLayerComponent} from './download-layer/download-layer.component';
import {BandwiseExpressionOperatorComponent} from './operators/dialogs/bandwise-expression-operator/bandwise-expression-operator.component';
import {BandNeighborhoodAggregateComponent} from './operators/dialogs/band-neighborhood-aggregate/band-neighborhood-aggregate.component';
import {WorkflowEditorComponent} from "./workflow-editor/workflow-editor.component";
import {CreateWorkflowComponent} from "./datasets/create-workflow/create-workflow.component";

export const MATERIAL_MODULES = [
MatAutocompleteModule,
Expand Down Expand Up @@ -195,6 +197,7 @@ const CORE_PIPES = [
const CORE_COMPONENTS = [
AddDataComponent,
AddWorkflowComponent,
CreateWorkflowComponent,
AutocompleteSelectDirective,
BackendStatusPageComponent,
BoxPlotOperatorComponent,
Expand Down Expand Up @@ -232,7 +235,6 @@ const CORE_COMPONENTS = [
LayerListMenuComponent,
LayerSelectionComponent,
LineageGraphComponent,
LineageGraphComponent,
LineSimplificationComponent,
LoadProjectComponent,
LoginComponent,
Expand Down Expand Up @@ -301,6 +303,7 @@ const CORE_COMPONENTS = [

WorkspaceSettingsComponent,
ZoomHandlesComponent,
WorkflowEditorComponent
];

@NgModule({
Expand Down
13 changes: 13 additions & 0 deletions projects/core/src/lib/datasets/add-data/add-data.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {LayoutService, SidenavConfig} from '../../layout.service';
import {AddWorkflowComponent} from '../add-workflow/add-workflow.component';
import {DrawFeaturesComponent} from '../draw-features/draw-features.component';
import {UploadComponent} from '../upload/upload.component';
import {CreateWorkflowComponent} from "../create-workflow/create-workflow.component";

export interface AddDataButton {
name: string;
Expand Down Expand Up @@ -98,4 +99,16 @@ export class AddDataComponent {
sidenavConfig: {component: AddWorkflowComponent, keepParent: true},
};
}

/**
* Create workflow dialog
*/
static createWorkflowEditorButton(): AddDataButton {
return {
name: 'Create Workflow using Editor',
description: 'Add a new workflow by graph editor',
icon: 'build',
sidenavConfig: {component: CreateWorkflowComponent, keepParent: true},
};
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Component, ChangeDetectionStrategy} from '@angular/core';
import {UntypedFormGroup, UntypedFormControl, Validators} from '@angular/forms';
import {GeoEngineErrorDict, RasterResultDescriptorDict, UUID, VectorResultDescriptorDict} from '../../backend/backend.model';
import {UUID} from '../../backend/backend.model';
import {NotificationService} from '../../notification.service';
import {ProjectService} from '../../project/project.service';
import {RandomColorService} from '../../util/services/random-color.service';
import {RasterLayer, RasterSymbology, VectorLayer, createVectorSymbology, isValidUuid} from '@geoengine/common';
import {isValidUuid} from '@geoengine/common';
import {DatasetService} from "../dataset.service";

@Component({
selector: 'geoengine-add-workflow',
Expand All @@ -19,6 +20,7 @@ export class AddWorkflowComponent {
protected readonly projectService: ProjectService,
protected readonly notificationService: NotificationService,
protected readonly randomColorService: RandomColorService,
protected readonly datasetService: DatasetService,
) {
this.form = new UntypedFormGroup({
layerName: new UntypedFormControl('New Layer', Validators.required),
Expand All @@ -30,71 +32,22 @@ export class AddWorkflowComponent {
const layerName: string = this.form.controls.layerName.value;
const workflowId: UUID = this.form.controls.workflowId.value;

this.projectService.getWorkflowMetaData(workflowId).subscribe(
(resultDescriptorDict) => {
const keys = Object.keys(resultDescriptorDict);
this.datasetService.createLayerFromWorkflow(layerName, workflowId).subscribe(
layer => {
this.projectService.addLayer(layer);
},
error => {
let errorMessage = `No workflow found for id: ${workflowId}`;

if (keys.includes('columns')) {
this.addVectorLayer(layerName, workflowId, resultDescriptorDict as VectorResultDescriptorDict);
} else if (keys.includes('bands')) {
this.addRasterLayer(layerName, workflowId, resultDescriptorDict as RasterResultDescriptorDict);
if ("error" in error) {
if (error.error !== 'NoWorkflowForGivenId') {
errorMessage = `Unknown error -> ${error.error}: ${error.message}`;
}
} else {
// TODO: implement plots, etc.
this.notificationService.error('Adding this workflow type is unimplemented, yet');
errorMessage = error.message;
}
},
(requestError) => this.handleError(requestError.error, workflowId),
this.notificationService.error(errorMessage);
}
);
}

private addVectorLayer(layerName: string, workflowId: UUID, resultDescriptor: VectorResultDescriptorDict): void {
const layer = new VectorLayer({
name: layerName,
workflowId,
isVisible: true,
isLegendVisible: false,
symbology: createVectorSymbology(resultDescriptor.dataType, this.randomColorService.getRandomColorRgba()),
});

this.projectService.addLayer(layer);
}

private addRasterLayer(layerName: string, workflowId: UUID, _resultDescriptor: RasterResultDescriptorDict): void {
const layer = new RasterLayer({
name: layerName,
workflowId,
isVisible: true,
isLegendVisible: false,
symbology: RasterSymbology.fromRasterSymbologyDict({
type: 'raster',
opacity: 1.0,
rasterColorizer: {
type: 'singleBand',
band: 0,
bandColorizer: {
type: 'linearGradient',
breakpoints: [
{value: 1, color: [0, 0, 0, 255]},
{value: 255, color: [255, 255, 255, 255]},
],
overColor: [255, 255, 255, 127],
underColor: [0, 0, 0, 127],
noDataColor: [0, 0, 0, 0],
},
},
}),
});

this.projectService.addLayer(layer);
}

private handleError(error: GeoEngineErrorDict, workflowId: UUID): void {
let errorMessage = `No workflow found for id: ${workflowId}`;

if (error.error !== 'NoWorkflowForGivenId') {
errorMessage = `Unknown error -> ${error.error}: ${error.message}`;
}

this.notificationService.error(errorMessage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<geoengine-sidenav-header>Create Workflow via Editor</geoengine-sidenav-header>

<geoengine-dialog-help>
<p>
Here you can add a new layer by creating a new workflow using an interactive graph-based editor.
</p>
</geoengine-dialog-help>

<form [formGroup]="form">
<mat-form-field appearance="fill">
<mat-label>layer Name</mat-label>
<input matInput type="text" formControlName="layerName" />
<mat-hint class="error" *ngIf="form.controls.layerName.errors">Must not be empty</mat-hint>
</mat-form-field>

<div class="actions">
<button type="button" mat-raised-button color="primary" [disabled]="(form.statusChanges | async) !== 'VALID'" (click)="openEditor()">
Open Editor
</button>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
:host {
display: block;
padding: 1rem;
}

mat-form-field,
button {
width: 100% !important;
}

.error {
color: var(--geoengine-warn-color, red);
}

button {
margin-top: 1rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {UntypedFormControl, UntypedFormGroup, Validators} from "@angular/forms";
import {MatDialog} from "@angular/material/dialog";
import {WorkflowEditorComponent} from "../../workflow-editor/workflow-editor.component";
import {LayoutService} from "../../layout.service";

@Component({
selector: 'geoengine-create-workflow',
templateUrl: './create-workflow.component.html',
styleUrl: './create-workflow.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CreateWorkflowComponent {
readonly form: UntypedFormGroup;

constructor(
protected readonly dialog: MatDialog,
protected readonly layoutService: LayoutService
) {
this.form = new UntypedFormGroup({
layerName: new UntypedFormControl('New Layer', Validators.required)
});
}

openEditor(): void {
this.layoutService.setSidenavContentComponent(undefined);
const layerName: string = this.form.controls.layerName.value;
this.dialog.open(WorkflowEditorComponent, {data: {layerOrNewName: layerName}});
}
}
Loading