From 4767dce74940a986e40e68180916e8ead6e51022 Mon Sep 17 00:00:00 2001 From: William Chargin Date: Fri, 29 Jun 2018 18:22:15 -0700 Subject: [PATCH] Implement the GitHub plugin adapter (#461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This enables grabbing the GitHub relational view from disk and converting it to a graph on the client. Paired with @decentralion. Test Plan: For testing, information about the GitHub graph is printed when you click the “Load data” button in the UI. Do so. wchargin-branch: github-plugin-adapter --- src/v3/app/credExplorer/App.js | 8 +++- src/v3/app/pluginAdapter.js | 13 ++++++ src/v3/plugins/github/pluginAdapter.js | 60 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/v3/app/pluginAdapter.js create mode 100644 src/v3/plugins/github/pluginAdapter.js diff --git a/src/v3/app/credExplorer/App.js b/src/v3/app/credExplorer/App.js index c2352b7..1c648e6 100644 --- a/src/v3/app/credExplorer/App.js +++ b/src/v3/app/credExplorer/App.js @@ -4,6 +4,7 @@ import React from "react"; import {StyleSheet, css} from "aphrodite/no-important"; import LocalStore from "./LocalStore"; +import {createPluginAdapter as createGithubAdapter} from "../../plugins/github/pluginAdapter"; type Props = {}; type State = { @@ -81,7 +82,12 @@ export default class App extends React.Component { console.error(`Invalid repository name: ${JSON.stringify(repoName)}`); return; } - console.log(`Would load data for: ${repoOwner}/${repoName}.`); + createGithubAdapter(repoOwner, repoName).then((githubAdapter) => { + const graph = githubAdapter.graph(); + const nodeCount = Array.from(graph.nodes()).length; + const edgeCount = Array.from(graph.edges()).length; + console.log(`Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`); + }); } } diff --git a/src/v3/app/pluginAdapter.js b/src/v3/app/pluginAdapter.js new file mode 100644 index 0000000..26805d5 --- /dev/null +++ b/src/v3/app/pluginAdapter.js @@ -0,0 +1,13 @@ +// @flow + +import type {Graph, NodeAddressT} from "../core/graph"; + +export interface Renderer { + nodeDescription(NodeAddressT): string; +} + +export interface PluginAdapter { + graph(): Graph; + renderer(): Renderer; + nodePrefix(): NodeAddressT; +} diff --git a/src/v3/plugins/github/pluginAdapter.js b/src/v3/plugins/github/pluginAdapter.js new file mode 100644 index 0000000..be22c4d --- /dev/null +++ b/src/v3/plugins/github/pluginAdapter.js @@ -0,0 +1,60 @@ +// @flow +import type { + PluginAdapter as IPluginAdapter, + Renderer as IRenderer, +} from "../../app/pluginAdapter"; +import {type Graph, NodeAddress} from "../../core/graph"; +import {createGraph} from "./createGraph"; +import * as N from "./nodes"; +import {RelationalView} from "./relationalView"; +import {description} from "./render"; + +export async function createPluginAdapter( + repoOwner: string, + repoName: string +): Promise { + const url = `/api/v1/data/data/${repoOwner}/${repoName}/github/view.json`; + const response = await fetch(url); + if (!response.ok) { + return Promise.reject(response); + } + const json = await response.json(); + const view = RelationalView.fromJSON(json); + const graph = createGraph(view); + return new PluginAdapter(view, graph); +} + +class PluginAdapter implements IPluginAdapter { + +_view: RelationalView; + +_graph: Graph; + constructor(view: RelationalView, graph: Graph) { + this._view = view; + this._graph = graph; + } + graph() { + return this._graph; + } + renderer() { + return new Renderer(this._view); + } + nodePrefix() { + return N._Prefix.base; + } +} + +class Renderer implements IRenderer { + +_view: RelationalView; + constructor(view) { + this._view = view; + } + nodeDescription(node) { + // This cast is unsound, and might throw at runtime, but won't have + // silent failures or cause problems down the road. + const address = N.fromRaw((node: any)); + const entity = this._view.entity(address); + if (entity == null) { + throw new Error(`unknown entity: ${NodeAddress.toString(node)}`); + } + return description(entity); + } +}