Skip to content

Commit

Permalink
Unsaved changes modal (#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
parostatkiem authored and jesusreal committed Dec 18, 2018
1 parent 2cd8baf commit 778e691
Show file tree
Hide file tree
Showing 15 changed files with 425 additions and 139 deletions.
14 changes: 12 additions & 2 deletions client/luigi-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
return {
/** @lends linkManager */
/**
* Navigates to the given path in application hosted by Luigi. It contains either a full absolute path or a relative path without a leading slash that uses the active route as a base. This is the standard navigation.
* Navigates to the given path in the application hosted by Luigi. It contains either a full absolute path or a relative path without a leading slash that uses the active route as a base. This is the standard navigation.
* @param {string} path path to be navigated to
* @param {string} sessionId current Luigi **sessionId**
* @param {boolean} preserveView Preserve a view by setting it to `true`. It keeps the current view opened in the background and opens the new route in a new frame. Use the {@link #goBack goBack()} function to navigate back. You can use this feature across different levels. Preserved views are discarded as soon as the standard {@link #navigate navigate()} function is used instead of {@link #goBack goBack()}.
Expand Down Expand Up @@ -336,7 +336,7 @@

/** @lends linkManager */
/**
* Checks if the path you can navigate to exists in the main application. For example, you can use this helper method conditionally display a DOM element like a button.
* Checks if the path you can navigate to exists in the main application. For example, you can use this helper method conditionally to display a DOM element like a button.
* @param {string} path path which existence you want to check
* @returns {promise} A promise which resolves to a Boolean variable specifying whether the path exists or not.
* @example
Expand Down Expand Up @@ -431,6 +431,16 @@
*/
removeBackdrop: function removeBackdrop() {
window.parent.postMessage({ msg: 'luigi.remove-backdrop' }, '*');
},
/**
* This method informs the main application that there are unsaved changes in the current view in the iframe. For example, that can be a view with form fields which were edited but not submitted.
* @param {boolean} isDirty tells if there are any unsaved changes on the current page or component
*/
setDirtyStatus: function setDirtyStatus(isDirty) {
window.parent.postMessage(
{ msg: 'luigi.set-page-dirty', dirty: isDirty },
'*'
);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,59 @@ describe('Luigi client features', () => {
cy.get('.spinnerContainer .fd-spinner').should('not.exist');
});
});
it("Unsaved changes - shouldn't proceed when 'No' was pressed in modal", () => {
cy.get('iframe').then($iframe => {
const $iframeBody = $iframe.contents().find('body');

cy.wrap($iframeBody)
.find('[data-cy=toggle-dirty-state]')
.check();

cy.get('button')
.contains('Projects')
.click();

cy.get('[data-cy=confirmation-modal]').should('be.visible');

cy.location().should(loc => {
expect(loc.pathname).to.eq('/overview'); //the location is unchanged
});

cy.get('[data-cy=modal-no]').click();

cy.get('[data-cy=confirmation-modal]').should('not.be.visible');

cy.location().should(loc => {
expect(loc.pathname).to.eq('/overview'); //the location is still unchanged after "No" clicked
});
});
});
it("Unsaved changes - should proceed when 'Yes' was pressed in modal", () => {
cy.get('iframe').then($iframe => {
const $iframeBody = $iframe.contents().find('body');

cy.wrap($iframeBody)
.find('[data-cy=toggle-dirty-state]')
.check();

cy.get('button')
.contains('Projects')
.click();

cy.get('[data-cy=confirmation-modal]').should('be.visible');

cy.location().should(loc => {
expect(loc.pathname).to.eq('/overview'); //the location is unchanged
});

cy.get('[data-cy=modal-yes]').click();

cy.get('[data-cy=confirmation-modal]').should('not.be.visible');

cy.location().should(loc => {
expect(loc.pathname).to.eq('/projects'); //the location is changed after "Yes" clicked
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,36 +1,58 @@
<header class="fd-page__header">
<div class="fd-action-bar">
<div class="fd-action-bar__header">
<h1 class="fd-action-bar__title">
Luigi Angular Example
</h1>
<p class="fd-action-bar__description">Follow the links below to the Luigi feature demos.</p>
</div>
</div>
<div class="fd-action-bar">
<div class="fd-action-bar__header">
<h1 class="fd-action-bar__title">
Luigi Angular Example
</h1>
<p class="fd-action-bar__description">Follow the links below to the Luigi feature demos.</p>
</div>
</div>
</header>

<section class="fd-section">
<div class="fd-section__header">
<h1 class="fd-section__title">LuigiClient Features</h1>
</div>
<div class="fd-panel">
<ul class="fd-list-group">
<li class="fd-list-group__item clickable" *ngFor="let item of luigiClientLinks" (click)="luigiClient.linkManager().navigate(item.link)">
<strong>{{item.text}}</strong> &nbsp;&ndash; {{item.description}}
</li>
</ul>
</div>
<div class="fd-section__header">
<h1 class="fd-section__title">LuigiClient Features</h1>
</div>
<div class="fd-panel">
<ul class="fd-list-group">
<li class="fd-list-group__item clickable" *ngFor="let item of luigiClientLinks" (click)="luigiClient.linkManager().navigate(item.link)">
<strong>{{item.text}}</strong> &nbsp;&ndash; {{item.description}}
</li>
</ul>
</div>
</section>

<section class="fd-section">
<div class="fd-section__header">
<h1 class="fd-section__title">Luigi Core Features</h1>
</div>
<div class="fd-panel">
<ul class="fd-list-group">
<li class="fd-list-group__item clickable" *ngFor="let item of luigiCoreLinks" (click)="luigiClient.linkManager().navigate(item.link)">
<strong>{{item.text}}</strong> &nbsp;&ndash; {{item.description}}
</li>
</ul>
</div>
</section>
<div class="fd-section__header">
<h1 class="fd-section__title">Luigi Core Features</h1>
</div>
<div class="fd-panel">
<ul class="fd-list-group">
<li class="fd-list-group__item clickable" *ngFor="let item of luigiCoreLinks" (click)="luigiClient.linkManager().navigate(item.link)">
<strong>{{item.text}}</strong> &nbsp;&ndash; {{item.description}}
</li>
<li class="fd-list-group__item ">
<div class="fd-form__item fd-form__item--check">
<label class="fd-form__label" for="ImBw4551">
<span class="fd-toggle fd-toggle--xs fd-form__control">
<input type="checkbox" [(ngModel)]="isDirty" (change)="sendDirtyEvent()" id="ImBw4551" data-cy="toggle-dirty-state" >
<span class="fd-toggle__switch" role="presentation"></span>
</span>

</label>
</div>
<span *ngIf="!isDirty">
<strong>There are no unsaved changes</strong>
&nbsp;&ndash; toggle this to be asked for confirmation when you leave this page
</span>
<span *ngIf="isDirty">
<strong>There are unsaved changes</strong>
&nbsp;&ndash; a confirmation modal will appear when you navigate
<a title="Navigate to /projects/pr2 as an example" (click)="luigiClient.linkManager().navigate('/projects/pr2')">
somewhere else
</a>
</span>
</li>
</ul>
</div>
</section>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import LuigiClient from '@kyma-project/luigi-client';

@Component({
Expand Down Expand Up @@ -57,4 +57,9 @@ export class OverviewComponent {
description: 'navigation node configuration to redirect to another path'
}
];

private isDirty: boolean = false;
private sendDirtyEvent = () => {
LuigiClient.uxManager().setDirtyStatus(this.isDirty);
};
}
Loading

0 comments on commit 778e691

Please sign in to comment.