feat(ui): colo fetch indicator with text-success when response is being processed

This add a visual indicator of the progress, helpful for big responses or slow connections
This commit is contained in:
Łukasz Mierzwa
2018-09-18 19:45:18 +01:00
parent ff27f358f3
commit 9822bce87c
5 changed files with 87 additions and 16 deletions

View File

@@ -24,7 +24,7 @@ exports[`<FetchIndicator /> matches snapshot when idle 1`] = `
<svg aria-hidden=\\"true\\"
data-prefix=\\"fas\\"
data-icon=\\"circle-notch\\"
class=\\"svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg mx-1 text-muted\\"
class=\\"svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg mx-1 text-success\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
@@ -37,3 +37,22 @@ exports[`<FetchIndicator /> matches snapshot when idle 1`] = `
</svg>
"
`;
exports[`<FetchIndicator /> matches snapshot when response is processed 1`] = `
"
<svg aria-hidden=\\"true\\"
data-prefix=\\"fas\\"
data-icon=\\"circle-notch\\"
class=\\"svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg mx-1 text-success\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
style=\\"opacity: 1;\\"
>
<path fill=\\"currentColor\\"
d=\\"M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z\\"
>
</path>
</svg>
"
`;

View File

@@ -13,11 +13,19 @@ class FetchIndicator extends Component {
render() {
const { status } = this.props;
const visible = status === AlertStoreStatuses.InProgress.toString();
const visible =
status === AlertStoreStatuses.Fetching.toString() ||
status === AlertStoreStatuses.Processing.toString();
const textClass =
status === AlertStoreStatuses.Fetching.toString()
? "text-muted"
: "text-success";
return (
<FontAwesomeIcon
style={{ opacity: visible ? 1 : 0 }}
className="mx-1 text-muted"
className={`mx-1 ${textClass}`}
icon={faCircleNotch}
size="lg"
spin

View File

@@ -10,11 +10,32 @@ import { AlertStoreStatuses } from "Stores/AlertStore";
describe("<FetchIndicator />", () => {
it("opacity is 1 when fetch is in progress", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.InProgress.toString()} />
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
);
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(1);
});
it("uses text-muted when fetch is in progress", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
);
expect(tree.find("FontAwesomeIcon").hasClass("text-muted")).toBe(true);
});
it("opacity is 1 when response is processed", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
);
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(1);
});
it("uses text-success when response is processed", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
);
expect(tree.find("FontAwesomeIcon").hasClass("text-success")).toBe(true);
});
it("opacity is 0 when idle", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.Idle.toString()} />
@@ -31,7 +52,14 @@ describe("<FetchIndicator />", () => {
it("matches snapshot when fetch is in progress", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.InProgress.toString()} />
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});
it("matches snapshot when response is processed", () => {
const tree = mount(
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});

View File

@@ -67,7 +67,8 @@ function UpdateLocationSearch(newParams) {
const AlertStoreStatuses = Object.freeze({
Idle: Symbol("idle"),
InProgress: Symbol("in-progres"),
Fetching: Symbol("fetching"),
Processing: Symbol("processing"),
Failure: Symbol("failure")
});
@@ -172,8 +173,12 @@ class AlertStore {
this.value = AlertStoreStatuses.Idle;
this.error = null;
},
setInProgress() {
this.value = AlertStoreStatuses.InProgress;
setFetching() {
this.value = AlertStoreStatuses.Fetching;
this.error = null;
},
setProcessing() {
this.value = AlertStoreStatuses.Processing;
this.error = null;
},
setFailure(err) {
@@ -183,7 +188,8 @@ class AlertStore {
},
{
setIdle: action,
setInProgress: action,
setFetching: action,
setProcessing: action,
setFailure: action
},
{ name: "Store status" }
@@ -194,14 +200,17 @@ class AlertStore {
}
fetch = action(() => {
this.status.setInProgress();
this.status.setFetching();
const alertsURI =
FormatBackendURI("alerts.json?") +
FormatAPIFilterQuery(this.filters.values.map(f => f.raw));
return fetch(alertsURI, { credentials: "include" })
.then(result => result.json())
.then(result => {
this.status.setProcessing();
return result.json();
})
.then(result => {
return this.parseAPIResponse(result);
})

View File

@@ -25,10 +25,17 @@ describe("AlertStore.status", () => {
expect(store.status.error).toBeNull();
});
it("status is InProgress with no error after setInProgress", () => {
it("status is Fetching with no error after setFetching()", () => {
const store = new AlertStore([]);
store.status.setInProgress();
expect(store.status.value).toEqual(AlertStoreStatuses.InProgress);
store.status.setFetching();
expect(store.status.value).toEqual(AlertStoreStatuses.Fetching);
expect(store.status.error).toBeNull();
});
it("status is Processing with no error after setProcessing()", () => {
const store = new AlertStore([]);
store.status.setProcessing();
expect(store.status.value).toEqual(AlertStoreStatuses.Processing);
expect(store.status.error).toBeNull();
});
@@ -39,9 +46,9 @@ describe("AlertStore.status", () => {
expect(store.status.error).toEqual("my error");
});
it("status is Idle with no error after setInProgress and setIdle", () => {
it("status is Idle with no error after setFetching and setIdle", () => {
const store = new AlertStore([]);
store.status.setInProgress();
store.status.setFetching();
store.status.setIdle();
expect(store.status.value).toEqual(AlertStoreStatuses.Idle);
expect(store.status.error).toBeNull();