Skip to content

Commit

Permalink
Made auto update opt-in by default and changed UX. (#1575)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyanziano authored and cwhitten committed Jun 6, 2019
1 parent d1c6efe commit abd94f7
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.input-container {
display: flex;
flex-flow: column nowrap;

input[type="radio"] {
-webkit-appearance: none;
margin: 0;
margin-right: 8px;
height: 16px;
width: 16px;
box-sizing: border-box;
background-color: var(--radio-bg-color);
border-radius: 50%;
border: 1px solid var(--radio-border-color);

&:checked {
border: 5px solid var(--radio-selected-border-color);
}
}

> span {
display: flex;
flex-flow: row nowrap;
align-items: center;
margin-bottom: 8px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is a generated file. Changes are likely to result in being overwritten
export const inputContainer: string;
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { mount } from 'enzyme';
import { navBar } from '../../../data/reducer/navBar';

import { UpdateAvailableDialogContainer } from './updateAvailableDialogContainer';
import { UpdateAvailableDialog } from './updateAvailableDialog';
import { Options, UpdateAvailableDialog } from './updateAvailableDialog';

let mockHideDialog;
jest.mock('../service', () => ({
Expand Down Expand Up @@ -74,13 +74,14 @@ describe('UpdateAvailableDialog', () => {
expect(node.find(UpdateAvailableDialog)).not.toBe(null);
});

it('should change state when the install after download checkbox is toggled', () => {
instance.setState({ installAfterDownload: false });
it('should change state when the install after a radio button is selected', () => {
const mockEvent = { target: { value: Options[Options.AutoUpdate] } };
instance.setState({ selectedOption: 0 });

instance.onChangeInstallAfterDownload();
instance.onChange(mockEvent);

const state = instance.state;
expect(state.installAfterDownload).toBe(true);
expect(state.selectedOption).toBe(2);
});

it('should close properly', () => {
Expand All @@ -89,9 +90,9 @@ describe('UpdateAvailableDialog', () => {
expect(mockHideDialog).toHaveBeenCalledWith(null);
});

it('should close and return the passed in value when "Download" is clicked', () => {
instance.props.onDownloadClick(true);
it('should close and return the passed in value when "Update" is clicked', () => {
instance.props.onUpdateClick(1);

expect(mockHideDialog).toHaveBeenCalledWith({ installAfterDownload: true });
expect(mockHideDialog).toHaveBeenCalledWith(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -31,48 +31,91 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

import { Checkbox, DefaultButton, Dialog, DialogFooter, PrimaryButton } from '@bfemulator/ui-react';
import { DefaultButton, Dialog, DialogFooter, PrimaryButton } from '@bfemulator/ui-react';
import * as React from 'react';

import * as styles from './updateAvailableDialog.scss';

export enum Options {
ManuallyInstall,
InstallAndRestart,
AutoUpdate,
}

export interface UpdateAvailableDialogProps {
autoInstallUpdates?: boolean;
onCloseClick?: () => any;
onDownloadClick?: (installAfterDownload: boolean) => any;
onUpdateClick?: (updateOption: number) => any;
version?: string;
}

export interface UpdateAvailableDialogState {
installAfterDownload: boolean;
selectedOption: Options;
}

export class UpdateAvailableDialog extends React.Component<UpdateAvailableDialogProps, UpdateAvailableDialogState> {
constructor(props: UpdateAvailableDialogProps) {
super(props);

this.state = { installAfterDownload: false };
this.state = {
selectedOption: Options.InstallAndRestart,
};
}

public render(): JSX.Element {
const { onCloseClick, onDownloadClick, version } = this.props;
const { installAfterDownload } = this.state;
const { onChangeInstallAfterDownload } = this;
const { onCloseClick, onUpdateClick, version } = this.props;
const { selectedOption } = this.state;

return (
<Dialog cancel={onCloseClick} title="Update available">
<p>Bot Framework Emulator {version} is available. Would you like to download the new version?</p>
<Checkbox
label="Restart the emulator and install update after download"
checked={installAfterDownload}
onChange={onChangeInstallAfterDownload}
/>
<div className={styles.inputContainer}>
<span>
<input
name="update-choice"
type="radio"
id="choice1"
value={Options[Options.ManuallyInstall]}
onChange={this.onChange}
checked={selectedOption === Options.ManuallyInstall}
/>
<label htmlFor="choice1">Download and manually install this update.</label>
</span>
<span>
<input
name="update-choice"
type="radio"
id="choice2"
value={Options[Options.InstallAndRestart]}
onChange={this.onChange}
checked={selectedOption === Options.InstallAndRestart}
/>
<label htmlFor="choice2">Install this update and restart Emulator.</label>
</span>
<span>
<input
name="update-choice"
type="radio"
id="choice3"
value={Options[Options.AutoUpdate]}
onChange={this.onChange}
checked={selectedOption === Options.AutoUpdate}
/>
<label htmlFor="choice3">Automatically download and install all updates.</label>
</span>
</div>
<DialogFooter>
<DefaultButton text="Cancel" onClick={onCloseClick} />
<PrimaryButton text="Download" onClick={() => onDownloadClick(this.state.installAfterDownload)} />
<PrimaryButton text="Update" onClick={() => onUpdateClick(this.state.selectedOption)} />
</DialogFooter>
</Dialog>
);
}

private onChangeInstallAfterDownload = (): void => {
this.setState({ installAfterDownload: !this.state.installAfterDownload });
private onChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
const {
target: { value },
} = ev;
this.setState({ selectedOption: Options[value] });
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import { UpdateAvailableDialog, UpdateAvailableDialogProps } from './updateAvail
function mapDispatchToProps(_dispatch: any): UpdateAvailableDialogProps {
return {
onCloseClick: () => DialogService.hideDialog(null),
onDownloadClick: (installAfterDownload: boolean) => {
DialogService.hideDialog({ installAfterDownload });
onUpdateClick: (updateOption: number) => {
DialogService.hideDialog(updateOption);
},
};
}
Expand Down
5 changes: 5 additions & 0 deletions packages/app/client/src/ui/styles/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ html {
--service-picker-scrollbar-thumb: var(--scrollbar-color);
--service-picker-scrollbar-track: var(--neutral-4);
--service-picker-select-all-border: 1px solid transparent;

/* Radio buttons */
--radio-bg-color: var(--neutral-1);
--radio-border-color: var(--neutral-16);
--radio-selected-border-color: #3B99FC;
}

.dialog {
Expand Down
5 changes: 5 additions & 0 deletions packages/app/client/src/ui/styles/themes/high-contrast.css
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ html {
--service-picker-scrollbar-thumb: var(--neutral-1);
--service-picker-scrollbar-track: transparent;
--service-picker-select-all-border: 1px solid transparent;

/* Radio buttons */
--radio-bg-color: var(--neutral-1);
--radio-border-color: var(--neutral-1);
--radio-selected-border-color: #3B99FC;
}

.dialog .ms-Button-label {
Expand Down
5 changes: 5 additions & 0 deletions packages/app/client/src/ui/styles/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,9 @@ html {
--service-picker-scrollbar-thumb: var(--scrollbar-color);
--service-picker-scrollbar-track: var(--neutral-4);
--service-picker-select-all-border: 1px solid transparent;

/* Radio buttons */
--radio-bg-color: var(--neutral-1);
--radio-border-color: var(--neutral-16);
--radio-selected-border-color: #3B99FC;
}
Loading

0 comments on commit abd94f7

Please sign in to comment.