Redirect back to account settings when exiting the Theme Editor

refs CNVS-22055

This change replaces the 'X' close button with a 'Cancel' button.
Also now, whenever you exit out of the Theme Editor, via either
'Apply' or 'Cancel' you will be redirected back to the account
settings page instead of the preview iframe location.

These changes should make things work better once CNVS-2196 is
implemented.

This change also cleans up the Theme Editor header a bit, adding
the Canvas logo, and adjusting some padding/margins.

Test plan:
1. Open Theme Editor and click 'Cancel'. You should be redirected back
account settings page and the appropriate message should display.
2. Open Theme Editor, make some changes, click 'Preview', click 'Cancel'.
You should be redirected to the account settings page, the theme changes
should be reset/removed and the appropriate message should display.
3. Open Theme Editor, make some changes, click 'Preview', click 'Apply'.
You should be redirected to the account settings page and the appropriate
message should display.

Change-Id: If5f1aa67a87a1587d8f26b9134ccf9d33a299229
Reviewed-on: https://gerrit.instructure.com/58913
Reviewed-by: Ryan Shaw <ryan@instructure.com>
Tested-by: Jenkins
Reviewed-by: Colleen Palmer <colleen@instructure.com>
Product-Review: Colleen Palmer <colleen@instructure.com>
QA-Review: Matt Fairbourn <mfairbourn@instructure.com>
This commit is contained in:
Jennifer Stern 2015-07-21 11:24:30 -05:00 committed by Matt Fairbourn
parent 1c2d97102d
commit c8f7ca0aae
4 changed files with 136 additions and 114 deletions

View File

@ -72,16 +72,17 @@ class BrandConfigsController < ApplicationController
@domain_root_account.brand_config = new_md5 && BrandConfig.find(new_md5)
@domain_root_account.save!
BrandConfig.destroy_if_unused(old_md5)
redirect_to :back, notice: t('Success! All users on this domain will now see this branding.')
redirect_to account_path(@domain_root_account), notice: t('Success! All users on this domain will now see this branding.')
end
# When you close the theme editor, it will send a DELETE to this action to
# clear out the session brand_config that you were prevewing.
def destroy
session.delete(:brand_config_md5)
BrandConfig.destroy_if_unused(session.delete(:brand_config_md5))
flash[:notice] = t('Theme editor changes have been cancelled.')
render json: {success: true}
if session.delete(:brand_config_md5).presence
session.delete(:brand_config_md5)
BrandConfig.destroy_if_unused(session.delete(:brand_config_md5))
end
redirect_to account_path(@domain_root_account), notice: t('Theme editor changes have been cancelled.')
end
protected

View File

@ -37,15 +37,20 @@ define([
className="screenreader-only"
htmlFor="sharedThemes"
>
{I18n.t('Start From a Template Theme:')}
{I18n.t('Start From a Theme Template')}
</label>
<select
id="sharedThemes"
defaultValue={this.defaultValue()}
onChange={event => this.selectBrandConfig(event.target.value)}
className="ic-Input"
>
<option value="" disabled selected> {I18n.t('-- Start From a Template --')} </option>
<option value={USE_CANVAS_DEFAULT}>{I18n.t('Canvas Default')}</option>
<option value="" disabled selected>
{I18n.t('Start from a template...')}
</option>
<option value={USE_CANVAS_DEFAULT}>
{I18n.t('Canvas Default')}
</option>
{this.props.sharedBrandConfigs.map(brandConfig =>
<option key={brandConfig.md5} value={brandConfig.md5}>
{brandConfig.name}

View File

@ -71,6 +71,10 @@ define([
})
},
onProgress(data) {
this.setState({progress: data.completion})
},
getDefault(variableName) {
var val = this.state.changedValues[variableName] && this.state.changedValues[variableName].val
if (val) return val
@ -87,34 +91,24 @@ define([
submitHtmlForm('/brand_configs/save_to_user_session', 'POST', md5)
},
redirectToWhatIframeIsShowing() {
window.top.location = this.refs.previewIframe.getDOMNode().contentWindow.location
},
exit() {
handleCancelClicked() {
if (this.props.hasUnsavedChanges || this.state.somethingChanged) {
var msg = I18n.t('You are about to lose any unsaved changes.\n\n' +
var msg = I18n.t('You are about to lose any changes that you have not yet applied to your account.\n\n' +
'Would you still like to proceed?')
if (confirm(msg)) {
$.ajax('/brand_configs', {type: 'DELETE'})
.then(this.redirectToWhatIframeIsShowing)
.then(null, () => alert(I18n.t('Something went wrong, please try again.')))
if (!confirm(msg)) {
return;
}
} else {
this.redirectToWhatIframeIsShowing()
}
submitHtmlForm('/brand_configs', 'DELETE');
},
saveToAccount() {
handleApplyClicked() {
var msg = I18n.t('This will apply these changes to your entire account. Would you like to proceed?')
if (confirm(msg)) submitHtmlForm('/brand_configs/save_to_account', 'POST')
},
onProgress(data) {
this.setState({progress: data.completion})
},
preview() {
handleFormSubmit() {
var newMd5
this.setState({showProgressModal: true})
@ -143,61 +137,61 @@ define([
render() {
return (
<div id="main">
<form
ref="ThemeEditorForm"
onSubmit={preventDefault(this.preview)}
encType="multipart/form-data"
acceptCharset="UTF-8"
action="/brand_configs"
method="POST"
className="Theme__container"
>
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value={$.cookie('_csrf_token')} />
<div className="Theme__editor">
<div className="Theme__editor-header">
<h1 className="Theme__editor-header_title">
<button
type='button'
className="Theme__editor-header_title-icon btn-link pull-left"
onClick={this.exit}
title={I18n.t('Exit Theme Editor')}
>
<i className="icon-x" />
<span className="screenreader-only">{I18n.t('Exit Theme Editor')}</span>
</button>
<form
ref="ThemeEditorForm"
onSubmit={preventDefault(this.handleFormSubmit)}
encType="multipart/form-data"
acceptCharset="UTF-8"
action="/brand_configs"
method="POST"
className="Theme__container">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value={$.cookie('_csrf_token')} />
<div className="Theme__editor">
{I18n.t('Theme Editor')}
</h1>
<div className="Theme__editor-header_actions">
<span
data-tooltip="bottom"
title={this.state.somethingChanged ?
I18n.t('you need to "Preview Your Changes" before applying to everyone') :
null
}
>
<div className="Theme__editor-header">
<div className="Theme__editor-header_title">
<i className="Theme__editor-header_title-icon icon-instructure" />
<h1 className="Theme__editor-header_title-text">
{I18n.t('Theme Editor')}
</h1>
</div>
<div className="Theme__editor-header_actions">
<span
data-tooltip="bottom"
title={this.state.somethingChanged ?
I18n.t('You need to "Preview Your Changes" before applying to everyone.') :
null
}
>
<button
type="button"
className="Theme__editor-header_button Button Button--success"
disabled={!this.props.hasUnsavedChanges || this.state.somethingChanged}
onClick={this.handleApplyClicked}
>
{I18n.t('Apply')}
</button>
</span>
<button
type="button"
className="Theme__editor-header_button Button Button--success"
disabled={!this.props.hasUnsavedChanges || this.state.somethingChanged}
onClick={this.saveToAccount}
className="Theme__editor-header_button Button"
onClick={this.handleCancelClicked}
>
{I18n.t('Apply')}
{I18n.t('Cancel')}
</button>
</span>
</div>
</div>
</div>
<SharedBrandConfigPicker
sharedBrandConfigs={this.props.sharedBrandConfigs}
activeBrandConfigMd5={this.props.brandConfig.md5}
saveToSession={this.saveToSession}
/>
<div id="Theme__editor-tabs">
<div id="te-editor">
<div className="Theme__editor-tabs_panel">
<div className="Theme__editor-tabs">
<div id="te-editor-panel" className="Theme__editor-tabs_panel">
<SharedBrandConfigPicker
sharedBrandConfigs={this.props.sharedBrandConfigs}
activeBrandConfigMd5={this.props.brandConfig.md5}
saveToSession={this.saveToSession}
/>
<ThemeEditorAccordion
variableSchema={this.props.variableSchema}
brandConfigVariables={this.props.brandConfig.variables}
@ -207,40 +201,46 @@ define([
/>
</div>
</div>
</div>
</div>
<div className="Theme__preview">
{ this.state.somethingChanged ?
<div className="Theme__preview-overlay">
<div className="Theme__preview-overlay__container">
<button type="submit" className="Button Button--primary" disabled={this.invalidForm()}>
<i className="icon-refresh" />
{I18n.t('Preview Your Changes')}
</button>
</div>
<div className="Theme__preview">
{ this.state.somethingChanged ?
<div className="Theme__preview-overlay">
<div className="Theme__preview-overlay__container">
<button
type="submit"
className="Button Button--primary"
disabled={this.invalidForm()}>
<i className="icon-refresh" />
<span className="Theme__preview-button-text">
{I18n.t('Preview Your Changes')}
</span>
</button>
</div>
</div>
: null }
<iframe ref="previewIframe" src="/?editing_brand_config=1" />
</div>
: null }
<iframe ref="previewIframe" src="/?editing_brand_config=1" />
</div>
</form>
<Modal
isOpen={this.state.showProgressModal}
className='ReactModal__Content--canvas ReactModal__Content--mini-modal'
overlayClassName='ReactModal__Overlay--Theme__editor_progress'
>
<div className="Theme__editor_progress">
<h4>{I18n.t('Generating Preview...')}</h4>
<ProgressBar
progress={this.state.progress}
title={I18n.t('%{percent} complete', {
percent: I18n.toPercentage(this.state.progress, {precision: 0})
})}
/>
</div>
</Modal>
</div>
</form>
<Modal
isOpen={this.state.showProgressModal}
className='ReactModal__Content--canvas ReactModal__Content--mini-modal'
overlayClassName='ReactModal__Overlay--Theme__editor_progress'>
<div className="Theme__editor_progress">
<h4>{I18n.t('Generating Preview...')}</h4>
<ProgressBar
progress={this.state.progress}
title={I18n.t('%{percent} complete', {
percent: I18n.toPercentage(this.state.progress, {precision: 0})
})}
/>
</div>
</Modal>
</div>
)
}
})
});
});

View File

@ -80,6 +80,9 @@ $te-border-color: darken($ic-color-neutral, 10);
align-items: center;
justify-content: center;
}
.Theme__preview-button-text {
padding-left: $ic-sp;
}
.Theme__preview iframe {
border: none;
width: 100%;
@ -90,31 +93,40 @@ $te-border-color: darken($ic-color-neutral, 10);
.Theme__editor-header {
background: $ic-color-dark;
padding: 10px 0;
padding: 10px;
display: flex;
align-items: center;
position: relative;
.Theme__editor-header_title {
padding: 0 0 0 $ic-sp;
margin: 0;
flex: 1;
display: flex;
align-items: center;
@include overwrite-default-icon-size(18px);
}
.Theme__editor-header_title-text {
color: $ic-color-light;
line-height: normal;
font-size: 18px;
font-size: 16px;
font-weight: 300;
margin: 0 0 0 $ic-sp;
flex: 1;
text-align: center;
line-height: 1.2;
}
.Theme__editor-header_title-icon {
color: $ic-color-light;
line-height: 1;
color: #D5412F;
}
.Theme__editor-header_actions {
display: flex;
justify-content: flex-end;
}
.Theme__editor-Button--trigger {
}
.Theme__editor-header_button {
margin: 0 $ic-sp;
margin-left: $ic-sp/2;
}
}
@ -125,6 +137,10 @@ $te-border-color: darken($ic-color-neutral, 10);
padding: $ic-sp;
border-top: 1px solid $te-border-color;
border-bottom: 1px solid $te-border-color;
select {
margin: 0;
}
}
//// Tabs for Theme Editor
///////