Save graph fetcher credentials in local storage

Test Plan:
Make a request, then refresh, and note that the fields are populated.

Paired with @dandelionmane.

wchargin-branch: graph-fetcher-localstore
This commit is contained in:
William Chargin 2018-03-19 17:33:27 -07:00
parent 5d80e39473
commit 55225fd53e
2 changed files with 89 additions and 1 deletions

View File

@ -3,6 +3,7 @@
import React from "react"; import React from "react";
import type {Graph} from "../../../core/graph"; import type {Graph} from "../../../core/graph";
import LocalStore from "./LocalStore";
import fetchGitHubRepo from "../../github/fetchGitHubRepo"; import fetchGitHubRepo from "../../github/fetchGitHubRepo";
import type { import type {
NodePayload as GitHubNodePayload, NodePayload as GitHubNodePayload,
@ -19,14 +20,17 @@ type State = {
repoName: string, repoName: string,
}; };
const SETTINGS_KEY = "GitHubGraphFetcher.settings";
export class GitHubGraphFetcher extends React.Component<Props, State> { export class GitHubGraphFetcher extends React.Component<Props, State> {
constructor() { constructor() {
super(); super();
this.state = { const defaultState = {
apiToken: "", apiToken: "",
repoOwner: "", repoOwner: "",
repoName: "", repoName: "",
}; };
this.state = LocalStore.get(SETTINGS_KEY, defaultState);
} }
render() { render() {
@ -78,6 +82,7 @@ export class GitHubGraphFetcher extends React.Component<Props, State> {
fetchGraph() { fetchGraph() {
const {repoOwner, repoName, apiToken} = this.state; const {repoOwner, repoName, apiToken} = this.state;
LocalStore.set(SETTINGS_KEY, {apiToken, repoOwner, repoName});
fetchGitHubRepo(repoOwner, repoName, apiToken) fetchGitHubRepo(repoOwner, repoName, apiToken)
.then((json) => { .then((json) => {
const parser = new GithubParser(`${repoOwner}/${repoName}`); const parser = new GithubParser(`${repoOwner}/${repoName}`);

View File

@ -0,0 +1,83 @@
// @flow
/*
* A simple abstraction over 'localStorage' to provide transparent JSON
* serialization and deserialization.
*
* The implementation is borrowed heavily from Khan Academy's LocalStore
* module, and also KaVideoPlayer's SafeLocalStore module.
*/
export default {
// Bump this to expire all old values.
version: 1,
keyPrefix: "artifact-editor",
cacheKey(key: string): string {
if (!key) {
throw new Error("Falsy key provided to cacheKey: " + key);
}
return [this.keyPrefix, this.version, key].join(":");
},
get(key: string, whenUnavailable: any): any {
if (!this.isEnabled()) {
return whenUnavailable;
}
try {
const data = window.localStorage[this.cacheKey(key)];
if (data) {
return JSON.parse(data);
} else {
return whenUnavailable;
}
} catch (e) {
// If we had trouble retrieving, like FF's NS_FILE_CORRUPTED:
// http://stackoverflow.com/q/18877643/
return whenUnavailable;
}
},
set(key: string, data: any): void {
if (!this.isEnabled()) {
return;
}
const stringified = JSON.stringify(data);
try {
window.localStorage[this.cacheKey(key)] = stringified;
} catch (e) {
// Probably went over the storage limit... that's not good.
throw e;
}
},
/*
* Delete whatever data was associated with the given key.
*/
del(key: string): void {
if (!this.isEnabled()) {
return;
}
const cacheKey = this.cacheKey(key);
if (cacheKey in window.localStorage) {
// (IE throws when deleting a non-existent entry.)
delete window.localStorage[cacheKey];
}
},
/*
* Local storage might be disabled in old browsers or in Safari's
* private browsing mode. Don't die.
*/
isEnabled(): boolean {
const uid = String(+new Date());
try {
window.sessionStorage[uid] = uid;
const enabled = window.sessionStorage[uid] === uid;
window.sessionStorage.removeItem(uid);
return enabled;
} catch (e) {
return false;
}
},
};