Skip to content

Commit

Permalink
refactor: clean up gist action states (#491)
Browse files Browse the repository at this point in the history
* refactor: clean up gist action states

* fix: tweak small state edge case
  • Loading branch information
codebytere committed Sep 24, 2020
1 parent 24435b3 commit 6e54dd6
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 35 deletions.
7 changes: 7 additions & 0 deletions src/interfaces.ts
Expand Up @@ -22,6 +22,13 @@ export enum GistActionType {
delete = 'Delete',
}

export enum GistActionState {
publishing = 'publishing',
updating = 'updating',
deleting = 'deleting',
none = 'none',
}

export interface Version {
version: string;
name?: string;
Expand Down
35 changes: 21 additions & 14 deletions src/renderer/components/commands-action-button.tsx
Expand Up @@ -12,7 +12,11 @@ import { observer } from 'mobx-react';
import * as React from 'react';

import { when } from 'mobx';
import { EditorValues, GistActionType } from '../../interfaces';
import {
EditorValues,
GistActionState,
GistActionType,
} from '../../interfaces';
import { IpcEvents } from '../../ipc-events';
import {
INDEX_HTML_NAME,
Expand Down Expand Up @@ -112,7 +116,7 @@ export class GistActionButton extends React.Component<
const options = { includeDependencies: true, includeElectron: true };
const values = await window.ElectronFiddle.app.getEditorValues(options);

appState.isPublishing = true;
appState.activeGistAction = GistActionState.publishing;

try {
const gist = await octo.gists.create({
Expand All @@ -126,6 +130,9 @@ export class GistActionButton extends React.Component<

console.log(`Publish Button: Publishing complete`, { gist });
this.renderToast({ message: 'Publishing completed successfully!' });

// Only set action type to update if publish completed successfully.
this.setActionType(GistActionType.update);
} catch (error) {
console.warn(`Could not publish gist`, { error });

Expand All @@ -138,8 +145,7 @@ export class GistActionButton extends React.Component<
ipcRendererManager.send(IpcEvents.SHOW_WARNING_DIALOG, messageBoxOptions);
}

appState.isPublishing = false;
this.setActionType(GistActionType.update);
appState.activeGistAction = GistActionState.none;
}

/**
Expand All @@ -151,7 +157,7 @@ export class GistActionButton extends React.Component<
const options = { includeDependencies: true, includeElectron: true };
const values = await window.ElectronFiddle.app.getEditorValues(options);

this.setState({ isUpdating: true });
appState.activeGistAction = GistActionState.updating;

try {
const gist = await octo.gists.update({
Expand All @@ -173,7 +179,7 @@ export class GistActionButton extends React.Component<
ipcRendererManager.send(IpcEvents.SHOW_WARNING_DIALOG, messageBoxOptions);
}

this.setState({ isUpdating: false });
appState.activeGistAction = GistActionState.none;
this.setActionType(GistActionType.update);
}

Expand All @@ -184,7 +190,8 @@ export class GistActionButton extends React.Component<
const { appState } = this.props;
const octo = await getOctokit(this.props.appState);

this.setState({ isDeleting: true });
appState.activeGistAction = GistActionState.deleting;

try {
const gist = await octo.gists.delete({
gist_id: appState.gistId!,
Expand All @@ -205,7 +212,7 @@ export class GistActionButton extends React.Component<
}

appState.gistId = undefined;
this.setState({ isDeleting: false });
appState.activeGistAction = GistActionState.none;
this.setActionType(GistActionType.publish);
}

Expand Down Expand Up @@ -253,18 +260,18 @@ export class GistActionButton extends React.Component<
}

public render() {
const { isPublishing, gistId } = this.props.appState;
const { isDeleting, isUpdating, actionType } = this.state;
const { gistId, activeGistAction } = this.props.appState;
const { actionType } = this.state;

const getTextForButton = () => {
let text;
if (gistId) {
text = actionType;
} else if (isUpdating) {
} else if (activeGistAction === GistActionState.updating) {
text = 'Updating...';
} else if (isPublishing) {
} else if (activeGistAction === GistActionState.publishing) {
text = 'Publishing...';
} else if (isDeleting) {
} else if (activeGistAction === GistActionState.deleting) {
text = 'Deleting...';
} else {
text = 'Publish';
Expand All @@ -283,7 +290,7 @@ export class GistActionButton extends React.Component<
}
};

const isPerformingAction = isPublishing || isUpdating || isDeleting;
const isPerformingAction = activeGistAction !== GistActionState.none;
return (
<>
<fieldset disabled={isPerformingAction}>
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/components/commands-address-bar.tsx
Expand Up @@ -5,6 +5,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';

import { IpcEvents } from '../../ipc-events';
import { GistActionState } from '../../interfaces';
import { idFromUrl, urlFromId } from '../../utils/gist';
import { ipcRendererManager } from '../ipc';
import { AppState } from '../state';
Expand Down Expand Up @@ -121,14 +122,15 @@ export class AddressBar extends React.Component<
}

public render() {
const { isUnsaved, isPublishing } = this.props.appState;
const { isUnsaved, activeGistAction } = this.props.appState;
const { value } = this.state;
const isCorrect = /https:\/\/gist\.github\.com\/(.+)$/.test(value);
const className = classnames('address-bar', isUnsaved, { empty: !value });

const isPerformingAction = activeGistAction !== GistActionState.none;
return (
<form className={className} onSubmit={this.handleSubmit}>
<fieldset disabled={isPublishing}>
<fieldset disabled={isPerformingAction}>
<InputGroup
key="addressbar"
leftIcon="geosearch"
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/state.ts
Expand Up @@ -8,6 +8,7 @@ import {
EditorId,
GenericDialogOptions,
GenericDialogType,
GistActionState,
MosaicId,
OutputEntry,
OutputOptions,
Expand Down Expand Up @@ -151,7 +152,7 @@ export class AppState {
@observable public localTypeWatcher: fsType.FSWatcher | undefined;
@observable public Bisector: Bisector | undefined;

@observable public isPublishing = false;
@observable public activeGistAction: GistActionState = GistActionState.none;
@observable public isRunning = false;
@observable public isUnsaved: boolean;
@observable public isUpdatingElectronVersions = false;
Expand Down
Expand Up @@ -5,7 +5,9 @@ exports[`AddressBar component renders 1`] = `
className="address-bar empty"
onSubmit={[Function]}
>
<fieldset>
<fieldset
disabled={true}
>
<Blueprint3.InputGroup
key="addressbar"
leftIcon="geosearch"
Expand Down
Expand Up @@ -3,7 +3,7 @@
exports[`Publish button component renders 1`] = `
<Fragment>
<fieldset
disabled={false}
disabled={true}
>
<Blueprint3.ButtonGroup
className="button-gist-action"
Expand Down Expand Up @@ -58,7 +58,7 @@ exports[`Publish button component renders 1`] = `
</Blueprint3.Popover>
<Blueprint3.Button
icon="upload"
loading={false}
loading={true}
onClick={[Function]}
text="Publish"
/>
Expand Down
55 changes: 49 additions & 6 deletions tests/renderer/components/commands-address-bar-spec.tsx
Expand Up @@ -5,6 +5,7 @@ import { observable } from 'mobx';
import { AddressBar } from '../../../src/renderer/components/commands-address-bar';
import { ElectronFiddleMock } from '../../mocks/electron-fiddle';
import { MockState } from '../../mocks/state';
import { GistActionState } from '../../../src/interfaces';

jest.mock('../../../src/utils/octokit');

Expand Down Expand Up @@ -68,12 +69,54 @@ describe('AddressBar component', () => {
it('disables during gist publishing', async () => {
const wrapper = shallow(<AddressBar appState={store} />);

wrapper.setProps({ appState: { ...store, isPublishing: true } }, () => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
});
wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.publishing } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);

wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
});

it('disables during gist updating', async () => {
const wrapper = shallow(<AddressBar appState={store} />);

wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.updating } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);

wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
});

it('disables during gist deleting', async () => {
const wrapper = shallow(<AddressBar appState={store} />);

wrapper.setProps({ appState: { ...store, isPublishing: false } }, () => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
});
wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.deleting } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);

wrapper.setProps(
{ appState: { ...store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
});
});
80 changes: 71 additions & 9 deletions tests/renderer/components/commands-publish-button-spec.tsx
@@ -1,6 +1,6 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { GistActionType } from '../../../src/interfaces';
import { GistActionState, GistActionType } from '../../../src/interfaces';

import { GistActionButton } from '../../../src/renderer/components/commands-action-button';
import { getOctokit } from '../../../src/utils/octokit';
Expand Down Expand Up @@ -182,7 +182,7 @@ describe('Publish button component', () => {

await instance.performGistAction();

expect(store.isPublishing).toBe(false);
expect(store.activeGistAction).toBe(GistActionState.none);
});

it('uses the privacy setting correctly', async () => {
Expand Down Expand Up @@ -218,20 +218,82 @@ describe('Publish button component', () => {
});

it('disables during gist publishing', async () => {
store.isPublishing = false;
store.activeGistAction = GistActionState.none;
const wrapper = shallow(<GistActionButton appState={store} />);
const instance: GistActionButton = wrapper.instance() as any;

expect(wrapper.find('fieldset').prop('disabled')).toBe(false);

instance.performGistAction = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve) => {
wrapper.setProps({ appState: { store, isPublishing: true } }, () => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
});
wrapper.setProps({ appState: { store, isPublishing: false } }, () => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
});
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.publishing } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
resolve();
});
});

await instance.performGistAction();
});

it('disables during gist updating', async () => {
store.activeGistAction = GistActionState.none;
const wrapper = shallow(<GistActionButton appState={store} />);
const instance: GistActionButton = wrapper.instance() as any;

expect(wrapper.find('fieldset').prop('disabled')).toBe(false);

instance.performGistAction = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve) => {
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.updating } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
resolve();
});
});

await instance.performGistAction();
});

it('disables during gist deleting', async () => {
store.activeGistAction = GistActionState.none;
const wrapper = shallow(<GistActionButton appState={store} />);
const instance: GistActionButton = wrapper.instance() as any;

expect(wrapper.find('fieldset').prop('disabled')).toBe(false);

instance.performGistAction = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve) => {
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.deleting } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(true);
},
);
wrapper.setProps(
{ appState: { store, activeGistAction: GistActionState.none } },
() => {
expect(wrapper.find('fieldset').prop('disabled')).toBe(false);
},
);
resolve();
});
});
Expand Down

0 comments on commit 6e54dd6

Please sign in to comment.