Skip to content

Commit

Permalink
Merge pull request #157 from ndsev/datasource-config
Browse files Browse the repository at this point in the history
  • Loading branch information
josephbirkner authored Sep 18, 2024
2 parents e30c621 + 4c209ec commit 00fa34e
Show file tree
Hide file tree
Showing 20 changed files with 15,953 additions and 15,375 deletions.
92 changes: 90 additions & 2 deletions erdblick_app/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ import {FloatLabelModule} from "primeng/floatlabel";
import {TabViewModule} from "primeng/tabview";
import {OnEnterClickDirective} from "./keyboard.service";
import {DropdownModule} from "primeng/dropdown";
import {
ArrayTypeComponent,
DatasourcesComponent,
MultiSchemaTypeComponent,
ObjectTypeComponent
} from "./datasources.component";
import {EditorService} from "./editor.service";
import {FormlyFieldConfig, FormlyModule} from "@ngx-formly/core";
import {ReactiveFormsModule} from '@angular/forms';
import {FormlyPrimeNGModule} from "@ngx-formly/primeng";
import {DataSourcesService} from "./datasources.service";
import {ProgressSpinnerModule} from "primeng/progressspinner";

export function initializeServices(styleService: StyleService, mapService: MapService, coordService: CoordinatesService) {
return async () => {
Expand All @@ -71,6 +83,50 @@ export function initializeServices(styleService: StyleService, mapService: MapSe
}
}

export function minItemsValidationMessage(error: any, field: FormlyFieldConfig) {
return `should NOT have fewer than ${field.props?.['minItems']} items`;
}

export function maxItemsValidationMessage(error: any, field: FormlyFieldConfig) {
return `should NOT have more than ${field.props?.['maxItems']} items`;
}

export function minLengthValidationMessage(error: any, field: FormlyFieldConfig) {
return `should NOT be shorter than ${field.props?.minLength} characters`;
}

export function maxLengthValidationMessage(error: any, field: FormlyFieldConfig) {
return `should NOT be longer than ${field.props?.maxLength} characters`;
}

export function minValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be >= ${field.props?.min}`;
}

export function maxValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be <= ${field.props?.max}`;
}

export function multipleOfValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be multiple of ${field.props?.step}`;
}

export function exclusiveMinimumValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be > ${field.props?.step}`;
}

export function exclusiveMaximumValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be < ${field.props?.step}`;
}

export function constValidationMessage(error: any, field: FormlyFieldConfig) {
return `should be equal to constant "${field.props?.['const']}"`;
}

export function typeValidationMessage({ schemaType }: any) {
return `should be "${schemaType[0]}".`;
}

@NgModule({
declarations: [
AppComponent,
Expand All @@ -85,7 +141,11 @@ export function initializeServices(styleService: StyleService, mapService: MapSe
CoordinatesPanelComponent,
FeatureSearchComponent,
AlertDialogComponent,
DatasourcesComponent,
OnEnterClickDirective,
ArrayTypeComponent,
ObjectTypeComponent,
MultiSchemaTypeComponent,
HighlightSearch,
TreeTableFilterPatchDirective,
],
Expand Down Expand Up @@ -126,10 +186,36 @@ export function initializeServices(styleService: StyleService, mapService: MapSe
TabViewModule,
InputTextareaModule,
ButtonGroupModule,
TabViewModule,
BreadcrumbModule,
TableModule,
DropdownModule
DropdownModule,
TableModule,
ReactiveFormsModule,
FormlyPrimeNGModule,
FormlyModule.forRoot({
validationMessages: [
{name: 'required', message: 'This field is required'},
{name: 'type', message: typeValidationMessage},
{name: 'minLength', message: minLengthValidationMessage},
{name: 'maxLength', message: maxLengthValidationMessage},
{name: 'min', message: minValidationMessage},
{name: 'max', message: maxValidationMessage},
{name: 'multipleOf', message: multipleOfValidationMessage},
{name: 'exclusiveMinimum', message: exclusiveMinimumValidationMessage},
{name: 'exclusiveMaximum', message: exclusiveMaximumValidationMessage},
{name: 'minItems', message: minItemsValidationMessage},
{name: 'maxItems', message: maxItemsValidationMessage},
{name: 'uniqueItems', message: 'should NOT have duplicate items'},
{name: 'const', message: constValidationMessage},
{name: 'enum', message: `must be equal to one of the allowed values`},
],
types: [
{name: 'array', component: ArrayTypeComponent},
{name: 'object', component: ObjectTypeComponent},
{name: 'multischema', component: MultiSchemaTypeComponent}
],
}),
ProgressSpinnerModule
],
providers: [
{
Expand All @@ -147,6 +233,8 @@ export function initializeServices(styleService: StyleService, mapService: MapSe
SidePanelService,
FeatureSearchService,
ClipboardService,
EditorService,
DataSourcesService,
provideHttpClient(withInterceptorsFromDi()),
]
})
Expand Down
4 changes: 2 additions & 2 deletions erdblick_app/app/coordinates.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {HttpClient} from "@angular/common/http";
export class CoordinatesService {
mouseMoveCoordinates: BehaviorSubject<Cartographic | null> = new BehaviorSubject<Cartographic | null>(null);
mouseClickCoordinates: BehaviorSubject<Cartographic | null> = new BehaviorSubject<Cartographic | null>(null);
auxiliaryCoordinatesFun: Function | null = null;
auxiliaryTileIdsFun: Function | null = null;
auxiliaryCoordinatesFun: ((x: number, y: number)=>any) | null = null;
auxiliaryTileIdsFun: ((x: number, y: number, level: number)=>any) | null = null;

constructor(private httpClient: HttpClient,
public parametersService: ParametersService) {
Expand Down
232 changes: 232 additions & 0 deletions erdblick_app/app/datasources.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import {Component, ViewChild} from "@angular/core";
import {InfoMessageService} from "./info.service";
import {ParametersService} from "./parameters.service";
import {Subscription} from "rxjs";
import {Dialog} from "primeng/dialog";
import {EditorService} from "./editor.service";
import {JSONSchema7} from "json-schema";
import {DataSourcesService} from "./datasources.service";
import {FormGroup} from '@angular/forms';
import {FormlyFormOptions, FormlyFieldConfig, FieldType, FieldArrayType} from '@ngx-formly/core';
import {FormlyJsonschema} from '@ngx-formly/core/json-schema';

@Component({
selector: 'formly-multi-schema-type',
template: `
<div class="card mb-3">
<div class="card-body">
<legend *ngIf="props.label">{{ props.label }}</legend>
<p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
</div>
</div>
`,
})
export class MultiSchemaTypeComponent extends FieldType {}

@Component({
selector: 'formly-object-type',
template: `
<div class="mb-3">
<legend *ngIf="props.label">{{ props.label }}</legend>
<p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
</div>
`,
})
export class ObjectTypeComponent extends FieldType {}

@Component({
selector: 'formly-array-type',
template: `
<div class="mb-3">
<p-fieldset class="ds-fieldset" [legend]="props.label">
<p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<div *ngFor="let field of field.fieldGroup; let i = index" class="row align-items-start">
<div style="display: flex; flex-direction: row; gap: 0.5em;">
<div *ngIf="field.props?.['removable'] !== false" class="col-2 text-right">
<p-button class="btn btn-danger" type="button" (click)="remove(i)">-</p-button>
</div>
<formly-field class="p-col" [field]="field"></formly-field>
</div>
<p-divider></p-divider>
</div>
<div class="d-flex flex-row-reverse">
<p-button class="btn btn-primary" type="button" (click)="add()">+</p-button>
</div>
</p-fieldset>
</div>
`,
})
export class ArrayTypeComponent extends FieldArrayType {}

@Component({
selector: 'datasources',
template: `
<!-- <p-dialog class="ds-config-dialog" header="DataSource Configuration" [(visible)]="dsService.configDialogVisible"-->
<!-- [modal]="false" (onShow)="dsService.getConfig()">-->
<!-- <p *ngIf="dsService.errorMessage">{{ dsService.errorMessage }}</p>-->
<!-- <div *ngIf="!dsService.loading" style="margin: 0.5em 0; display: flex; flex-direction: column; gap: 1em;">-->
<!-- <form [formGroup]="form" *ngIf="form && fields && !dsService.errorMessage" (ngSubmit)="postConfig()"-->
<!-- #formElement="ngForm">-->
<!-- <formly-form [model]="model" [fields]="fields" [options]="options" [form]="form"></formly-form>-->
<!-- </form>-->
<!-- <div style="margin: 0.5em 0; display: flex; flex-direction: row; justify-content: center; gap: 1em;">-->
<!-- <p-button (click)="showConfigEditor()" [disabled]="false"-->
<!-- label="Open in Editor" icon="pi pi-pencil"></p-button>-->
<!-- <p-button (click)="submitForm()" [disabled]="(form && !form.valid)"-->
<!-- label="Apply" icon="pi pi-check"></p-button>-->
<!-- <div style="display: flex; flex-direction: row; align-content: center; gap: 0.5em;">-->
<!-- <p-button (click)="closeDatasources()" label="Close" icon="pi pi-times"></p-button>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div *ngIf="dsService.loading">-->
<!-- <p-progressSpinner ariaLabel="loading"/>-->
<!-- </div>-->
<!-- </p-dialog>-->
<p-dialog header="DataSource Configuration Editor" [(visible)]="dsService.configDialogVisible" [modal]="false"
#editorDialog class="editor-dialog" (onShow)="loadConfigEditor()">
<p *ngIf="dsService.errorMessage">{{ dsService.errorMessage }}</p>
<div [ngClass]="{'loading': dsService.loading || dsService.errorMessage }">
<editor [loadFun]="loadEditedConfig" [saveFun]="saveEditedConfig"></editor>
</div>
<div class="spinner" *ngIf="dsService.loading">
<p-progressSpinner ariaLabel="loading"/>
</div>
<div style="margin: 0.5em 0; display: flex; flex-direction: row; align-content: center; justify-content: space-between;">
<div style="display: flex; flex-direction: row; align-content: center; gap: 0.5em;">
<p-button (click)="applyEditedDatasourceConfig()" label="Apply" icon="pi pi-check"
[disabled]="!wasModified"></p-button>
<p-button (click)="closeEditorDialog($event)" [label]='this.wasModified ? "Discard" : "Cancel"'
icon="pi pi-times"></p-button>
<div style="display: flex; flex-direction: column; align-content: center; justify-content: center; color: silver; font-size: medium;">
<div>Press <span style="color: grey">Ctrl-S/Cmd-S</span> to save changes</div>
<div>Press <span style="color: grey">Esc</span> to quit without saving</div>
</div>
</div>
</div>
</p-dialog>
`,
styles: [`
.loading {
visibility: collapse;
}
`]
})
export class DatasourcesComponent {

datasourcesEditorDialogVisible: boolean = false;
datasourceWasModified: boolean = false;
wasModified: boolean = false;
dataSourcesConfig: string = "";
form: FormGroup | undefined;
model: any = {};
options!: FormlyFormOptions;
fields!: FormlyFieldConfig[];
schema: JSONSchema7 = {};

@ViewChild('formElement') formElement!: HTMLFormElement;
@ViewChild('editorDialog') editorDialog: Dialog | undefined;

private editedConfigSourceSubscription: Subscription = new Subscription();
private savedConfigSourceSubscription: Subscription = new Subscription();

constructor(private messageService: InfoMessageService,
public parameterService: ParametersService,
private formlyJsonSchema: FormlyJsonschema,
public editorService: EditorService,
public dsService: DataSourcesService) {
this.parameterService.parameters.subscribe(parameters => {
return;
});

this.dsService.dataSourcesConfigJson.subscribe((config: any) => {
if (config && config["schema"] && config["model"]) {
this.schema = config["schema"];
this.model = config["model"];
this.dataSourcesConfig = JSON.stringify(this.model, null, 2);
this.editorService.editableData = this.dataSourcesConfig;
this.form = new FormGroup({});
this.options = {};
this.fields = [this.formlyJsonSchema.toFieldConfig(this.schema)];
this.dsService.loading = false;
this.editorService.updateEditorState.next(true);
}
});
}

loadConfigEditor() {
// this.datasourcesEditorDialogVisible = true;
// this.editorService.updateEditorState.next(true);
this.dsService.getConfig();
this.editedConfigSourceSubscription = this.editorService.editedStateData.subscribe(editedStyleSource => {
this.wasModified = editedStyleSource.replace(/\n+$/, '') !== this.dataSourcesConfig.replace(/\n+$/, '');
});
this.savedConfigSourceSubscription = this.editorService.editedSaveTriggered.subscribe(_ => {
this.applyEditedDatasourceConfig();
});
}

applyEditedDatasourceConfig() {
const configData = this.editorService.editedStateData.getValue().replace(/\n+$/, '');
if (!configData) {
this.messageService.showError(`Cannot apply an empty configuration definition!`);
return;
}
this.dsService.postConfig(configData);
this.dataSourcesConfig = configData;
this.wasModified = false;
}

closeEditorDialog(event: any) {
if (this.editorDialog !== undefined) {
if (this.wasModified) {
event.stopPropagation();
} else {
this.editorDialog.close(event);
}
}
this.editedConfigSourceSubscription.unsubscribe();
this.savedConfigSourceSubscription.unsubscribe();
}

discardConfigEdits() {
this.editorService.updateEditorState.next(false);
}

loadEditedConfig() {
return `${this.editorService.editableData}\n\n\n\n\n`;
}

saveEditedConfig() {
this.editorService.editedSaveTriggered.next(true);
}

closeDatasources() {
this.dsService.configDialogVisible = false;
}

submitForm() {
// if (this.form && this.form.valid) {
// this.formElement.submit();
// } else {
// alert("Form is invalid");
// }
}

postConfig() {
// this.dsService.postConfig(this.model);
}
}
Loading

0 comments on commit 00fa34e

Please sign in to comment.