<commit_before>describe('Playlist Editor (Populated)', function() {

    beforeEach(function() {
        cy.login();

        // Create random name
        let uuid = Cypress._.random(0, 1e9);

        // Create a new layout and go to the layout's designer page
        cy.createNonDynamicPlaylist(uuid).as('testPlaylistId').then((res) => {

            // Populate playlist with some widgets and media
            cy.addWidgetToPlaylist(res, 'embedded', {
                name: 'Embedded Widget'
            });

            cy.addRandomMediaToPlaylist(res);

            cy.addWidgetToPlaylist(res, 'clock', {
                name: 'Clock Widget'
            });

            cy.openPlaylistEditorAndLoadPrefs(res);
        });
    });

/* Disabled for testing speed reasons
    after(function() {
        // Remove the created layout
        cy.deletePlaylist(this.testPlaylistId);
    });
*/

    it('changes and saves widget properties', () => {
        // Create and alias for reload widget
        cy.server();
        cy.route('/playlist/widget/form/edit/*').as('reloadWidget');

        // Select the first widget on timeline ( image )
        cy.get('#timeline-container [data-type="widget"]:first-child').click();

        // Wait for the widget to load
        cy.wait('@reloadWidget');

        // Type the new name in the input
        cy.get('#properties-panel-container input[name="name"]').clear().type('newName');

        // Set a duration
        cy.get('#properties-panel-container #useDuration').check();
        cy.get('#properties-panel-container input[name="duration"]').clear().type(12);

        // Save form
        cy.get('#properties-panel-container button[data-action="save"]').click();

        // Should show a notification for the name change
        cy.get('.toast-success');

        // Wait for the widget to reload
        cy.wait('@reloadWidget');

        // Check if the values are the same entered after reload
        cy.get('#properties-panel-container input[name="name"]').should('have.attr', 'value').and('equal', 'newName');
        cy.get('#properties-panel-container input[name="duration"]').should('have.attr', 'value').and('equal', '12');

    });

    it('should revert a saved form to a previous state', () => {

        let oldName;

        // Create and alias for reload widget
        cy.server();
        cy.route('/playlist/widget/form/edit/*').as('reloadWidget');
        cy.route('PUT', '/playlist/widget/*').as('saveWidget');

        // Select the first widget on timeline ( image )
        cy.get('#timeline-container [data-type="widget"]:first-child').click();

        // Wait for the widget to load
        cy.wait('@reloadWidget');

        // Get the input field
        cy.get('#properties-panel-container input[name="name"]').then(($input) => {

            // Save old name
            oldName = $input.val();

            //Type the new name in the input
            cy.get('#properties-panel-container input[name="name"]').clear().type('newName');

            // Save form
            cy.get('#properties-panel-container button[data-action="save"]').click();

            // Should show a notification for the name change
            cy.get('.toast-success');

            // Wait for the widget to save
            cy.wait('@reloadWidget');

            // Click the revert button
            cy.get('#playlist-editor-toolbar #undoContainer').click();

            // Wait for the widget to save
            cy.wait('@saveWidget');

            // Test if the revert made the name go back to the old name
            cy.get('#properties-panel-container input[name="name"]').should('have.attr', 'value').and('equal', oldName);
        });
    });

    it('should delete a widget using the toolbar bin', () => {
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Select a widget from the navigator
        cy.get('#playlist-timeline [data-type="widget"]:first-child').click().then(($el) => {

            const widgetId = $el.attr('id');

            // Click trash container
            cy.get('#playlist-editor-toolbar a#trashContainer').click();

            // Confirm delete on modal
            cy.get('[data-test="deleteObjectModal"] button[data-bb-handler="confirm"]').click();

            // Check toast message
            cy.get('.toast-success').contains('Deleted');

            // Wait for the layout to reload
            cy.wait('@reloadPlaylist');

            // Check that widget is not on timeline
            cy.get('#playlist-timeline [data-type="widget"]#' + widgetId).should('not.exist');
        });
    });

    it('should add an audio clip to a widget by drag and drop, and adds a link to open the form in the timeline', () => {

        cy.populateLibraryWithMedia();

        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the audio form
        cy.dragToElement(
            '#playlist-editor-toolbar #content-1 .toolbar-pane-content [data-sub-type="audio"] .drag-area',
            '#timeline-container [data-type="widget"]:first-child'
        ).then(() => {

            // Select the 1st option
            cy.get('[data-test="widgetPropertiesForm"] #mediaId > option').eq(1).then(($el) => {
                cy.get('[data-test="widgetPropertiesForm"] #mediaId').select($el.val());
            });

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the audio icon
            cy.wait('@reloadPlaylist');
            cy.get('#timeline-container [data-type="widget"]:first-child')
                .find('i[data-property="Audio"]').click();

            cy.get('[data-test="widgetPropertiesForm"]').contains('Audio for');
        });
    });

    it('attaches expiry dates to a widget by drag and drop, and adds a link to open the form in the timeline', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the expiry form
        cy.dragToElement(
            '#playlist-editor-toolbar #content-1 .toolbar-pane-content [data-sub-type="expiry"] .drag-area',
            '#timeline-container [data-type="widget"]:first-child'
        ).then(() => {

            // Add dates
            cy.get('[data-test="widgetPropertiesForm"] #fromDt_Link1').type('2018-01-01');
            cy.get('[data-test="widgetPropertiesForm"] #fromDt_Link2').type('00:00');

            cy.get('[data-test="widgetPropertiesForm"] #toDt_Link1').type('2018-01-01');
            cy.get('[data-test="widgetPropertiesForm"] #toDt_Link2').type('23:45');

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the expiry dates icon
            cy.wait('@reloadPlaylist');
            cy.get('#timeline-container [data-type="widget"]:first-child')
                .find('i[data-property="Expiry"]').click();

            cy.get('[data-test="widgetPropertiesForm"]').contains('Expiry for');
        });
    });

    // NOTE: Test skipped for now until transitions are enabled by default
    it.skip('adds a transition to a widget by drag and drop, and adds a link to open the form in the timeline', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the transition form
        cy.dragToElement(
            '#playlist-editor-toolbar .toolbar-pane-content [data-sub-type="transitionIn"] .drag-area',
            '#timeline-container [data-type="widget"]:nth-child(2)'
        ).then(() => {

            // Select the 1st option
            cy.get('[data-test="widgetPropertiesForm"] #transitionType > option').eq(1).then(($el) => {
                cy.get('[data-test="widgetPropertiesForm"] #transitionType').select($el.val());
            });

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the transition icon
            cy.wait('@reloadPlaylist').then(() => {
                cy.get('#timeline-container [data-type="widget"]:nth-child(2)')
                    .find('i[data-property="Transition"]').click();

                cy.get('[data-test="widgetPropertiesForm"]').contains('Edit in Transition for');
            });
        });
    });

    it('check if the form to attach a transition to a widget by click to add appears', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar .btn-menu-tab').contains('Widgets').should('be.visible').click();
        cy.get('#playlist-editor-toolbar .btn-menu-tab').contains('Tools').should('be.visible').click();

        // Activate the Add button
        cy.get('#playlist-editor-toolbar #content-0 .toolbar-pane-content [data-sub-type="transitionIn"] .add-area').invoke('show').click();

            // Click on the widget to add
        cy.get('#timeline-container [data-type="widget"]:nth-child(2)').click();

        // Check if the right form appears
        cy.get('[data-test="widgetPropertiesForm"]').contains('Edit in Transition for');

    });
});<commit_msg>Prepare 2.3.1 release. Temporarily disable failing cypress test.<commit_after>describe.skip('Playlist Editor (Populated)', function() { //FIXME: Tests skipped for now, need update to the new Layout Designer revamp

    beforeEach(function() {
        cy.login();

        // Create random name
        let uuid = Cypress._.random(0, 1e9);

        // Create a new layout and go to the layout's designer page
        cy.createNonDynamicPlaylist(uuid).as('testPlaylistId').then((res) => {

            // Populate playlist with some widgets and media
            cy.addWidgetToPlaylist(res, 'embedded', {
                name: 'Embedded Widget'
            });

            cy.addRandomMediaToPlaylist(res);

            cy.addWidgetToPlaylist(res, 'clock', {
                name: 'Clock Widget'
            });

            cy.openPlaylistEditorAndLoadPrefs(res);
        });
    });

/* Disabled for testing speed reasons
    after(function() {
        // Remove the created layout
        cy.deletePlaylist(this.testPlaylistId);
    });
*/

    it('changes and saves widget properties', () => {
        // Create and alias for reload widget
        cy.server();
        cy.route('/playlist/widget/form/edit/*').as('reloadWidget');

        // Select the first widget on timeline ( image )
        cy.get('#timeline-container [data-type="widget"]:first-child').click();

        // Wait for the widget to load
        cy.wait('@reloadWidget');

        // Type the new name in the input
        cy.get('#properties-panel-container input[name="name"]').clear().type('newName');

        // Set a duration
        cy.get('#properties-panel-container #useDuration').check();
        cy.get('#properties-panel-container input[name="duration"]').clear().type(12);

        // Save form
        cy.get('#properties-panel-container button[data-action="save"]').click();

        // Should show a notification for the name change
        cy.get('.toast-success');

        // Wait for the widget to reload
        cy.wait('@reloadWidget');

        // Check if the values are the same entered after reload
        cy.get('#properties-panel-container input[name="name"]').should('have.attr', 'value').and('equal', 'newName');
        cy.get('#properties-panel-container input[name="duration"]').should('have.attr', 'value').and('equal', '12');

    });

    it('should revert a saved form to a previous state', () => {

        let oldName;

        // Create and alias for reload widget
        cy.server();
        cy.route('/playlist/widget/form/edit/*').as('reloadWidget');
        cy.route('PUT', '/playlist/widget/*').as('saveWidget');

        // Select the first widget on timeline ( image )
        cy.get('#timeline-container [data-type="widget"]:first-child').click();

        // Wait for the widget to load
        cy.wait('@reloadWidget');

        // Get the input field
        cy.get('#properties-panel-container input[name="name"]').then(($input) => {

            // Save old name
            oldName = $input.val();

            //Type the new name in the input
            cy.get('#properties-panel-container input[name="name"]').clear().type('newName');

            // Save form
            cy.get('#properties-panel-container button[data-action="save"]').click();

            // Should show a notification for the name change
            cy.get('.toast-success');

            // Wait for the widget to save
            cy.wait('@reloadWidget');

            // Click the revert button
            cy.get('#playlist-editor-toolbar #undoContainer').click();

            // Wait for the widget to save
            cy.wait('@saveWidget');

            // Test if the revert made the name go back to the old name
            cy.get('#properties-panel-container input[name="name"]').should('have.attr', 'value').and('equal', oldName);
        });
    });

    it('should delete a widget using the toolbar bin', () => {
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Select a widget from the navigator
        cy.get('#playlist-timeline [data-type="widget"]:first-child').click().then(($el) => {

            const widgetId = $el.attr('id');

            // Click trash container
            cy.get('#playlist-editor-toolbar a#trashContainer').click();

            // Confirm delete on modal
            cy.get('[data-test="deleteObjectModal"] button[data-bb-handler="confirm"]').click();

            // Check toast message
            cy.get('.toast-success').contains('Deleted');

            // Wait for the layout to reload
            cy.wait('@reloadPlaylist');

            // Check that widget is not on timeline
            cy.get('#playlist-timeline [data-type="widget"]#' + widgetId).should('not.exist');
        });
    });

    it('should add an audio clip to a widget by drag and drop, and adds a link to open the form in the timeline', () => {

        cy.populateLibraryWithMedia();

        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the audio form
        cy.dragToElement(
            '#playlist-editor-toolbar #content-1 .toolbar-pane-content [data-sub-type="audio"] .drag-area',
            '#timeline-container [data-type="widget"]:first-child'
        ).then(() => {

            // Select the 1st option
            cy.get('[data-test="widgetPropertiesForm"] #mediaId > option').eq(1).then(($el) => {
                cy.get('[data-test="widgetPropertiesForm"] #mediaId').select($el.val());
            });

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the audio icon
            cy.wait('@reloadPlaylist');
            cy.get('#timeline-container [data-type="widget"]:first-child')
                .find('i[data-property="Audio"]').click();

            cy.get('[data-test="widgetPropertiesForm"]').contains('Audio for');
        });
    });

    it('attaches expiry dates to a widget by drag and drop, and adds a link to open the form in the timeline', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the expiry form
        cy.dragToElement(
            '#playlist-editor-toolbar #content-1 .toolbar-pane-content [data-sub-type="expiry"] .drag-area',
            '#timeline-container [data-type="widget"]:first-child'
        ).then(() => {

            // Add dates
            cy.get('[data-test="widgetPropertiesForm"] #fromDt_Link1').type('2018-01-01');
            cy.get('[data-test="widgetPropertiesForm"] #fromDt_Link2').type('00:00');

            cy.get('[data-test="widgetPropertiesForm"] #toDt_Link1').type('2018-01-01');
            cy.get('[data-test="widgetPropertiesForm"] #toDt_Link2').type('23:45');

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the expiry dates icon
            cy.wait('@reloadPlaylist');
            cy.get('#timeline-container [data-type="widget"]:first-child')
                .find('i[data-property="Expiry"]').click();

            cy.get('[data-test="widgetPropertiesForm"]').contains('Expiry for');
        });
    });

    // NOTE: Test skipped for now until transitions are enabled by default
    it.skip('adds a transition to a widget by drag and drop, and adds a link to open the form in the timeline', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar #btn-menu-2').should('be.visible').click();
        cy.get('#playlist-editor-toolbar #btn-menu-1').should('be.visible').click();

        // Open the transition form
        cy.dragToElement(
            '#playlist-editor-toolbar .toolbar-pane-content [data-sub-type="transitionIn"] .drag-area',
            '#timeline-container [data-type="widget"]:nth-child(2)'
        ).then(() => {

            // Select the 1st option
            cy.get('[data-test="widgetPropertiesForm"] #transitionType > option').eq(1).then(($el) => {
                cy.get('[data-test="widgetPropertiesForm"] #transitionType').select($el.val());
            });

            // Save and close the form
            cy.get('[data-test="widgetPropertiesForm"] [data-bb-handler="done"]').click();

            // Check if the widget has the transition icon
            cy.wait('@reloadPlaylist').then(() => {
                cy.get('#timeline-container [data-type="widget"]:nth-child(2)')
                    .find('i[data-property="Transition"]').click();

                cy.get('[data-test="widgetPropertiesForm"]').contains('Edit in Transition for');
            });
        });
    });

    it('check if the form to attach a transition to a widget by click to add appears', () => {
        // Create and alias for reload playlist
        cy.server();
        cy.route('/playlist?playlistId=*').as('reloadPlaylist');

        // Open toolbar Tools tab
        cy.get('#playlist-editor-toolbar .btn-menu-tab').contains('Widgets').should('be.visible').click();
        cy.get('#playlist-editor-toolbar .btn-menu-tab').contains('Tools').should('be.visible').click();

        // Activate the Add button
        cy.get('#playlist-editor-toolbar #content-0 .toolbar-pane-content [data-sub-type="transitionIn"] .add-area').invoke('show').click();

            // Click on the widget to add
        cy.get('#timeline-container [data-type="widget"]:nth-child(2)').click();

        // Check if the right form appears
        cy.get('[data-test="widgetPropertiesForm"]').contains('Edit in Transition for');

    });
});<|endoftext|>


<commit_before>//= require ../store
//= require ../dispatcher
//= require ../client

(function () {
"use strict";

var App = Dashboard.Stores.App = Dashboard.Store.createClass({
	displayName: "Stores.App",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = this.id;

		this.__formationLock = Promise.resolve();
		this.__releaseLock = Promise.resolve();
	},

	getInitialState: function () {
		return {
			app: null,
			release: null,
			formation: null,
			serviceUnavailable: false
		};
	},

	didBecomeActive: function () {
		this.__fetchApp();
		this.__fetchAppRelease().then(this.__fetchAppFormation.bind(this));
	},

	handleEvent: function (event) {
		switch (event.name) {
			case "APP_ENV:CREATE_RELEASE":
				this.__createRelease(event.release).then(function () {
					return this.__fetchAppRelease().then(this.__fetchAppFormation.bind(this));
				}.bind(this));
			break;

			case "APP_PROCESSES:CREATE_FORMATION":
				this.__createAppFormation(event.formation);
			break;

			case "APP_DELETE:DELETE_APP":
				this.__deleteApp();
			break;

			case "APP_DEPLOY_COMMIT:DEPLOY_COMMIT":
				this.__deployCommit(event.ownerLogin, event.repoName, event.branchName, event.sha);
			break;
		}
	},

	__getApp: function () {
		if (this.state.app) {
			return Promise.resolve(this.state.app);
		} else {
			return this.__fetchApp();
		}
	},

	__getAppRelease: function () {
		return this.__releaseLock.then(function () {
			if (this.state.release) {
				return Promise.resolve(this.state.release);
			} else {
				return this.__fetchAppRelease();
			}
		}.bind(this));
	},

	__fetchApp: function () {
		return App.getClient.call(this).getApp(this.props.appId).then(function (args) {
			var res = args[0];
			this.setState({
				app: res
			});
		}.bind(this)).catch(function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			} else {
				var xhr = args[1];
				if (xhr.status === 503) {
					this.setState({
						serviceUnavailable: true
					});
				} else {
					return Promise.reject(args);
				}
			}
		}.bind(this));
	},

	__fetchAppRelease: function () {
		var releaseLockResolve;
		this.__releaseLock = new Promise(function (resolve) {
			releaseLockResolve = function (isError, args) {
				resolve();
				if (isError) {
					return Promise.reject(args);
				} else {
					return Promise.resolve(args);
				}
			}.bind(this);
		}.bind(this));

		return App.getClient.call(this).getAppRelease(this.props.appId).then(function (args) {
			var res = args[0];
			this.setState({
				release: res
			});
			return res;
		}.bind(this)).then(releaseLockResolve.bind(null, false), releaseLockResolve.bind(null, true));
	},

	__fetchAppFormation: function () {
		var formationLockResolve;
		this.__formationLock = new Promise(function (resolve) {
			formationLockResolve = function (isError, args) {
				resolve();
				if (isError) {
					return Promise.reject(args);
				} else {
					return Promise.resolve(args);
				}
			}.bind(this);
		}.bind(this));

		function buildProcesses (release) {
			var processes = {};
			Object.keys(release.processes).sort().forEach(function (k) {
				processes[k] = 0;
			});
			return processes;
		}

		return App.getClient.call(this).getAppFormation(this.props.appId, this.state.release.id).then(function (args) {
			var res = args[0];
			if ( !res.processes ) {
				res.processes = buildProcesses(this.state.release);
			}
			this.setState({
				formation: res
			});
			return res;
		}.bind(this), function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			}
			var xhr = args[1];
			var release = this.state.release;
			var formation = {
				app: this.props.appId,
				release: release.id,
				processes: {}
			};
			if (xhr.status === 404) {
				formation.processes = buildProcesses(release);
				this.setState({
					formation: formation
				});
				return formation;
			} else {
				return Promise.reject(args);
			}
		}.bind(this)).then(formationLockResolve.bind(null, false), formationLockResolve.bind(null, true));
	},

	__createRelease: function (release) {
		var client = App.getClient.call(this);
		var appId = this.props.appId;
		return this.__releaseLock.then(function () {
			return client.createRelease(release).then(function (args) {
				var res = args[0];
				var releaseId = res.id;
				return client.createAppRelease(appId, {id: releaseId});
			}.bind(this)).then(function () {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:RELEASE_CREATED",
					appId: appId
				});
			}.bind(this));
		}.bind(this));
	},

	__createAppFormation: function (formation) {
		return this.__formationLock.then(function () {
			return App.getClient.call(this).createAppFormation(formation.app, formation).then(function (args) {
				var res = args[0];
				this.setState({
					formation: res
				});
			}.bind(this));
		}.bind(this));
	},

	__deleteApp: function () {
		var __appId = this.id.appId;
		return App.getClient.call(this).deleteApp(this.props.appId).then(function (args) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DELETED",
				appId: __appId
			});
			return args;
		});
	},

	__deployCommit: function (ownerLogin, repoName, branchName, sha) {
		var client = App.getClient.call(this);
		var appId = this.props.appId;
		var app, meta, release, artifactId;

		function createRelease () {
			return client.createRelease(Marbles.Utils.extend({}, release, {
				id: null,
				artifact: artifactId
			})).then(function (args) {
				var res = args[0];
				return createAppRelease(res.id);
			});
		}

		function createAppRelease (releaseId) {
			return client.createAppRelease(appId, {
				id: releaseId
			}).then(function () {
				return getTaffyRelease();
			});
		}

		function getTaffyRelease () {
			return client.getTaffyRelease().then(function (args) {
				var res = args[0];
				return createTaffyJob(res.id);
			});
		}

		function createTaffyJob (taffyReleaseId) {
			return client.createTaffyJob({
				release: taffyReleaseId,
				cmd: [app.name, meta.clone_url, meta.ref, meta.sha]
			}).then(function (args) {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:JOB_CREATED",
					appId: appId,
					job: args[0]
				});
				return args;
			});
		}

		return Promise.all([this.__getApp(), this.__getAppRelease(), this.__formationLock]).then(function (__args) {
			app = __args[0];
			release = __args[1];
			meta = Marbles.Utils.extend({}, app.meta, {
				ref: branchName,
				sha: sha
			});

			return client.createArtifact({
				type: "docker",
				uri: "example://uri"
			}).then(function (args) {
				var res = args[0];
				artifactId = res.id;
				return createRelease();
			}).then(function () {
				var data = {
					name: app.name,
					meta: meta
				};
				return client.updateApp(appId, data);
			});
		}).catch(function (args) {
			if (args instanceof Error) {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:DEPLOY_FAILED",
					appId: appId,
					errorMsg: "Something went wrong"
				});
				throw args;
			} else {
				var res = args[0];
				var xhr = args[1];
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:DEPLOY_FAILED",
					appId: appId,
					errorMsg: res.message || "Something went wrong ["+ xhr.status +"]"
				});
			}
		}).then(function () {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DEPLOY_SUCCESS",
				appId: appId
			});
		});
	}
});

App.getClient = function () {
	return Dashboard.client;
};

App.dispatcherIndex = App.registerWithDispatcher(Dashboard.Dispatcher);

App.findOrFetch = function (appId) {
	var instances = this.__instances;
	var instance;
	var app;
	for (var k in instances) {
		if (instances.hasOwnProperty(k)) {
			instance = instances[k];
			if (instance.id.appId === appId) {
				app = instance.state.app;
				break;
			}
		}
	}

	if (app) {
		return Promise.resolve(app);
	} else {
		return App.getClient.call(this).getApp(appId).then(function (args) {
			return args[0];
		});
	}
};

App.createFromGithubCommit = function (repo, branchName, sha, appData) {
	var meta = {
		type: "github",
		user_login: repo.ownerLogin,
		repo_name: repo.name,
		ref: branchName,
		sha: sha,
		clone_url: repo.cloneURL
	};
	var client = App.getClient.call(this);
	return this.createFromGithub(client, meta, appData);
};

App.createFromGithubPull = function (repo, pull, appData) {
	var meta = {
		type: "github",
		user_login: repo.ownerLogin,
		repo_name: repo.name,
		ref: pull.head.ref,
		sha: pull.head.sha,
		clone_url: repo.cloneURL,
		pull_number: String(pull.number),
		pull_user_login: pull.user.login,
		base_user_login: pull.base.ownerLogin,
		base_repo_name: pull.base.name,
		base_ref: pull.base.ref,
		base_sha: pull.base.sha
	};
	var client = App.getClient.call(this);
	return this.createFromGithub(client, meta, appData);
};

App.createFromGithub = function (client, meta, appData) {
	var data = {
		name: appData.name,
		meta: meta
	};

	var appId, appName, databaseEnv, artifactId;

	function createDatabase () {
		return client.createAppDatabase({ apps: [appId] }).then(function (args) {
			var res = args[0];
			databaseEnv = res.env;
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DATABASE_CREATED",
				appId: appId,
				appName: appName,
				env: Marbles.Utils.extend({}, appData.env, databaseEnv)
			});
			return createArtifact();
		});
	}

	function createArtifact () {
		return client.createArtifact({
			type: "docker",
			uri: "example://uri"
		}).then(function (args) {
			var res = args[0];
			artifactId = res.id;
			return createRelease();
		});
	}

	function createRelease () {
		return client.createRelease({
			env: Marbles.Utils.extend({}, appData.env, databaseEnv),
			artifact: artifactId
		}).then(function (args) {
			var res = args[0];
			return createAppRelease(res.id);
		});
	}

	function createAppRelease (releaseId) {
		return client.createAppRelease(appId, {
			id: releaseId
		}).then(function () {
			return getTaffyRelease();
		});
	}

	function getTaffyRelease () {
		return client.getTaffyRelease().then(function (args) {
			var res = args[0];
			return createTaffyJob(res.id);
		});
	}

	function createTaffyJob (taffyReleaseId) {
		return client.createTaffyJob({
			release: taffyReleaseId,
			cmd: [appName, meta.clone_url, meta.ref, meta.sha]
		}).then(function (args) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:JOB_CREATED",
				appId: appId,
				appName: appName,
				job: args[0]
			});
			return args;
		});
	}

	return client.createApp(data).then(function (args) {
		var res = args[0];
		appId = res.id;
		appName = res.name;
		Dashboard.Dispatcher.handleStoreEvent({
			name: "APP:CREATED",
			app: res
		});
		if (appData.dbRequested) {
			return createDatabase();
		} else {
			return getTaffyRelease();
		}
	}).catch(function (args) {
		if (args instanceof Error) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:CREATE_FAILED",
				appName: data.name,
				errorMsg: "Something went wrong"
			});
			throw args;
		} else {
			var res = args[0];
			var xhr = args[1];
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:CREATE_FAILED",
				appName: data.name,
				errorMsg: res.message || "Something went wrong ["+ xhr.status +"]"
			});
		}
	});
};

App.handleEvent = function (event) {
	switch (event.name) {
		case "GITHUB_DEPLOY:LAUNCH_FROM_COMMIT":
			App.createFromGithubCommit(event.repo, event.branchName, event.commit.sha, event.appData);
		break;

		case "GITHUB_DEPLOY:LAUNCH_FROM_PULL":
			App.createFromGithubPull(event.repo, event.pull, event.appData);
		break;
	}
};
Dashboard.Dispatcher.register(App.handleEvent);

})();
<commit_msg>dashboard/app: App store: Use id.appId in events<commit_after>//= require ../store
//= require ../dispatcher
//= require ../client

(function () {
"use strict";

var App = Dashboard.Stores.App = Dashboard.Store.createClass({
	displayName: "Stores.App",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = this.id;

		this.__formationLock = Promise.resolve();
		this.__releaseLock = Promise.resolve();
	},

	getInitialState: function () {
		return {
			app: null,
			release: null,
			formation: null,
			serviceUnavailable: false
		};
	},

	didBecomeActive: function () {
		this.__fetchApp();
		this.__fetchAppRelease().then(this.__fetchAppFormation.bind(this));
	},

	handleEvent: function (event) {
		switch (event.name) {
			case "APP_ENV:CREATE_RELEASE":
				this.__createRelease(event.release).then(function () {
					return this.__fetchAppRelease().then(this.__fetchAppFormation.bind(this));
				}.bind(this));
			break;

			case "APP_PROCESSES:CREATE_FORMATION":
				this.__createAppFormation(event.formation);
			break;

			case "APP_DELETE:DELETE_APP":
				this.__deleteApp();
			break;

			case "APP_DEPLOY_COMMIT:DEPLOY_COMMIT":
				this.__deployCommit(event.ownerLogin, event.repoName, event.branchName, event.sha);
			break;
		}
	},

	__getApp: function () {
		if (this.state.app) {
			return Promise.resolve(this.state.app);
		} else {
			return this.__fetchApp();
		}
	},

	__getAppRelease: function () {
		return this.__releaseLock.then(function () {
			if (this.state.release) {
				return Promise.resolve(this.state.release);
			} else {
				return this.__fetchAppRelease();
			}
		}.bind(this));
	},

	__fetchApp: function () {
		return App.getClient.call(this).getApp(this.props.appId).then(function (args) {
			var res = args[0];
			this.setState({
				app: res
			});
		}.bind(this)).catch(function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			} else {
				var xhr = args[1];
				if (xhr.status === 503) {
					this.setState({
						serviceUnavailable: true
					});
				} else {
					return Promise.reject(args);
				}
			}
		}.bind(this));
	},

	__fetchAppRelease: function () {
		var releaseLockResolve;
		this.__releaseLock = new Promise(function (resolve) {
			releaseLockResolve = function (isError, args) {
				resolve();
				if (isError) {
					return Promise.reject(args);
				} else {
					return Promise.resolve(args);
				}
			}.bind(this);
		}.bind(this));

		return App.getClient.call(this).getAppRelease(this.props.appId).then(function (args) {
			var res = args[0];
			this.setState({
				release: res
			});
			return res;
		}.bind(this)).then(releaseLockResolve.bind(null, false), releaseLockResolve.bind(null, true));
	},

	__fetchAppFormation: function () {
		var formationLockResolve;
		this.__formationLock = new Promise(function (resolve) {
			formationLockResolve = function (isError, args) {
				resolve();
				if (isError) {
					return Promise.reject(args);
				} else {
					return Promise.resolve(args);
				}
			}.bind(this);
		}.bind(this));

		function buildProcesses (release) {
			var processes = {};
			Object.keys(release.processes).sort().forEach(function (k) {
				processes[k] = 0;
			});
			return processes;
		}

		return App.getClient.call(this).getAppFormation(this.props.appId, this.state.release.id).then(function (args) {
			var res = args[0];
			if ( !res.processes ) {
				res.processes = buildProcesses(this.state.release);
			}
			this.setState({
				formation: res
			});
			return res;
		}.bind(this), function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			}
			var xhr = args[1];
			var release = this.state.release;
			var formation = {
				app: this.props.appId,
				release: release.id,
				processes: {}
			};
			if (xhr.status === 404) {
				formation.processes = buildProcesses(release);
				this.setState({
					formation: formation
				});
				return formation;
			} else {
				return Promise.reject(args);
			}
		}.bind(this)).then(formationLockResolve.bind(null, false), formationLockResolve.bind(null, true));
	},

	__createRelease: function (release) {
		var client = App.getClient.call(this);
		var __appId = this.id.appId;
		return this.__releaseLock.then(function () {
			return client.createRelease(release).then(function (args) {
				var res = args[0];
				var releaseId = res.id;
				return client.createAppRelease(this.props.appId, {id: releaseId});
			}.bind(this)).then(function () {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:RELEASE_CREATED",
					appId: __appId
				});
			}.bind(this));
		}.bind(this));
	},

	__createAppFormation: function (formation) {
		return this.__formationLock.then(function () {
			return App.getClient.call(this).createAppFormation(formation.app, formation).then(function (args) {
				var res = args[0];
				this.setState({
					formation: res
				});
			}.bind(this));
		}.bind(this));
	},

	__deleteApp: function () {
		var __appId = this.id.appId;
		return App.getClient.call(this).deleteApp(this.props.appId).then(function (args) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DELETED",
				appId: __appId
			});
			return args;
		});
	},

	__deployCommit: function (ownerLogin, repoName, branchName, sha) {
		var client = App.getClient.call(this);
		var appId = this.props.appId;
		var __appId = this.id.appId;
		var app, meta, release, artifactId;

		function createRelease () {
			return client.createRelease(Marbles.Utils.extend({}, release, {
				id: null,
				artifact: artifactId
			})).then(function (args) {
				var res = args[0];
				return createAppRelease(res.id);
			});
		}

		function createAppRelease (releaseId) {
			return client.createAppRelease(appId, {
				id: releaseId
			}).then(function () {
				return getTaffyRelease();
			});
		}

		function getTaffyRelease () {
			return client.getTaffyRelease().then(function (args) {
				var res = args[0];
				return createTaffyJob(res.id);
			});
		}

		function createTaffyJob (taffyReleaseId) {
			return client.createTaffyJob({
				release: taffyReleaseId,
				cmd: [app.name, meta.clone_url, meta.ref, meta.sha]
			}).then(function (args) {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:JOB_CREATED",
					appId: __appId,
					job: args[0]
				});
				return args;
			});
		}

		return Promise.all([this.__getApp(), this.__getAppRelease(), this.__formationLock]).then(function (__args) {
			app = __args[0];
			release = __args[1];
			meta = Marbles.Utils.extend({}, app.meta, {
				ref: branchName,
				sha: sha
			});

			return client.createArtifact({
				type: "docker",
				uri: "example://uri"
			}).then(function (args) {
				var res = args[0];
				artifactId = res.id;
				return createRelease();
			}).then(function () {
				var data = {
					name: app.name,
					meta: meta
				};
				return client.updateApp(appId, data);
			});
		}).catch(function (args) {
			if (args instanceof Error) {
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:DEPLOY_FAILED",
					appId: __appId,
					errorMsg: "Something went wrong"
				});
				throw args;
			} else {
				var res = args[0];
				var xhr = args[1];
				Dashboard.Dispatcher.handleStoreEvent({
					name: "APP:DEPLOY_FAILED",
					appId: __appId,
					errorMsg: res.message || "Something went wrong ["+ xhr.status +"]"
				});
			}
		}).then(function () {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DEPLOY_SUCCESS",
				appId: __appId
			});
		});
	}
});

App.getClient = function () {
	return Dashboard.client;
};

App.dispatcherIndex = App.registerWithDispatcher(Dashboard.Dispatcher);

App.findOrFetch = function (appId) {
	var instances = this.__instances;
	var instance;
	var app;
	for (var k in instances) {
		if (instances.hasOwnProperty(k)) {
			instance = instances[k];
			if (instance.id.appId === appId) {
				app = instance.state.app;
				break;
			}
		}
	}

	if (app) {
		return Promise.resolve(app);
	} else {
		return App.getClient.call(this).getApp(appId).then(function (args) {
			return args[0];
		});
	}
};

App.createFromGithubCommit = function (repo, branchName, sha, appData) {
	var meta = {
		type: "github",
		user_login: repo.ownerLogin,
		repo_name: repo.name,
		ref: branchName,
		sha: sha,
		clone_url: repo.cloneURL
	};
	var client = App.getClient.call(this);
	return this.createFromGithub(client, meta, appData);
};

App.createFromGithubPull = function (repo, pull, appData) {
	var meta = {
		type: "github",
		user_login: repo.ownerLogin,
		repo_name: repo.name,
		ref: pull.head.ref,
		sha: pull.head.sha,
		clone_url: repo.cloneURL,
		pull_number: String(pull.number),
		pull_user_login: pull.user.login,
		base_user_login: pull.base.ownerLogin,
		base_repo_name: pull.base.name,
		base_ref: pull.base.ref,
		base_sha: pull.base.sha
	};
	var client = App.getClient.call(this);
	return this.createFromGithub(client, meta, appData);
};

App.createFromGithub = function (client, meta, appData) {
	var data = {
		name: appData.name,
		meta: meta
	};

	var appId, appName, databaseEnv, artifactId;

	function createDatabase () {
		return client.createAppDatabase({ apps: [appId] }).then(function (args) {
			var res = args[0];
			databaseEnv = res.env;
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:DATABASE_CREATED",
				appId: appId,
				appName: appName,
				env: Marbles.Utils.extend({}, appData.env, databaseEnv)
			});
			return createArtifact();
		});
	}

	function createArtifact () {
		return client.createArtifact({
			type: "docker",
			uri: "example://uri"
		}).then(function (args) {
			var res = args[0];
			artifactId = res.id;
			return createRelease();
		});
	}

	function createRelease () {
		return client.createRelease({
			env: Marbles.Utils.extend({}, appData.env, databaseEnv),
			artifact: artifactId
		}).then(function (args) {
			var res = args[0];
			return createAppRelease(res.id);
		});
	}

	function createAppRelease (releaseId) {
		return client.createAppRelease(appId, {
			id: releaseId
		}).then(function () {
			return getTaffyRelease();
		});
	}

	function getTaffyRelease () {
		return client.getTaffyRelease().then(function (args) {
			var res = args[0];
			return createTaffyJob(res.id);
		});
	}

	function createTaffyJob (taffyReleaseId) {
		return client.createTaffyJob({
			release: taffyReleaseId,
			cmd: [appName, meta.clone_url, meta.ref, meta.sha]
		}).then(function (args) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:JOB_CREATED",
				appId: appId,
				appName: appName,
				job: args[0]
			});
			return args;
		});
	}

	return client.createApp(data).then(function (args) {
		var res = args[0];
		appId = res.id;
		appName = res.name;
		Dashboard.Dispatcher.handleStoreEvent({
			name: "APP:CREATED",
			app: res
		});
		if (appData.dbRequested) {
			return createDatabase();
		} else {
			return getTaffyRelease();
		}
	}).catch(function (args) {
		if (args instanceof Error) {
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:CREATE_FAILED",
				appName: data.name,
				errorMsg: "Something went wrong"
			});
			throw args;
		} else {
			var res = args[0];
			var xhr = args[1];
			Dashboard.Dispatcher.handleStoreEvent({
				name: "APP:CREATE_FAILED",
				appName: data.name,
				errorMsg: res.message || "Something went wrong ["+ xhr.status +"]"
			});
		}
	});
};

App.handleEvent = function (event) {
	switch (event.name) {
		case "GITHUB_DEPLOY:LAUNCH_FROM_COMMIT":
			App.createFromGithubCommit(event.repo, event.branchName, event.commit.sha, event.appData);
		break;

		case "GITHUB_DEPLOY:LAUNCH_FROM_PULL":
			App.createFromGithubPull(event.repo, event.pull, event.appData);
		break;
	}
};
Dashboard.Dispatcher.register(App.handleEvent);

})();
<|endoftext|>


<commit_before>// Generic submission user page (Part A)

'use strict';

var _                = require('mano').i18n.bind('View: Business Process')
  , generateSections = require('./components/generate-form-sections')
  , errorMsg         = require('./components/business-process-error-info').errorMsg
  , infoMsg          = require('./components/business-process-optional-info').infoMsg;

exports._parent = require('./business-process-base');

exports['step-submission'] = { class: { 'step-active': true } };

exports.step = function () {
	var user                       = this.user
	  , businessProcess            = this.businessProcess
	  , submissionForms            = businessProcess.submissionForms
	  , guideProgress              = businessProcess._guideProgress
	  , dataFormsProgress          = businessProcess.dataForms._progress
	  , requirementUploadsProgress = businessProcess.requirementUploads._progress;

	exports._submissionHeading.call(this);

	insert(errorMsg(this));
	insert(infoMsg(this));
	insert(exports._optionalInfo.call(this));

	disabler(
		{ id: 'submission-forms-disabler-range' },
		exports._disableCondition.call(this),
		generateSections(submissionForms.applicable, { viewContext: this })
	);

	insert(_if(eq(guideProgress, 1),
		_if(or(lt(dataFormsProgress, 1), lt(requirementUploadsProgress, 1),
			lt(submissionForms._formsProgress, 1)),
			section({ class: 'section-warning' },
				ul(
					_if(lt(dataFormsProgress, 1),
						li(a({ class: 'form-complition-link', href: '/forms/' },
							_("Some mandatory fields on tab 'Enter your details' have not been completed")))),
					_if(not(eq(requirementUploadsProgress, 1)),
						li(a({ class: 'form-complition-link', href: '/documents/' },
							_("Some documents have not been uploaded")))),
					_if(not(eq(submissionForms._formsProgress, 1)),
						li(a({ class: 'form-complition-link', onclick: 'window.scroll(0, 0)' },
							_("Some mandatory fields on tab 'Send' have not been completed"))))
				)),
			form(
				{ action: '/application-submit/', method: 'post', id: 'submit-form' },
				section(
					{ class: 'section-primary user-submission-sworn-declaration' },
					h2(_("Acceptance")),
					p(_("Before sending, you must accept that the information entered into the system, " +
						"would be saved and processed by the involved institutions")),
					label({ class: 'input-aside' }, span(input({
						dbjs: submissionForms._isAffidavitSigned,
						type: 'checkbox',
						control: { id: 'input-certified-truth' }
					})), " ", span(_("I, ${ fullName }, declare under oath that the information, " +
						"regarding registration of \"${ businessName }\", entered into the system is " +
						"correct, and I accept that it would be saved and processed by involved institutions.",
						{ fullName: user._fullName, businessName: businessProcess._businessName })))
				),
				div(p({ id: 'application-submit-button' },
					_if(user._isDemo,
						a({ class: 'user-submission-button', href: '#register' }, _("Send request")),
						button({ type: 'submit', class: 'user-submission-button' }, _("Send request"))))),
				script(
					function () {
						var checkbox = $('input-certified-truth')
						  , submitP = $('application-submit-button');

						$.onEnvUpdate('submit-form', function () {
							submitP.toggle(checkbox.checked);
						});
					}
				)
			))));
};

exports._disableCondition = function () {
	return not(eq(this.businessProcess._guideProgress, 1));
};

var getHeadingText = function (isPaymentEnabled) {
	return String(_("${ stepNumber } Send your files", { stepNumber: isPaymentEnabled ? 4 : 3 }));
};

exports._submissionHeading = function () {
	var isPaymentEnabled = this.businessProcess.costs._paymentWeight;

	return div(
		{ class: 'capital-first' },
		div(isPaymentEnabled.map(function (paymentWeight) {
			return getHeadingText(paymentWeight)[0];
		})),
		div(
			h1(isPaymentEnabled.map(function (paymentWeight) {
				return getHeadingText(paymentWeight).slice(1);
			})),
			p(_("Approve the sworn declaration and submit your application."))
		)
	);
};

// Displayed together with error info and 'global' optional info
exports._optionalInfo = Function.prototype;
<commit_msg>#1688 expose sworn declaration as customisable<commit_after>// Generic submission user page (Part A)

'use strict';

var _                = require('mano').i18n.bind('View: Business Process')
  , generateSections = require('./components/generate-form-sections')
  , errorMsg         = require('./components/business-process-error-info').errorMsg
  , infoMsg          = require('./components/business-process-optional-info').infoMsg;

exports._parent = require('./business-process-base');

exports['step-submission'] = { class: { 'step-active': true } };

exports.step = function () {
	var user                       = this.user
	  , businessProcess            = this.businessProcess
	  , submissionForms            = businessProcess.submissionForms
	  , guideProgress              = businessProcess._guideProgress
	  , dataFormsProgress          = businessProcess.dataForms._progress
	  , requirementUploadsProgress = businessProcess.requirementUploads._progress;

	exports._submissionHeading.call(this);

	insert(errorMsg(this));
	insert(infoMsg(this));
	insert(exports._optionalInfo.call(this));

	disabler(
		{ id: 'submission-forms-disabler-range' },
		exports._disableCondition.call(this),
		generateSections(submissionForms.applicable, { viewContext: this })
	);

	insert(_if(eq(guideProgress, 1),
		_if(or(lt(dataFormsProgress, 1), lt(requirementUploadsProgress, 1),
			lt(submissionForms._formsProgress, 1)),
			section({ class: 'section-warning' },
				ul(
					_if(lt(dataFormsProgress, 1),
						li(a({ class: 'form-complition-link', href: '/forms/' },
							_("Some mandatory fields on tab 'Enter your details' have not been completed")))),
					_if(not(eq(requirementUploadsProgress, 1)),
						li(a({ class: 'form-complition-link', href: '/documents/' },
							_("Some documents have not been uploaded")))),
					_if(not(eq(submissionForms._formsProgress, 1)),
						li(a({ class: 'form-complition-link', onclick: 'window.scroll(0, 0)' },
							_("Some mandatory fields on tab 'Send' have not been completed"))))
				)),
			form(
				{ action: '/application-submit/', method: 'post', id: 'submit-form' },
				section(
					{ class: 'section-primary user-submission-sworn-declaration' },
					h2(_("Acceptance")),
					p(_("Before sending, you must accept that the information entered into the system, " +
						"would be saved and processed by the involved institutions")),
					label({ class: 'input-aside' }, span(input({
						dbjs: submissionForms._isAffidavitSigned,
						type: 'checkbox',
						control: { id: 'input-certified-truth' }
					})), " ", exports._swornDeclaration.call(this))
				),
				div(p({ id: 'application-submit-button' },
					_if(user._isDemo,
						a({ class: 'user-submission-button', href: '#register' }, _("Send request")),
						button({ type: 'submit', class: 'user-submission-button' }, _("Send request"))))),
				script(
					function () {
						var checkbox = $('input-certified-truth')
						  , submitP = $('application-submit-button');

						$.onEnvUpdate('submit-form', function () {
							submitP.toggle(checkbox.checked);
						});
					}
				)
			))));
};

exports._swornDeclaration = function () {
	return span(_("I, ${ fullName }, declare under oath that the information, " +
			"regarding registration of \"${ businessName }\", entered into the system is " +
			"correct, and I accept that it would be saved and processed by involved institutions.",
		{ fullName: this.user._fullName, businessName: this.businessProcess._businessName }));
};

exports._disableCondition = function () {
	return not(eq(this.businessProcess._guideProgress, 1));
};

var getHeadingText = function (isPaymentEnabled) {
	return String(_("${ stepNumber } Send your files", { stepNumber: isPaymentEnabled ? 4 : 3 }));
};

exports._submissionHeading = function () {
	var isPaymentEnabled = this.businessProcess.costs._paymentWeight;

	return div(
		{ class: 'capital-first' },
		div(isPaymentEnabled.map(function (paymentWeight) {
			return getHeadingText(paymentWeight)[0];
		})),
		div(
			h1(isPaymentEnabled.map(function (paymentWeight) {
				return getHeadingText(paymentWeight).slice(1);
			})),
			p(_("Approve the sworn declaration and submit your application."))
		)
	);
};

// Displayed together with error info and 'global' optional info
exports._optionalInfo = Function.prototype;
<|endoftext|>


<commit_before>'use strict';

var ensureArray  = require('es5-ext/array/valid-array')
  , ensureObject = require('es5-ext/object/valid-object')
  , generateId   = require('dom-ext/html-document/generate-id');

var generateTableBody = function (rows, master) {
	return rows.map(function (row) {
		return tr(th(row.label, span({ class: 'hint' }, row.inputHint)),
			list(row.paths, function (path) {
				if (!path) return td();
				var resolved = master.resolveSKeyPath(path);
				return td(input({
					control: { id: 'matrix-display-input-' + path },
					dbjs: resolved.observable,
					required: false
				}));
			}),
			td({ id: row.totalId }));
	});
};

module.exports = function (config) {
	var horizontalTotal, horizontalTotals = [], verticalTotals = [], skipVerticalTotal,
		totalId, rows, columnLabels, lastRowLabel, tableId, master, formId;
	ensureObject(config);
	rows              = ensureArray(config.rows);
	columnLabels      = ensureArray(config.columnLabels);
	lastRowLabel      = config.lastRowLabel;
	master            = ensureObject(config.master);
	tableId           = config.tableId || generateId();
	formId            = config.formId || tableId;
	skipVerticalTotal = config.skipVerticalTotal;

	totalId = generateId('total');
	//vertical totals
	if (!skipVerticalTotal) {
		rows.forEach(function (row) {
			var verticalTotal = {
				totalId: generateId('total'),
				paths: row.paths
			};
			verticalTotals.push(verticalTotal);
			row.totalId = verticalTotal.totalId;
		});
	}
	//horizontal totals
	rows[0].paths.forEach(function (path, index) {
		horizontalTotal = {
			totalId: generateId('total'),
			paths: []
		};
		rows.forEach(function (row) {
			horizontalTotal.paths.push(row.paths[index]);
		});
		horizontalTotals.push(horizontalTotal);
	});

	return table({ id: tableId },
		thead(tr(
			th(),
			list(columnLabels, function (label) {
				return th(label);
			})
		)),
		tbody(generateTableBody(rows, master)),
		tfoot(tr(
			th(lastRowLabel),
			list(horizontalTotals, function (horizontalTotal) {
				return td({ id: horizontalTotal.totalId });
			}),
			td({ id: totalId })
		)),

		script(function (formId, horizontalTotals, verticalTotals, skipVerticalTotal, totalId) {
			var form = $(formId), totals = [], fullTotal = { total: $(totalId), subTotals: [] };
			$.forEach(horizontalTotals.concat(verticalTotals), function (total) {
				var subTotatals = [];
				$.forEach(total.paths, function (path) {
					if (!path) return;
					subTotatals.push($('matrix-display-input-' + path));
				});
				totals.push({
					total: $(total.totalId),
					subTotals: subTotatals
				});
			});
			$.forEach(verticalTotals, function (total) {
				var subTotatals = [];
				$.forEach(total.paths, function (path) {
					if (!path) return;
					subTotatals.push($('matrix-display-input-' + path));
				});
				fullTotal.subTotals = fullTotal.subTotals.concat(subTotatals);
			});
			if (!skipVerticalTotal) totals.push(fullTotal);

			$.onEnvUpdate(form, function () {
				$.forEach(totals, function (total) {
					var sum = 0;
					$.forEach(total.subTotals, function (subTotal) {
						sum += (subTotal.value ? Number(subTotal.value) : 0);
					});
					total.total.innerText = sum.toLocaleString();
				});
			});
		}, formId, horizontalTotals, verticalTotals, skipVerticalTotal, totalId));
};
<commit_msg>fixed things that came up with review. Fulltotal still gone in case verticalTotals are skipped since it is a member of verticalTotals.<commit_after>'use strict';

var ensureArray  = require('es5-ext/array/valid-array')
  , ensureObject = require('es5-ext/object/valid-object')
  , generateId   = require('dom-ext/html-document/generate-id');

var generateTableBody = function (rows, master) {
	return rows.map(function (row) {
		return tr(th(row.label, span({ class: 'hint' }, row.inputHint)),
			list(row.paths, function (path) {
				if (path == null) return td();
				var resolved = master.resolveSKeyPath(path);
				return td(input({
					control: { id: 'matrix-display-input-' + path },
					dbjs: resolved.observable,
					required: false
				}));
			}),
			td({ id: row.totalId }));
	});
};

module.exports = function (config) {
	var horizontalTotal, horizontalTotals = [], verticalTotals = [], skipVerticalTotal,
		totalId, rows, columnLabels, lastRowLabel, tableId, master, formId;
	ensureObject(config);
	rows              = ensureArray(config.rows);
	columnLabels      = ensureArray(config.columnLabels);
	lastRowLabel      = config.lastRowLabel;
	master            = ensureObject(config.master);
	tableId           = config.tableId || generateId();
	formId            = config.formId || tableId;
	skipVerticalTotal = config.skipVerticalTotal;

	totalId = generateId('total');
	//vertical totals
	if (!skipVerticalTotal) {
		rows.forEach(function (row) {
			var verticalTotal = {
				totalId: generateId('total'),
				paths: row.paths
			};
			verticalTotals.push(verticalTotal);
			row.totalId = verticalTotal.totalId;
		});
	}
	//horizontal totals
	rows[0].paths.forEach(function (path, index) {
		horizontalTotal = {
			totalId: generateId('total'),
			paths: []
		};
		rows.forEach(function (row) {
			horizontalTotal.paths.push(row.paths[index]);
		});
		horizontalTotals.push(horizontalTotal);
	});

	return table({ id: tableId },
		thead(tr(
			th(),
			list(columnLabels, function (label) {
				return th(label);
			})
		)),
		tbody(generateTableBody(rows, master)),
		tfoot(tr(
			th(lastRowLabel),
			list(horizontalTotals, function (horizontalTotal) {
				return td({ id: horizontalTotal.totalId });
			}),
			td({ id: totalId })
		)),

		script(function (formId, horizontalTotals, verticalTotals, totalId) {
			var form = $(formId), totals = [], fullTotal = { total: $(totalId), subTotals: [] };
			$.forEach(horizontalTotals.concat(verticalTotals), function (total) {
				var subTotatals = [];
				$.forEach(total.paths, function (path) {
					if (path == null) return;
					subTotatals.push($('matrix-display-input-' + path));
				});
				totals.push({
					total: $(total.totalId),
					subTotals: subTotatals
				});
			});
			$.forEach(verticalTotals, function (total) {
				var subTotatals = [];
				$.forEach(total.paths, function (path) {
					if (path == null) return;
					subTotatals.push($('matrix-display-input-' + path));
				});
				fullTotal.subTotals = fullTotal.subTotals.concat(subTotatals);
			});
			if (verticalTotals.length > 0) totals.push(fullTotal);

			$.onEnvUpdate(form, function () {
				$.forEach(totals, function (total) {
					var sum = 0;
					$.forEach(total.subTotals, function (subTotal) {
						sum += (subTotal.value ? Number(subTotal.value) : 0);
					});
					total.total.innerText = sum.toLocaleString();
				});
			});
		}, formId, horizontalTotals, verticalTotals, totalId));
};
<|endoftext|>


<commit_before>$(function () {
    var deleteRole = function () {
        var link = $(this);
        var row = link.parents("tr");
        var roleId = link.data("role-id");
        var userId = row.data("user-id");
        // note that something appears to be broken with .ajax delete with data. Hard coding
        // url parameters for now.
        $.ajax({
            url:getContextPath() + "/admin/system/user/role?roleId=" + roleId + "&userId=" + userId,
            type:'DELETE',
            success:function (data, status, xhr) {
                var span = link.parents("span");
                span.hide('slow', function () {
                    span.remove();
                })
            },
            error:function (xhr, status, error) {
                alert("An error has occurred while removing the role. Please check the log for more details.");
            }
        });
    };

    var addRoleToUser = function () {
        var link = $(this);
        var roleId = link.data("role-id");
        var userId = addRoleDialog.data("user-id");
        $.ajax({
            url:getContextPath() + "/admin/system/user/role?roleId=" + roleId + "&userId=" + userId,
            type:'POST',
            success:function (data, status, xhr) {
                link.parents("span").remove();
                addRoleDialog.modal('hide');
                var row = $("#userTable").find("[data-user-id='" + userId + "']");
                var td = row.find(".role-column");
                var roleLabel = $(document.createElement("span"));
                roleLabel.addClass("label");
                roleLabel.addClass("label-warning");
                roleLabel.text(link.text());
                var closeLink = $(document.createElement('a'));
                closeLink.attr('href', '#');
                closeLink.text('×');
                closeLink.data("role-id", roleId);
                closeLink.click(deleteRole);
                roleLabel.append(closeLink);
                td.append(roleLabel).show('slow');
            },
            error:function (xhr, status, error) {
                alert("An error has occurred while adding the role. Please check the log for more details.");
            }
        });
    };

    var showAddRoleDialog = function () {
        var link = $(this);
        var row = link.parents("tr");
        var userId = row.data("user-id");
        addRoleDialog.data("user-id", userId);
        addRoleDialog.modal('show');
    };

    var addRoleDialog = $('#addRoleDialog').modal({show:false});
    $(".descriptive").tooltip();
    $(".delete-role").click(deleteRole);
    $(".add-role").click(addRoleToUser);
    $(".add-role-action").click(showAddRoleDialog);
});<commit_msg>housekeeping<commit_after>$(function () {
    var deleteRole = function () {
        var link = $(this);
        var row = link.parents("tr");
        var roleId = link.data("role-id");
        var userId = row.data("user-id");
        // note that something appears to be broken with .ajax delete with data. Hard coding
        // url parameters for now.
        $.ajax({
            url:getContextPath() + "/admin/system/user/role?roleId=" + roleId + "&userId=" + userId,
            type:'DELETE',
            success:function (data, status, xhr) {
                var span = link.parents("span");
                span.hide('slow', function () {
                    span.remove();
                })
            },
            error:function (xhr, status, error) {
                alert("An error has occurred while removing the role. Please check the log for more details.");
            }
        });
    };

    var addRoleToUser = function () {
        var link = $(this);
        var roleId = link.data("role-id");
        var userId = addRoleDialog.data("user-id");
        var updateUserRow = function (data, status, xhr) {
            link.parents("span").remove();
            addRoleDialog.modal('hide');
            var row = $("#userTable").find("[data-user-id='" + userId + "']");
            var td = row.find(".role-column");
            var roleLabel = $(document.createElement("span"));
            roleLabel.addClass("label");
            roleLabel.addClass("label-warning");
            roleLabel.text(link.text());
            var closeLink = $(document.createElement('a'));
            closeLink.attr('href', '#');
            closeLink.text('×');
            closeLink.data("role-id", roleId);
            closeLink.click(deleteRole);
            roleLabel.append(closeLink);
            td.append(roleLabel).show('slow');
        };
        $.ajax({
            url:getContextPath() + "/admin/system/user/role",
            type:'POST',
            data: { roleId: roleId, userId:userId},
            success:updateUserRow,
            error:function (xhr, status, error) {
                alert("An error has occurred while adding the role. Please check the log for more details.");
            }
        });
    };

    var showAddRoleDialog = function () {
        var link = $(this);
        var row = link.parents("tr");
        var userId = row.data("user-id");
        addRoleDialog.data("user-id", userId);
        addRoleDialog.modal('show');
    };

    var addRoleDialog = $('#addRoleDialog').modal({show:false});
    $(".descriptive").tooltip();
    $(".delete-role").click(deleteRole);
    $(".add-role").click(addRoleToUser);
    $(".add-role-action").click(showAddRoleDialog);
});<|endoftext|>


<commit_before>const PlotCard = require('../../plotcard.js');

class NothingBurnsLikeTheCold extends PlotCard {
    setupCardAbilities() {
        this.whenRevealed({
            handler: () => {
                this.selections = [];
                this.remainingPlayers = this.game.getPlayersInFirstPlayerOrder();
                this.proceedToNextStep();
            }
        });
    }

    proceedToNextStep() {
        if(this.remainingPlayers.length > 0) {
            let currentPlayer = this.remainingPlayers.shift();
            this.promptForAttachment(currentPlayer);
        } else {
            this.doDiscard();
        }
    }

    promptForAttachment(currentPlayer) {
        if(!this.hasValidAttachments(currentPlayer)) {
            this.onSelectAttachment(currentPlayer, null);
            return;
        }

        this.game.promptForSelect(currentPlayer, {
            activePromptTitle: 'Select an attachment',
            source: this,
            cardCondition: card => card.location === 'play area' && card.controller === currentPlayer && card.getType() === 'attachment',
            onSelect: (player, card) => this.onSelectAttachment(player, card),
            onCancel: (player) => this.onSelectAttachment(player, null)
        });
    }

    hasValidAttachments(player) {
        return this.game.anyCardsInPlay(card => card.controller === player && card.getType() === 'attachment');
    }

    onSelectAttachment(currentPlayer, attachment) {
        this.promptForLocation(currentPlayer, attachment);
        return true;
    }

    promptForLocation(currentPlayer, attachment) {
        if(!this.hasValidLocations(currentPlayer)) {
            this.onSelectLocation(currentPlayer, attachment, null);
            return;
        }

        this.game.promptForSelect(currentPlayer, {
            activePromptTitle: 'Select a location',
            source: this,
            cardCondition: card => card.location === 'play area' && card.controller === currentPlayer && card.getType() === 'location',
            onSelect: (player, card) => this.onSelectLocation(player, attachment, card),
            onCancel: (player) => this.onSelectLocation(player, attachment, null)
        });
    }

    hasValidLocations(player) {
        return this.game.anyCardsInPlay(card => card.controller === player && card.getType() === 'location' && !card.isLimited());
    }

    onSelectLocation(player, attachment, location) {
        let cards = [attachment, location].filter(card => card !== null);

        if(cards.length === 0) {
            this.game.addMessage('{0} does not choose any cards for {1}', player, this);
        } else {
            this.game.addMessage('{0} chooses {1} for {2}', player, cards, this);
        }

        if(!attachment && this.hasValidAttachments(player)) {
            this.game.addAlert('danger', '{0} has attachments for {1} but did not select one', player, this);
        }

        if(!location && this.hasValidLocations(player)) {
            this.game.addAlert('danger', '{0} has locations for {1} but did not select one', player, this);
        }

        this.selections.push({ player: player, cards: cards });
        this.proceedToNextStep();
        return true;
    }

    doDiscard() {
        for(let selection of this.selections) {
            let player = selection.player;

            if(selection.cards.length !== 0) {
                this.game.addMessage('{0} discards {1} for {2}', player, selection.cards, this);
                player.discardCards(selection.cards, false);
            }
        }

        this.selections = [];
    }
}

NothingBurnsLikeTheCold.code = '09052';

module.exports = NothingBurnsLikeTheCold;
<commit_msg>Disallow limited locations for Nothing Burns Like Cold (#1565)<commit_after>const PlotCard = require('../../plotcard.js');

class NothingBurnsLikeTheCold extends PlotCard {
    setupCardAbilities() {
        this.whenRevealed({
            handler: () => {
                this.selections = [];
                this.remainingPlayers = this.game.getPlayersInFirstPlayerOrder();
                this.proceedToNextStep();
            }
        });
    }

    proceedToNextStep() {
        if(this.remainingPlayers.length > 0) {
            let currentPlayer = this.remainingPlayers.shift();
            this.promptForAttachment(currentPlayer);
        } else {
            this.doDiscard();
        }
    }

    promptForAttachment(currentPlayer) {
        if(!this.hasValidAttachments(currentPlayer)) {
            this.onSelectAttachment(currentPlayer, null);
            return;
        }

        this.game.promptForSelect(currentPlayer, {
            activePromptTitle: 'Select an attachment',
            source: this,
            cardCondition: card => card.location === 'play area' && card.controller === currentPlayer && card.getType() === 'attachment',
            onSelect: (player, card) => this.onSelectAttachment(player, card),
            onCancel: (player) => this.onSelectAttachment(player, null)
        });
    }

    hasValidAttachments(player) {
        return this.game.anyCardsInPlay(card => card.controller === player && card.getType() === 'attachment');
    }

    onSelectAttachment(currentPlayer, attachment) {
        this.promptForLocation(currentPlayer, attachment);
        return true;
    }

    promptForLocation(currentPlayer, attachment) {
        if(!this.hasValidLocations(currentPlayer)) {
            this.onSelectLocation(currentPlayer, attachment, null);
            return;
        }

        this.game.promptForSelect(currentPlayer, {
            activePromptTitle: 'Select a location',
            source: this,
            cardCondition: card => card.location === 'play area' && card.controller === currentPlayer && card.getType() === 'location' && !card.isLimited(),
            onSelect: (player, card) => this.onSelectLocation(player, attachment, card),
            onCancel: (player) => this.onSelectLocation(player, attachment, null)
        });
    }

    hasValidLocations(player) {
        return this.game.anyCardsInPlay(card => card.controller === player && card.getType() === 'location' && !card.isLimited());
    }

    onSelectLocation(player, attachment, location) {
        let cards = [attachment, location].filter(card => card !== null);

        if(cards.length === 0) {
            this.game.addMessage('{0} does not choose any cards for {1}', player, this);
        } else {
            this.game.addMessage('{0} chooses {1} for {2}', player, cards, this);
        }

        if(!attachment && this.hasValidAttachments(player)) {
            this.game.addAlert('danger', '{0} has attachments for {1} but did not select one', player, this);
        }

        if(!location && this.hasValidLocations(player)) {
            this.game.addAlert('danger', '{0} has locations for {1} but did not select one', player, this);
        }

        this.selections.push({ player: player, cards: cards });
        this.proceedToNextStep();
        return true;
    }

    doDiscard() {
        for(let selection of this.selections) {
            let player = selection.player;

            if(selection.cards.length !== 0) {
                this.game.addMessage('{0} discards {1} for {2}', player, selection.cards, this);
                player.discardCards(selection.cards, false);
            }
        }

        this.selections = [];
    }
}

NothingBurnsLikeTheCold.code = '09052';

module.exports = NothingBurnsLikeTheCold;
<|endoftext|>