Skip to content

Commit

Permalink
Add a status at the top, with a refresh status and link (#148)
Browse files Browse the repository at this point in the history
This fixes #146.
  • Loading branch information
fwouts committed Apr 19, 2019
1 parent 123d4df commit 3eb09fc
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 158 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"@fortawesome/fontawesome-svg-core": "^1.2.17",
"@fortawesome/free-solid-svg-icons": "^5.8.1",
"@fortawesome/react-fontawesome": "^0.1.4",
"@types/moment": "^2.13.0",
"assert-never": "^1.1.0",
"bootstrap": "^4.3.1",
"mobx": "^5.9.4",
"mobx-react-lite": "^1.2.0",
"moment": "^2.24.0",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.8",
"react-dom": "^16.8.6",
Expand Down
21 changes: 0 additions & 21 deletions src/components/Error.tsx

This file was deleted.

184 changes: 92 additions & 92 deletions src/components/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { observer } from "mobx-react-lite";
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { Badge, Tab, Tabs } from "react-bootstrap";
import { Filter } from "../filtering/filters";
import { Core } from "../state/core";
import { PullRequest } from "../storage/loaded-state";
import { Error } from "./Error";
import { PullRequestList } from "./PullRequestList";
import { Settings } from "./Settings";
import { Status } from "./Status";

export interface PopupProps {
core: Core;
Expand All @@ -21,13 +21,6 @@ export const Popup = observer((props: PopupProps) => {
currentFilter: Filter.INCOMING
});

useEffect(() => {
props.core
.load()
.then(() => props.core.refreshPullRequests())
.catch(console.error);
}, []);

const onOpen = (pullRequestUrl: string) => {
props.core.openPullRequest(pullRequestUrl).catch(console.error);
};
Expand All @@ -47,93 +40,100 @@ export const Popup = observer((props: PopupProps) => {

return (
<>
<Error lastError={props.core.lastError} />
{props.core.token && !props.core.lastError && (
<>
<Tabs
id="popup-tabs"
activeKey={state.currentFilter}
onSelect={(key: Filter) => setState({ currentFilter: key })}
>
<Tab
title={
<>
Incoming PRs{" "}
{props.core.filteredPullRequests && (
<Badge
variant={
props.core.filteredPullRequests.incoming.length > 0
? "danger"
: "secondary"
}
>
{props.core.filteredPullRequests.incoming.length}
</Badge>
)}
</>
<Status core={props.core} />
{props.core.token &&
// Don't show the list if there was an error, we're not refreshing
// anymore (because of the error) and we don't have any loaded state.
!(
props.core.lastError &&
!props.core.refreshing &&
!props.core.loadedState
) && (
<>
<Tabs
id="popup-tabs"
activeKey={state.currentFilter}
onSelect={(key: Filter) => setState({ currentFilter: key })}
>
<Tab
title={
<>
Incoming PRs{" "}
{props.core.filteredPullRequests && (
<Badge
variant={
props.core.filteredPullRequests.incoming.length > 0
? "danger"
: "secondary"
}
>
{props.core.filteredPullRequests.incoming.length}
</Badge>
)}
</>
}
eventKey={Filter.INCOMING}
/>
<Tab
title={
<>
Muted{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.muted.length}
</Badge>
)}
</>
}
eventKey={Filter.MUTED}
/>
<Tab
title={
<>
Already reviewed{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.reviewed.length}
</Badge>
)}
</>
}
eventKey={Filter.REVIEWED}
/>
<Tab
title={
<>
My PRs{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.mine.length}
</Badge>
)}
</>
}
eventKey={Filter.MINE}
/>
</Tabs>
<PullRequestList
pullRequests={
props.core.filteredPullRequests
? props.core.filteredPullRequests[state.currentFilter]
: null
}
eventKey={Filter.INCOMING}
/>
<Tab
title={
<>
Muted{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.muted.length}
</Badge>
)}
</>
emptyMessage={
state.currentFilter === Filter.INCOMING
? `Nothing to review, yay!`
: `There's nothing to see here.`
}
eventKey={Filter.MUTED}
/>
<Tab
title={
<>
Already reviewed{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.reviewed.length}
</Badge>
)}
</>
}
eventKey={Filter.REVIEWED}
/>
<Tab
title={
<>
My PRs{" "}
{props.core.filteredPullRequests && (
<Badge variant="secondary">
{props.core.filteredPullRequests.mine.length}
</Badge>
)}
</>
allowMuting={
state.currentFilter === Filter.INCOMING ||
state.currentFilter === Filter.MUTED
}
eventKey={Filter.MINE}
onOpen={onOpen}
onMute={onMute}
/>
</Tabs>
<PullRequestList
pullRequests={
props.core.filteredPullRequests
? props.core.filteredPullRequests[state.currentFilter]
: null
}
emptyMessage={
state.currentFilter === Filter.INCOMING
? `Nothing to review, yay!`
: `There's nothing to see here.`
}
allowMuting={
state.currentFilter === Filter.INCOMING ||
state.currentFilter === Filter.MUTED
}
onOpen={onOpen}
onMute={onMute}
/>
</>
)}
</>
)}
{props.core.overallStatus !== "loading" && <Settings core={props.core} />}
</>
);
Expand Down
45 changes: 45 additions & 0 deletions src/components/Status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { observer } from "mobx-react-lite";
import moment from "moment";
import React from "react";
import { Alert } from "react-bootstrap";
import { Core } from "../state/core";
import { Link } from "./design/Link";

export interface StatusProps {
core: Core;
}

export const Status = observer((props: StatusProps) => {
// TODO: Refresh button.
// TODO: Ensure it works on dev.
let lastUpdated;
if (props.core.loadedState && props.core.loadedState.startRefreshTimestamp) {
lastUpdated = (
<div>
Last updated{" "}
{moment(props.core.loadedState.startRefreshTimestamp).fromNow()}
{". "}
{props.core.refreshing ? (
"Refreshing..."
) : (
<Link
onClick={() => {
props.core.triggerBackgroundRefresh();
}}
>
Refresh now
</Link>
)}
</div>
);
}
if (props.core.lastError) {
return (
<Alert variant="danger">
<div>Error: {props.core.lastError}</div>
{lastUpdated}
</Alert>
);
}
return lastUpdated ? <Alert variant="info">{lastUpdated}</Alert> : <></>;
});
1 change: 1 addition & 0 deletions src/components/design/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export const Link = styled.a`
text-decoration: none;
font-weight: bold;
color: #000;
cursor: pointer;
`;
1 change: 1 addition & 0 deletions src/environment/testing/fake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function fakeStore() {
return {
lastError: fakeStorage<string | null>(null),
lastCheck: fakeStorage<LoadedState | null>(null),
currentlyRefreshing: fakeStorage<boolean>(false),
muteConfiguration: fakeStorage<MuteConfiguration>(NOTHING_MUTED),
notifiedPullRequests: fakeStorage<string[]>([]),
token: fakeStorage<string | null>(null),
Expand Down
4 changes: 3 additions & 1 deletion src/popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { Core } from "./state/core";
library.add(faBellSlash);

const env = buildEnvironment(chromeApiSingleton);
const core = new Core(env);
core.load().catch(console.error);

ReactDOM.render(
<>
Expand All @@ -38,7 +40,7 @@ ReactDOM.render(
}
`}
/>
<Popup core={new Core(env)} />
<Popup core={core} />
</>,
document.getElementById("root")
);
Loading

0 comments on commit 3eb09fc

Please sign in to comment.