Skip to content

Commit

Permalink
Use an optional permission for tabs (#145)
Browse files Browse the repository at this point in the history
This will remove the need to grant a seemingly dodgy permission on install.
  • Loading branch information
fwouts committed Apr 19, 2019
1 parent 0476a61 commit 22c9256
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 24 deletions.
3 changes: 2 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "PR Monitor",
"version": "0.0.0",
"description": "Get notified when you receive a pull request on GitHub.",
"permissions": ["alarms", "notifications", "storage", "tabs"],
"permissions": ["alarms", "notifications", "storage"],
"optional_permissions": ["tabs"],
"background": {
"scripts": ["background.js"],
"persistent": true
Expand Down
13 changes: 13 additions & 0 deletions src/chrome/fake-chrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export const fakeChrome = (<Partial<ChromeApi>>{
}
}
},
permissions: {
request(_permissions, callback) {
if (callback) {
callback(true);
}
},
getAll(callback) {
callback({});
}
},
storage: {
// To simulate chrome.storage.local, we simply fall back to the localStorage API.
local: {
Expand All @@ -63,6 +73,9 @@ export const fakeChrome = (<Partial<ChromeApi>>{
tabs: {
query(_queryInfo, callback) {
callback([]);
},
create(properties) {
window.open(properties.url);
}
}
}) as ChromeApi;
2 changes: 1 addition & 1 deletion src/components/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class Popup extends Component<PopupProps, PopupState> {
}

private onOpen = (pullRequestUrl: string) => {
this.props.core.openPullRequest(pullRequestUrl);
this.props.core.openPullRequest(pullRequestUrl).catch(console.error);
};

private onMute = (pullRequest: PullRequest) => {
Expand Down
5 changes: 3 additions & 2 deletions src/environment/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { buildTabOpener } from "../tabs/implementation";
import { Environment } from "./api";

export function buildEnvironment(chromeApi: ChromeApi): Environment {
const store = buildStore(chromeApi);
return {
store: buildStore(chromeApi),
store,
githubLoader: buildGitHubLoader(),
notifier: buildNotifier(chromeApi),
badger: buildBadger(chromeApi),
messenger: buildMessenger(chromeApi),
tabOpener: buildTabOpener(chromeApi),
tabOpener: buildTabOpener(chromeApi, store),
isOnline: () => navigator.onLine
};
}
5 changes: 3 additions & 2 deletions src/environment/testing/fake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ function fakeStore() {
lastCheck: fakeStorage<LoadedState | null>(null),
muteConfiguration: fakeStorage<MuteConfiguration>(NOTHING_MUTED),
notifiedPullRequests: fakeStorage<string[]>([]),
token: fakeStorage<string | null>(null)
token: fakeStorage<string | null>(null),
lastRequestForTabsPermission: fakeStorage<number | null>(null)
};
}

Expand Down Expand Up @@ -121,7 +122,7 @@ function fakeTabOpener() {
const openedUrls: string[] = [];
return {
openedUrls,
openPullRequest(pullRequestUrl: string) {
async openPullRequest(pullRequestUrl: string) {
openedUrls.push(pullRequestUrl);
}
};
Expand Down
8 changes: 5 additions & 3 deletions src/state/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export class Core {
this.load();
}
});
this.env.notifier.registerClickListener(url => this.openPullRequest(url));
this.env.notifier.registerClickListener(url =>
this.openPullRequest(url).catch(console.error)
);
}

async load() {
Expand Down Expand Up @@ -95,8 +97,8 @@ export class Core {
}
}

openPullRequest(pullRequestUrl: string) {
this.env.tabOpener.openPullRequest(pullRequestUrl);
async openPullRequest(pullRequestUrl: string) {
await this.env.tabOpener.openPullRequest(pullRequestUrl);
}

async mutePullRequest(pullRequest: {
Expand Down
5 changes: 5 additions & 0 deletions src/storage/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export interface Store {
* Storage of the user's provided GitHub token.
*/
token: ValueStorage<string | null>;

/**
* Storage of the last timestamp we requested the "tabs" permission.
*/
lastRequestForTabsPermission: ValueStorage<number | null>;
}

export interface ValueStorage<T> {
Expand Down
6 changes: 5 additions & 1 deletion src/storage/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export function buildStore(chromeApi: ChromeApi): Store {
"lastSeenPullRequests",
[]
),
token: chromeValueStorage<string>(chromeApi, "gitHubApiToken")
token: chromeValueStorage<string>(chromeApi, "gitHubApiToken"),
lastRequestForTabsPermission: chromeValueStorage<number>(
chromeApi,
"lastRequestForTabsPermission"
)
};
}
2 changes: 1 addition & 1 deletion src/tabs/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
* TabOpener opens tabs intelligently (reusing them when possible).
*/
export interface TabOpener {
openPullRequest(pullRequestUrl: string): void;
openPullRequest(pullRequestUrl: string): Promise<void>;
}
62 changes: 49 additions & 13 deletions src/tabs/implementation.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,57 @@
import { ChromeApi } from "../chrome/api";
import { Store } from "../storage/api";
import { TabOpener } from "./api";

export function buildTabOpener(chromeApi: ChromeApi): TabOpener {
export function buildTabOpener(chromeApi: ChromeApi, store: Store): TabOpener {
return {
openPullRequest(pullRequestUrl: string) {
chromeApi.tabs.query({}, tabs => {
const existingTab = tabs.find(tab =>
tab.url ? tab.url.startsWith(pullRequestUrl) : false
async openPullRequest(pullRequestUrl: string) {
const lastRequestTimestamp = await store.lastRequestForTabsPermission.load();
if (lastRequestTimestamp !== null) {
// We requested the permission before already. Let's not be persistent.
chromeApi.permissions.getAll(permissions => {
const granted = permissions.permissions
? permissions.permissions.indexOf("tabs") !== -1
: false;
openTab(chromeApi, pullRequestUrl, granted);
});
} else {
await store.lastRequestForTabsPermission.save(Date.now());
chromeApi.permissions.request(
{
permissions: ["tabs"]
},
granted => {
openTab(chromeApi, pullRequestUrl, granted);
}
);
if (existingTab) {
chromeApi.tabs.highlight({
tabs: existingTab.index
});
} else {
window.open(pullRequestUrl);
}
});
}
}
};
}

function openTab(
chromeApi: ChromeApi,
pullRequestUrl: string,
permissionGranted: boolean
) {
if (permissionGranted) {
chromeApi.tabs.query({}, tabs => {
const existingTab = tabs.find(tab =>
tab.url ? tab.url.startsWith(pullRequestUrl) : false
);
if (existingTab) {
chromeApi.tabs.highlight({
tabs: existingTab.index
});
} else {
chrome.tabs.create({
url: pullRequestUrl
});
}
});
} else {
chrome.tabs.create({
url: pullRequestUrl
});
}
}

0 comments on commit 22c9256

Please sign in to comment.