mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
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:
@@ -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>
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user