mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Set Save button on top, enable it only when devfile changed (#7015)
* Set Save button on top, enable it only when devfile changed * Use snackbar to display parse errors * Do not alert devfile modified when user clicks Save * Update UI static files
This commit is contained in:
@@ -5,7 +5,7 @@ describe('devfile editor errors handling', () => {
|
||||
it('fails when YAML is not valid', () => {
|
||||
cy.init();
|
||||
cy.setDevfile("wrong yaml content");
|
||||
cy.getByDataCy("yaml-error").should('contain.text', 'error parsing devfile YAML');
|
||||
cy.get(".cdk-overlay-container").should('contain.text', 'error parsing devfile YAML');
|
||||
});
|
||||
|
||||
it('fails when adding a container with an already used name', () => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<span class="spacer"></span>
|
||||
<span class="topright">Work in progress</span>
|
||||
<a mat-icon-button href="https://github.com/feloy/devfile-builder" target="_blank"><mat-icon svgIcon="github"></mat-icon></a>
|
||||
<button style="top: -8px" data-cy="yaml-send" matTooltip="Save Devfile to disk" mat-flat-button color="warn" disabled="{{!(state.modified|async)}}" (click)="onSave(input.value)">Save</button>
|
||||
</mat-toolbar>
|
||||
<main>
|
||||
|
||||
@@ -13,13 +14,11 @@
|
||||
|
||||
<mat-tab data-cy="tab-yaml" label="{{tabNames[0]}}">
|
||||
<div class="tab-content">
|
||||
<div *ngIf="errorMessage" data-cy="yaml-error" class="error-message">{{errorMessage}}</div>
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Devfile YAML</mat-label>
|
||||
<textarea data-cy="yaml-input" matInput #input id="input" rows="20" [value]="devfileYaml"></textarea>
|
||||
</mat-form-field>
|
||||
<button data-cy="yaml-send" matTooltip="Save Devfile to disk" mat-flat-button color="primary" (click)="onSave(input.value)">Save</button>
|
||||
<button data-cy="yaml-save" matTooltip="Apply changes to other tabs" mat-flat-button color="normal" (click)="onApply(input.value)">Apply</button>
|
||||
<button data-cy="yaml-save" matTooltip="Apply changes to other tabs" mat-flat-button color="primary" (click)="onApply(input.value)">Apply</button>
|
||||
<button data-cy="yaml-clear" matTooltip="Clear Devfile content" mat-flat-button color="normal" (click)="clear()">Clear</button>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
@@ -33,7 +33,6 @@ export class AppComponent implements OnInit {
|
||||
];
|
||||
protected mermaidContent: string = "";
|
||||
protected devfileYaml: string = "";
|
||||
protected errorMessage: string = "";
|
||||
private snackBarRef: MatSnackBarRef<ConfirmComponent> | null = null;
|
||||
|
||||
constructor(
|
||||
@@ -42,7 +41,7 @@ export class AppComponent implements OnInit {
|
||||
private wasmGo: DevstateService,
|
||||
private odoApi: OdoapiService,
|
||||
private mermaid: MermaidService,
|
||||
private state: StateService,
|
||||
protected state: StateService,
|
||||
private sse: SseService,
|
||||
private telemetry: TelemetryService,
|
||||
private snackbar: MatSnackBar
|
||||
@@ -63,7 +62,7 @@ export class AppComponent implements OnInit {
|
||||
devfile.subscribe({
|
||||
next: (devfile) => {
|
||||
if (devfile.content != undefined) {
|
||||
this.propagateChange(devfile.content, false);
|
||||
this.propagateChange(devfile.content, false, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -88,6 +87,10 @@ export class AppComponent implements OnInit {
|
||||
});
|
||||
|
||||
this.sse.subscribeTo(['DevfileUpdated']).subscribe(event => {
|
||||
const newDevfile: DevfileContent = JSON.parse(event.data);
|
||||
if (!this.state.isUpdated(newDevfile.content)) {
|
||||
return;
|
||||
}
|
||||
if (this.snackBarRef != null) {
|
||||
this.snackBarRef.afterDismissed().subscribe(() => {});
|
||||
this.snackBarRef.dismiss();
|
||||
@@ -98,9 +101,8 @@ export class AppComponent implements OnInit {
|
||||
yesLabel: "Update"
|
||||
}});
|
||||
this.snackBarRef.onAction().subscribe(() => {
|
||||
let newDevfile: DevfileContent = JSON.parse(event.data);
|
||||
if (newDevfile.content != undefined) {
|
||||
this.propagateChange(newDevfile.content, false);
|
||||
this.propagateChange(newDevfile.content, false, true);
|
||||
}
|
||||
this.snackBarRef = null;
|
||||
});
|
||||
@@ -123,35 +125,34 @@ export class AppComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
propagateChange(content: string, saveToApi: boolean){
|
||||
propagateChange(content: string, saveToApi: boolean, fromApi: boolean){
|
||||
const result = this.wasmGo.setDevfileContent(content);
|
||||
result.subscribe({
|
||||
next: (value) => {
|
||||
this.errorMessage = '';
|
||||
this.state.changeDevfileYaml(value);
|
||||
this.state.changeDevfileYaml(value, fromApi);
|
||||
if (saveToApi) {
|
||||
this.odoApi.saveDevfile(value.content).subscribe({
|
||||
next: () => {},
|
||||
error: (error) => {
|
||||
this.errorMessage = error.error.message;
|
||||
this.snackbar.open(error.error.message, "ok");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.errorMessage = error.error.message;
|
||||
this.snackbar.open(error.error.message, "ok");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSave(content: string) {
|
||||
this.telemetry.track("[ui] save devfile to disk");
|
||||
this.propagateChange(content, true);
|
||||
this.propagateChange(content, true, true);
|
||||
}
|
||||
|
||||
onApply(content: string) {
|
||||
this.telemetry.track("[ui] change devfile from textarea");
|
||||
this.propagateChange(content, false);
|
||||
this.propagateChange(content, false, false);
|
||||
}
|
||||
|
||||
clear() {
|
||||
@@ -159,7 +160,7 @@ export class AppComponent implements OnInit {
|
||||
this.telemetry.track("[ui] clear devfile");
|
||||
this.wasmGo.clearDevfileContent().subscribe({
|
||||
next: (value) => {
|
||||
this.propagateChange(value.content, false);
|
||||
this.propagateChange(value.content, false, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,11 +8,32 @@ import { DevfileContent } from '../api-gen';
|
||||
})
|
||||
export class StateService {
|
||||
|
||||
private savedDevfile: string = "";
|
||||
|
||||
private _state = new BehaviorSubject<DevfileContent | null>(null);
|
||||
public state = this._state.asObservable();
|
||||
|
||||
changeDevfileYaml(newValue: DevfileContent) {
|
||||
private _modified = new BehaviorSubject<boolean | null>(null);
|
||||
public modified = this._modified.asObservable();
|
||||
|
||||
changeDevfileYaml(newValue: DevfileContent, fromDisk: boolean = false) {
|
||||
this._state.next(newValue);
|
||||
|
||||
if (fromDisk) {
|
||||
this.savedDevfile = newValue.content;
|
||||
}
|
||||
if (this.savedDevfile == "") {
|
||||
this.savedDevfile = newValue.content;
|
||||
}
|
||||
if (this.savedDevfile == newValue.content) {
|
||||
this._modified.next(false);
|
||||
} else {
|
||||
this._modified.next(true);
|
||||
}
|
||||
}
|
||||
|
||||
isUpdated(devfile: string): boolean {
|
||||
return devfile != this.savedDevfile;
|
||||
}
|
||||
|
||||
getDragAndDropEnabled(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user