Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a status at the top, with a refresh status and link #148

Merged
merged 7 commits into from
Apr 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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