From e916bc91c8c64b4ca5ee1e6df8a83d44d070f198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Thu, 13 Jun 2019 17:07:05 +0300 Subject: [PATCH] Temporarily remove the odyssey plugin (#1178) In #1132 and #1134, I started work on the Odyssey plugin. However, before getting it to a state where it's usefully included in SourceCred, I decided to pivot to focus on timeline cred first. Now I'm merging significant refactors as a part of timeline cred (#1136). As a side effect of this refactor, the Odyssey plugin should undergo significant changes (OdysseyInstance is now basically redundant with base Graph.) Rather than incrementally update unused code, I elect to remove the plugin. This code should be revived on a side branch, and then merged into master once we have a fully functioning prototype. Test plan: `yarn test` passes. --- src/homepage/OdysseyPage.js | 12 -- src/homepage/routeData.js | 9 - src/plugins/odyssey/analysisAdapter.js | 38 ----- src/plugins/odyssey/declaration.js | 82 --------- src/plugins/odyssey/example.js | 114 ------------- src/plugins/odyssey/explorerAdapter.js | 48 ------ src/plugins/odyssey/instance.js | 225 ------------------------- src/plugins/odyssey/instance.test.js | 152 ----------------- src/plugins/odyssey/ui/App.js | 153 ----------------- src/plugins/odyssey/ui/Header.js | 66 -------- src/plugins/odyssey/ui/img/logo.svg | 8 - 11 files changed, 907 deletions(-) delete mode 100644 src/homepage/OdysseyPage.js delete mode 100644 src/plugins/odyssey/analysisAdapter.js delete mode 100644 src/plugins/odyssey/declaration.js delete mode 100644 src/plugins/odyssey/example.js delete mode 100644 src/plugins/odyssey/explorerAdapter.js delete mode 100644 src/plugins/odyssey/instance.js delete mode 100644 src/plugins/odyssey/instance.test.js delete mode 100644 src/plugins/odyssey/ui/App.js delete mode 100644 src/plugins/odyssey/ui/Header.js delete mode 100755 src/plugins/odyssey/ui/img/logo.svg diff --git a/src/homepage/OdysseyPage.js b/src/homepage/OdysseyPage.js deleted file mode 100644 index de468b9..0000000 --- a/src/homepage/OdysseyPage.js +++ /dev/null @@ -1,12 +0,0 @@ -// @flow - -import React from "react"; - -import OdysseyApp from "../plugins/odyssey/ui/App"; -import type {Assets} from "../webutil/assets"; - -export default class HomePage extends React.Component<{|+assets: Assets|}> { - render() { - return ; - } -} diff --git a/src/homepage/routeData.js b/src/homepage/routeData.js index db083eb..867ccd2 100644 --- a/src/homepage/routeData.js +++ b/src/homepage/routeData.js @@ -85,15 +85,6 @@ function makeRouteData(registry /*: RepoIdRegistry */) /*: RouteData */ { title: `${entry.repoId.owner}/${entry.repoId.name} • SourceCred`, navTitle: null, })), - { - path: "/odyssey/", - contents: { - type: "PAGE", - component: () => require("./OdysseyPage").default, - }, - title: "Odyssey Prototype", - navTitle: null, - }, { path: "/discord-invite/", contents: { diff --git a/src/plugins/odyssey/analysisAdapter.js b/src/plugins/odyssey/analysisAdapter.js deleted file mode 100644 index b4a2e0a..0000000 --- a/src/plugins/odyssey/analysisAdapter.js +++ /dev/null @@ -1,38 +0,0 @@ -// @flow - -import type {RepoId} from "../../core/repoId"; -import {type NodeAddressT} from "../../core/graph"; -import type { - IBackendAdapterLoader, - IAnalysisAdapter, -} from "../../analysis/analysisAdapter"; -import {hackathonExample} from "./example"; -import {declaration} from "./declaration"; - -export class BackendAdapterLoader implements IBackendAdapterLoader { - declaration() { - return declaration; - } - // TODO(@decentralion): Enable loading graphs other than the hackathon example. - load( - _unused_sourcecredDirectory: string, - _unused_repoId: RepoId - ): Promise { - const aa: AnalysisAdapter = new AnalysisAdapter(); - // HACK: This any-coercion should be unncessary. Sad flow. - return Promise.resolve((aa: any)); - } -} - -export class AnalysisAdapter implements IAnalysisAdapter { - declaration() { - return declaration; - } - // TODO(@decentralion): Add real creation times to the data model - createdAt(_unused_node: NodeAddressT): null { - return null; - } - graph() { - return hackathonExample().graph(); - } -} diff --git a/src/plugins/odyssey/declaration.js b/src/plugins/odyssey/declaration.js deleted file mode 100644 index 8bf7138..0000000 --- a/src/plugins/odyssey/declaration.js +++ /dev/null @@ -1,82 +0,0 @@ -// @flow - -import {EdgeAddress, NodeAddress} from "../../core/graph"; - -import type {PluginDeclaration} from "../../analysis/pluginDeclaration"; -import type {NodeType} from "../../analysis/types"; - -export type OdysseyNodeTypeIdentifier = - | "ARTIFACT" - | "CONTRIBUTION" - | "VALUE" - | "PERSON"; - -export type OdysseyEdgeTypeIdentifier = "DEPENDS_ON"; - -export function isOdysseyNodeTypeIdentifier( - n: OdysseyNodeTypeIdentifier -): boolean { - return ["ARTIFACT", "CONTRIBUTION", "VALUE", "PERSON"].indexOf(n) !== -1; -} - -export const NODE_PREFIX = NodeAddress.fromParts(["sourcecred", "odyssey"]); - -export function isOdysseyEdgeTypeIdentifier(x: string): boolean { - return x === "DEPENDS_ON"; -} -export const EDGE_PREFIX = EdgeAddress.fromParts(["sourcecred", "odyssey"]); - -const artifactNodeType: NodeType = Object.freeze({ - name: "Artifact", - pluralName: "Artifacts", - prefix: NodeAddress.append(NODE_PREFIX, "ARTIFACT"), - defaultWeight: 2, - description: - "Represents a durably valuable piece of a project, e.g. a major subcomponent.", -}); - -const contributionNodeType: NodeType = Object.freeze({ - name: "Contribution", - pluralName: "Contributions", - prefix: NodeAddress.append(NODE_PREFIX, "CONTRIBUTION"), - defaultWeight: 1, - description: - "Represents any specific work or labor that went into a project.", -}); - -const valueNodeType: NodeType = Object.freeze({ - name: "Value", - pluralName: "Values", - prefix: NodeAddress.append(NODE_PREFIX, "VALUE"), - defaultWeight: 4, - description: "Represents a high-level value of the project.", -}); - -const personNodeType: NodeType = Object.freeze({ - name: "Person", - pluralName: "People", - prefix: NodeAddress.append(NODE_PREFIX, "PERSON"), - defaultWeight: 1, - description: "Represents an individual contributor.", -}); - -const dependsOnEdgeType = Object.freeze({ - forwardName: "depends on", - backwardName: "is depended on by", - prefix: EdgeAddress.append(EDGE_PREFIX, "DEPENDS_ON"), - defaultWeight: {forwards: 1, backwards: 0}, - description: "Generic edge for flowing credit in the Odyssey plugin", -}); - -export const declaration: PluginDeclaration = Object.freeze({ - name: "Odyssey", - nodePrefix: NODE_PREFIX, - edgePrefix: EDGE_PREFIX, - nodeTypes: [ - contributionNodeType, - valueNodeType, - personNodeType, - artifactNodeType, - ], - edgeTypes: [dependsOnEdgeType], -}); diff --git a/src/plugins/odyssey/example.js b/src/plugins/odyssey/example.js deleted file mode 100644 index 694cd0e..0000000 --- a/src/plugins/odyssey/example.js +++ /dev/null @@ -1,114 +0,0 @@ -// @flow - -import {OdysseyInstance, type Node} from "./instance"; - -/** - * An example Odyssey instance, based on work at the Odyssey Hackathon. - */ -export function hackathonExample(): OdysseyInstance { - // Define the types of nodes allowed in our instance - const instance = new OdysseyInstance(); - - // define our values for the hackathon - const logistics = instance.addNode("VALUE", "logistics"); - const design = instance.addNode("VALUE", "design"); - const narrative = instance.addNode("VALUE", "narrative"); - const prototype = instance.addNode("VALUE", "prototype"); - const outreach = instance.addNode("VALUE", "outreach"); - - // the cast of characters - const dl = instance.addNode("PERSON", "dandelion"); - const mz = instance.addNode("PERSON", "z zargham"); - const irene = instance.addNode("PERSON", "irene"); - const max = instance.addNode("PERSON", "max"); - const dennis = instance.addNode("PERSON", "dennis"); - const jonathan = instance.addNode("PERSON", "jonathan"); - const lb = instance.addNode("PERSON", "lb"); - const brian = instance.addNode("PERSON", "brian"); - const sarah = instance.addNode("PERSON", "sarah"); - const jmnemo = instance.addNode("PERSON", "@jmnemo"); - const talbott = instance.addNode("PERSON", "jonathan talbott"); - const agata = instance.addNode("PERSON", "agata"); - - // the artifacts - const graphviz = instance.addNode("ARTIFACT", "graph visualizer"); - const backend = instance.addNode("ARTIFACT", "backend"); - const frontend = instance.addNode("ARTIFACT", "frontend"); - const seededPagerank = instance.addNode("ARTIFACT", "seeded pagerank"); - const canvas = instance.addNode( - "ARTIFACT", - "the awesome illustrated poster board" - ); - const logo = instance.addNode("ARTIFACT", "the broken-lightbulb logo"); - - instance.addEdge("DEPENDS_ON", prototype, graphviz); - instance.addEdge("DEPENDS_ON", prototype, backend); - instance.addEdge("DEPENDS_ON", prototype, frontend); - instance.addEdge("DEPENDS_ON", frontend, seededPagerank); - instance.addEdge("DEPENDS_ON", design, graphviz); - instance.addEdge("DEPENDS_ON", design, frontend); - instance.addEdge("DEPENDS_ON", design, logo); - instance.addEdge("DEPENDS_ON", narrative, logo); - instance.addEdge("DEPENDS_ON", narrative, canvas); - - function addContribution( - description: string, - authors: Node[], - impacted: Node[] - ) { - const contrib = instance.addNode("CONTRIBUTION", description); - for (const author of authors) { - instance.addEdge("DEPENDS_ON", contrib, author); - } - for (const impact of impacted) { - instance.addEdge("DEPENDS_ON", impact, contrib); - } - } - - addContribution( - "colors for the graph visualizer", - [dennis, irene, lb, max, dl], - [design, graphviz] - ); - addContribution("design for graph visualizer", [dennis], [graphviz, design]); - addContribution( - "design for the frontend", - [dennis, irene], - [design, frontend] - ); - addContribution( - "pre-hack planning and project management", - [brian], - [prototype, logistics] - ); - addContribution("implementing the graph visualizer", [dl], [graphviz]); - addContribution("implementing seeded PageRank", [dl, mz], [seededPagerank]); - addContribution("implementing the frontend", [dl, jmnemo], [frontend]); - addContribution("implementing the backend", [dl], [backend]); - addContribution("logo--preliminary work", [lb, agata], [logo]); - addContribution("logo--lightbulb moment", [lb, max], [logo]); - addContribution("drawing the canvas", [lb], [canvas]); - addContribution( - "narrative shaping for canvas", - [lb, dl, mz], - [canvas, narrative] - ); - addContribution("oneline narrative statement", [dl, talbott], [narrative]); - addContribution("oneline narrative review", [max, dl], [narrative]); - addContribution("booking hotel stay", [sarah], [logistics]); - addContribution("booking plane tickets", [sarah], [logistics]); - addContribution("helping Dennis get into the space", [sarah], [logistics]); - addContribution( - "example prototype dataset", - [mz, brian], - [prototype, outreach] - ); - addContribution("final presentation", [dl, prototype], [narrative]); - addContribution("connection to the common stack", [mz], [outreach]); - addContribution("discussing the canvas with folks", [lb], [outreach]); - addContribution("general logistical defense", [jonathan], [logistics]); - addContribution("recruiting Max & company", [mz], [outreach, logistics]); - addContribution("forming the team", [mz], [logistics]); - - return instance; -} diff --git a/src/plugins/odyssey/explorerAdapter.js b/src/plugins/odyssey/explorerAdapter.js deleted file mode 100644 index 241b7f6..0000000 --- a/src/plugins/odyssey/explorerAdapter.js +++ /dev/null @@ -1,48 +0,0 @@ -// @flow - -import type {Assets} from "../../webutil/assets"; -import type {PluginDeclaration} from "../../analysis/pluginDeclaration"; -import type {RepoId} from "../../core/repoId"; -import type { - StaticExplorerAdapter as IStaticExplorerAdapter, - DynamicExplorerAdapter as IDynamicExplorerAdapter, -} from "../../explorer/adapters/explorerAdapter"; -import {NodeAddress, type NodeAddressT} from "../../core/graph"; -import {declaration} from "./declaration"; -import {OdysseyInstance} from "./instance"; -import {hackathonExample} from "./example"; - -export class StaticExplorerAdapter implements IStaticExplorerAdapter { - declaration(): PluginDeclaration { - return declaration; - } - - // TODO(@decentralion): Enable loading instances other than the hackathon example. - async load( - _unused_assets: Assets, - _unused_repoId: RepoId - ): Promise { - const instance = hackathonExample(); - return new DynamicExplorerAdapter(instance); - } -} - -class DynamicExplorerAdapter implements IDynamicExplorerAdapter { - +_instance: OdysseyInstance; - constructor(instance: OdysseyInstance): void { - this._instance = instance; - } - nodeDescription(address: NodeAddressT) { - const node = this._instance.node(address); - if (node == null) { - throw new Error(`No Odyssey node for: ${NodeAddress.toString(address)}`); - } - return node.description; - } - graph() { - return this._instance.graph(); - } - static() { - return new StaticExplorerAdapter(); - } -} diff --git a/src/plugins/odyssey/instance.js b/src/plugins/odyssey/instance.js deleted file mode 100644 index 4097ffa..0000000 --- a/src/plugins/odyssey/instance.js +++ /dev/null @@ -1,225 +0,0 @@ -// @flow - -/** - * Core "model" logic for the Odyssey plugin. - * Basically allows creating a data store of priorities, contributions, and people, - * and compiling that data store into a cred Graph. - */ -import { - Graph, - EdgeAddress, - NodeAddress, - type NodeAddressT, - type GraphJSON, - sortedNodeAddressesFromJSON, -} from "../../core/graph"; - -import deepEqual from "lodash.isequal"; - -import { - NODE_PREFIX, - EDGE_PREFIX, - type OdysseyNodeTypeIdentifier, - isOdysseyNodeTypeIdentifier, - type OdysseyEdgeTypeIdentifier, - isOdysseyEdgeTypeIdentifier, -} from "./declaration"; - -import {toCompat, fromCompat, type Compatible} from "../../util/compat"; - -import * as NullUtil from "../../util/null"; - -export type Node = {| - +nodeTypeIdentifier: OdysseyNodeTypeIdentifier, - +address: NodeAddressT, - +description: string, -|}; - -const COMPAT_INFO = {type: "sourcecred/odyssey/instance", version: "0.1.0"}; -export type InstanceJSON = Compatible<{| - +graphJSON: GraphJSON, - +sortedDescriptions: $ReadOnlyArray, - +count: number, -|}>; - -/** - * This is the data model for a particular instance in the Odyssey Plugin. - * The OdysseyInstance allows adding "Entities", which are basically nodes - * in the Odyssey graph augmented with a type identifier, and a description. - * Currently, the types are restricted to types hard-coded in the - * [declaration](./declaration.js) but we intend to allow instance-specified - * types in the future. - * - * The OdysseyInstance maintains an internal graph which actually stores the - * node identities, as well as added nodes. You can get a copy of this graph - * by calling the `.graph()` method. - * - * Entities are identified by an incrementing id (`._count`). This is - * convenient for implementation, although it will make reconciling - * simultaneous edits challenging. Once that becomes a real issue, we should - * switch to a different node/edge identification strategy. - */ -export class OdysseyInstance { - _graph: Graph; - _descriptions: Map; - _count: number; - - /** - * Construct an Odyssey Instance. - */ - constructor() { - this._graph = new Graph(); - this._descriptions = new Map(); - this._count = 0; - } - - /** - * Add a new node to the instance (and a corresponding node to the graph). - * - * Requires a valid node type identifier (a string that uniquely identifies - * an Odyssey node type; see [declaration.js](./declaration.js)). - */ - addNode( - typeIdentifier: OdysseyNodeTypeIdentifier, - description: string - ): Node { - if (!isOdysseyNodeTypeIdentifier(typeIdentifier)) { - throw new Error( - `Tried to add node with invalid type identifier: ${typeIdentifier}` - ); - } - const address = NodeAddress.append( - NODE_PREFIX, - typeIdentifier, - String(this._count) - ); - this._graph.addNode(address); - this._count++; - this._descriptions.set(address, description); - return NullUtil.get(this.node(address)); - } - - /** - * Retrieve the Node corresponding to a given node address, if it exists. - */ - node(address: NodeAddressT): ?Node { - if (!this._graph.hasNode(address)) { - return null; - } - const parts = NodeAddress.toParts(address); - // We know it is an OdysseyNodeTypeIdentifier because the instance's internal - // graph only has Odyssey nodes in it. - const nodeTypeIdentifier: OdysseyNodeTypeIdentifier = (parts[2]: any); - if (!isOdysseyNodeTypeIdentifier(nodeTypeIdentifier)) { - throw new Error( - `Invariant violation: ${nodeTypeIdentifier} is not odyssey type identifier` - ); - } - const description = NullUtil.get(this._descriptions.get(address)); - return {address, nodeTypeIdentifier, description}; - } - - /** - * Retrieve all the Nodes in the instance. - * - * Optionally filter to only nodes of a chosen type. - */ - nodes(typeIdentifier?: OdysseyNodeTypeIdentifier): Iterator { - const prefix = - typeIdentifier == null - ? NODE_PREFIX - : NodeAddress.append(NODE_PREFIX, typeIdentifier); - return this._nodesIterator(prefix); - } - - *_nodesIterator(prefix: NodeAddressT): Iterator { - for (const a of this._graph.nodes({prefix})) { - yield NullUtil.get(this.node(a)); - } - } - - /** - * Add an edge to the Odyssey instance. - */ - // TODO(@decentralion): Add support for edge types (also configured on a per-instance basis). - addEdge( - type: OdysseyEdgeTypeIdentifier, - src: Node, - dst: Node - ): OdysseyInstance { - if (!isOdysseyEdgeTypeIdentifier(type)) { - throw new Error(`Invalid Odyssey edge type identifier: ${type}`); - } - const edge = { - src: src.address, - dst: dst.address, - address: EdgeAddress.append(EDGE_PREFIX, type, String(this._count)), - }; - this._graph.addEdge(edge); - this._count++; - return this; - } - - /** - * Returns a copy of the graph underlying this instance. - */ - graph(): Graph { - return this._graph.copy(); - } - - toJSON(): InstanceJSON { - const graphJSON = this._graph.toJSON(); - const sortedNodeAddresses = sortedNodeAddressesFromJSON(graphJSON); - const sortedDescriptions = sortedNodeAddresses.map((a) => - NullUtil.get(this._descriptions.get(a)) - ); - return toCompat(COMPAT_INFO, { - graphJSON, - sortedDescriptions, - count: this._count, - }); - } - - static fromJSON(j: InstanceJSON): OdysseyInstance { - const {graphJSON, sortedDescriptions, count} = fromCompat(COMPAT_INFO, j); - const instance = new OdysseyInstance(); - instance._graph = Graph.fromJSON(graphJSON); - instance._count = count; - const descriptions = new Map(); - const sortedNodeAddresses = sortedNodeAddressesFromJSON(graphJSON); - for (let i = 0; i < sortedNodeAddresses.length; i++) { - descriptions.set(sortedNodeAddresses[i], sortedDescriptions[i]); - } - instance._descriptions = descriptions; - return instance; - } - - /** - * Returns whether two Odyssey instances have identical histories. - * - * Two instances are historically identical if they have the same ordered - * sequence of node additions and deletions. This is because the address of - * Nodes and Edges in the instance is determined by the order in which they - * were added. - * - * For an illustration, consider the following case: - * ```js - * const i1 = new OdysseyInstance(); - * i1.addNode("PERSON", "me") - * i1.addNode("PERSON", "you") - * - * const i2 = new OdysseyInstance(); - * i2.addNode("PERSON", "you") - * i2.addNode("PERSON", "me") - * - * expect(i1.isHistoricallyIdentical(i2)).toBe(false); - * ``` - */ - isHistoricallyIdentical(that: OdysseyInstance): boolean { - return ( - this._count === that._count && - this._graph.equals(that._graph) && - deepEqual(this._descriptions, that._descriptions) - ); - } -} diff --git a/src/plugins/odyssey/instance.test.js b/src/plugins/odyssey/instance.test.js deleted file mode 100644 index 1888760..0000000 --- a/src/plugins/odyssey/instance.test.js +++ /dev/null @@ -1,152 +0,0 @@ -// @flow - -import {OdysseyInstance} from "./instance"; -import {EdgeAddress, NodeAddress, Direction} from "../../core/graph"; - -describe("plugins/odyssey/instance", () => { - function exampleInstance() { - const instance = new OdysseyInstance(); - const me = instance.addNode("PERSON", "me"); - const you = instance.addNode("PERSON", "you"); - const value = instance.addNode("VALUE", "valuable-ness"); - const contribution = instance.addNode("CONTRIBUTION", "a good deed"); - const artifact = instance.addNode( - "ARTIFACT", - "the thing that creates value" - ); - - // first off I'd like to thank myself - instance - .addEdge("DEPENDS_ON", me, me) - // thank you for your support - .addEdge("DEPENDS_ON", me, you) - .addEdge("DEPENDS_ON", contribution, me) - .addEdge("DEPENDS_ON", artifact, contribution) - .addEdge("DEPENDS_ON", value, artifact); - return {instance, you, me, value, contribution, artifact}; - } - it("can retrieve the graph", () => { - const {instance, me} = exampleInstance(); - const graph = instance.graph(); - const nodes = Array.from(graph.nodes()); - const edges = Array.from(graph.edges()); - expect(nodes).toHaveLength(5); - expect(edges).toHaveLength(5); - const myNeighbors = graph.neighbors(me.address, { - direction: Direction.ANY, - nodePrefix: NodeAddress.empty, - edgePrefix: EdgeAddress.empty, - }); - expect(Array.from(myNeighbors)).toHaveLength(3); - }); - it("retrieved graph is a copy", () => { - const {instance} = exampleInstance(); - expect(instance.graph()).not.toBe(instance.graph()); - }); - it("returns nodes as they are added", () => { - const {me} = exampleInstance(); - expect(me).toEqual({ - address: NodeAddress.fromParts(["sourcecred", "odyssey", "PERSON", "0"]), - nodeTypeIdentifier: "PERSON", - description: "me", - }); - }); - it("can retrieve nodes by address", () => { - const {instance, me} = exampleInstance(); - expect(instance.node(me.address)).toEqual(me); - }); - it("returns null for non-existent node", () => { - const instance = new OdysseyInstance(); - expect(instance.node(NodeAddress.empty)).toEqual(null); - }); - it("throws an error when adding an node with bad type", () => { - const instance = new OdysseyInstance(); - // $ExpectFlowError - expect(() => instance.addNode("FOO", "foo")).toThrowError( - "invalid type identifier: FOO" - ); - }); - it("can retrieve all nodes", () => { - const {instance} = exampleInstance(); - expect(Array.from(instance.nodes())).toHaveLength(5); - }); - it("can retrieve nodes by type", () => { - const {instance, artifact, contribution, value} = exampleInstance(); - expect(Array.from(instance.nodes("ARTIFACT"))).toEqual([artifact]); - expect(Array.from(instance.nodes("VALUE"))).toEqual([value]); - expect(Array.from(instance.nodes("CONTRIBUTION"))).toEqual([contribution]); - // $ExpectFlowError - expect(Array.from(instance.nodes("NONEXISTENT"))).toEqual([]); - }); - it("errors if adding edge between Nodes that don't exist", () => { - const {me, you} = exampleInstance(); - const i = new OdysseyInstance(); - expect(() => i.addEdge("DEPENDS_ON", me, you)).toThrowError( - "Missing src on edge:" - ); - }); - describe("equality", () => { - it("empty instance isHistoricallyIdentical empty instance", () => { - const a = new OdysseyInstance(); - const b = new OdysseyInstance(); - expect(a.isHistoricallyIdentical(b)).toBe(true); - }); - it("empty instance does not equal nonempty instance", () => { - const a = new OdysseyInstance(); - a.addNode("PERSON", "me"); - const b = new OdysseyInstance(); - expect(a.isHistoricallyIdentical(b)).toBe(false); - }); - it("complex but identically generated instances are equal", () => { - const {instance: a} = exampleInstance(); - const {instance: b} = exampleInstance(); - expect(a.isHistoricallyIdentical(b)).toBe(true); - }); - it("instances with different descriptions are not equal", () => { - const a = new OdysseyInstance(); - const b = new OdysseyInstance(); - a.addNode("PERSON", "me"); - b.addNode("PERSON", "me2"); - expect(a.isHistoricallyIdentical(b)).toBe(false); - }); - it("instances with different types are not equal", () => { - const a = new OdysseyInstance(); - const b = new OdysseyInstance(); - a.addNode("PERSON", "me"); - b.addNode("ARTIFACT", "me"); - expect(a.isHistoricallyIdentical(b)).toBe(false); - }); - it("instances with different edges are not equal", () => { - const a = new OdysseyInstance(); - const b = new OdysseyInstance(); - const me = a.addNode("PERSON", "me"); - b.addNode("PERSON", "me"); - a.addEdge("DEPENDS_ON", me, me); - expect(a.isHistoricallyIdentical(b)).toBe(false); - }); - it("instances with different histories are not equal", () => { - const i1 = new OdysseyInstance(); - i1.addNode("PERSON", "me"); - i1.addNode("PERSON", "you"); - - const i2 = new OdysseyInstance(); - i2.addNode("PERSON", "you"); - i2.addNode("PERSON", "me"); - - expect(i1.isHistoricallyIdentical(i2)).toBe(false); - }); - }); - describe("to/from JSON", () => { - it("to->fro is identity", () => { - const {instance} = exampleInstance(); - const instance2 = OdysseyInstance.fromJSON(instance.toJSON()); - expect(instance.isHistoricallyIdentical(instance2)).toBe(true); - }); - it("fro->to is identity", () => { - const {instance} = exampleInstance(); - const json1 = instance.toJSON(); - const json2 = OdysseyInstance.fromJSON(json1).toJSON(); - expect(json1).toEqual(json2); - }); - }); -}); diff --git a/src/plugins/odyssey/ui/App.js b/src/plugins/odyssey/ui/App.js deleted file mode 100644 index 4ef9415..0000000 --- a/src/plugins/odyssey/ui/App.js +++ /dev/null @@ -1,153 +0,0 @@ -// @flow -import React, {Component} from "react"; -import {StyleSheet, css} from "aphrodite/no-important"; - -import {Header} from "./Header"; - -type AppProps = {||}; -type AppState = {||}; - -type Entity = {| - +name: string, - +score: number, -|}; - -const exampleValues: $ReadOnlyArray = [ - {name: "Implementation", score: 1002}, - {name: "Research", score: 1001}, - {name: "Ethics", score: 1000}, - {name: "Learning", score: 999}, - {name: "Something With A Long Name, Really Quite Long", score: 999}, - {name: "@1", score: 998}, - {name: "@2", score: 998}, - {name: "@3", score: 998}, - {name: "@4", score: 998}, - {name: "@5", score: 998}, - {name: "@6", score: 998}, -]; - -const examplePeople: $ReadOnlyArray = [ - {name: "@decentralion", score: 1002}, - {name: "@wchargin", score: 1001}, - {name: "@mzargham", score: 1000}, - {name: "@brianlitwin", score: 999}, - {name: "@anthrocypher", score: 998}, - {name: "@brutalfluffy", score: 998}, - {name: "@1", score: 998}, - {name: "@2", score: 998}, - {name: "@3", score: 998}, - {name: "@4", score: 998}, - {name: "@5", score: 998}, - {name: "@6", score: 998}, - {name: "@7", score: 998}, - {name: "@8", score: 998}, - {name: "@9", score: 998}, -]; - -class App extends Component { - scoreList(title: string, entities: $ReadOnlyArray) { - const entries = entities.map(({name, score}) => ( -
-
{name}
-
{score.toFixed(0)} ¤
-
- )); - return ( -
-

{title}

- {entries} -
- ); - } - - render() { - return ( -
-
- -
-
- {this.scoreList("Our Values", exampleValues)} - {this.scoreList("Our People", examplePeople)} -
- -
Chart to go here.
-
-
- ); - } -} - -const styles = StyleSheet.create({ - app: { - // HACK: Position absolute / top:0 to cover up the header from the - // default SourceCred UI. There's some discussion in the pull request: - // https://github.com/sourcecred/sourcecred/pull/1132 - top: "0px", - position: "absolute", - display: "flex", - flexDirection: "column", - height: "100%", - width: "100%", - }, - - scoreList: { - padding: "20px 20px 50px 20px", - }, - - scoreListTitle: { - fontSize: "28px", - lineHeight: "36px", - color: "#fff", - fontFamily: "'DINCondensed', sans-serif", - fontWeight: "700", - letterSpacing: "0.04em", - margin: "0 0 20px 0", - }, - - entityRow: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", - fontSize: "16px", - lineHeight: "19px", - marginTop: "20px", - cursor: "pointer", - }, - - entityName: { - fontWeight: "700", - color: "#E9EDEC", - letterSpacing: "-0.2px", - }, - - entityScore: { - color: "#EDAD47", - fontWeight: "600", - flexShrink: 0, - paddingLeft: "5px", - }, - - scoreListsContainer: { - display: "flex", - flexDirection: "column", - backgroundColor: "#242424", - "overflow-y": "scroll", - minWidth: "400px", - }, - - nonHeader: { - display: "flex", - flexDirection: "row", - paddingTop: "80px", - overflow: "hidden", - }, - - chartContainer: { - width: "100%", - padding: "42px", - display: "flex", - }, -}); - -export default App; diff --git a/src/plugins/odyssey/ui/Header.js b/src/plugins/odyssey/ui/Header.js deleted file mode 100644 index d0ad408..0000000 --- a/src/plugins/odyssey/ui/Header.js +++ /dev/null @@ -1,66 +0,0 @@ -// @flow -import React, {Component} from "react"; -import {StyleSheet, css} from "aphrodite/no-important"; - -import LogoIcon from "./img/logo.svg"; - -export type Props = {||}; -export class Header extends Component { - render() { - return ( -
-
-
Project Name Here
-
- SourceCred - -
-
-
- ); - } -} - -const styles = StyleSheet.create({ - header: { - position: "fixed", - display: "flex", - justifyContent: "space-between", - alignItems: "center", - top: "0", - left: "0", - height: "80px", - width: "100%", - backgroundColor: "#1D1D1C", - padding: "0 50px", - zIndex: "776", - }, - - titleBlock: { - minWidth: "380px", - color: "#E9EDEC", - fontSize: "32px", - lineHeight: "30px", - fontFamily: "'DINCondensed', sans-serif", - fontWeight: "700", - }, - - logo: { - display: "flex", - alignItems: "center", - fontSize: "20px", - lineHeight: "20px", - color: "#8E8F91", - letterSpacing: "-0.25px", - - span: { - height: "16px", - }, - - svg: { - width: "20px", - height: "20px", - marginLeft: "7px", - }, - }, -}); diff --git a/src/plugins/odyssey/ui/img/logo.svg b/src/plugins/odyssey/ui/img/logo.svg deleted file mode 100755 index 134fda3..0000000 --- a/src/plugins/odyssey/ui/img/logo.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - -