425 Commits

Author SHA1 Message Date
Dandelion Mané
10f704ebd2
Use AppStateTransitionMachine to drive App (#583)
Pull #579 reifies the cred explorer state as an explicit state
transition machine, with a well-tested implementation. This pull
re-writes `credExplorer/App.js` to use that implementation, and thoroughly
tests it.

The result is that `credExplorer/App.js` has much simpler code
(because it just binds the rendered components to the state machine),
and is much more thoroughly tested.

To ensure easy testability of the `App` class, it was refactored so that
the module exports a factory function which takes a method for creating
the `AppStateTransitionMachine` and returns an `App` class. This ensures
that in test code, we can easily mock the state transition machine. This
had no effect on external callers, since the higher-level `<AppPage>`
class, which already wraps over `LocalStore` choice, was already the
preferred call site.

I also added a loading indicator component, which presently displays a
status text corresponding to the state, such as "Loading graph...", or
"Error while running PageRank". This way, there is always some user
feedback during loading states (which could take a while).

Test plan:
Visual inspection, and the very thorough included unit tests.
2018-08-02 20:16:55 -07:00
William Chargin
20c80c3390
Downcase sourcecred URL on homepage (#600)
Summary:
This is minor, but we might as well point to the canonical
capitalization.

Test Plan:
None.

wchargin-branch: downcase-sourcecred-url
2018-08-02 20:16:15 -07:00
William Chargin
05ef54be80
Enforce a max-width of 900px (#599)
Summary:
Here, we make the width consistent across the home page, the explorer,
and the navbar. Arguably, the PageRank table itself should be wider. We
can let it pop out of the box model with `relative`, `width`, and `left`
properties (using `calc`), but we don’t want to deal with the details
right now.

At some time in the future, we can also of course unify these styles.

Paired with @decentralion.

Test Plan:
Running `yarn start` and clicking around the various pages suffices. To
check the external redirect page, you can apply

```diff
diff --git a/src/app/HomePage.js b/src/app/HomePage.js
index 4d0f832..0eee519 100644
--- a/src/app/HomePage.js
+++ b/src/app/HomePage.js
@@ -143,7 +143,8 @@ export default class HomePage extends React.Component<{||}> {
         <h2>Roadmap</h2>
         <p>
           SourceCred is under active development.{" "}
-          <Link className={css(styles.link)} to="/prototype">
+          <Link className={css(styles.link)} to="/discord-invite">
+            {/* STOPSHIP */}
             We have a prototype
           </Link>{" "}
           that ingests data from Git and GitHub, computes cred, and allows the
```

and then click the appropriate link on the home page.

wchargin-branch: max-width-900
2018-08-02 19:53:47 -07:00
William Chargin
f137b83cde
Write prose for the home page (#598)
Summary:
@decentralion and I have spent a bunch of time on this prose, and we
think that it’s pretty good. Let’s put some content on our otherwise
bare site.

Test Plan:
Running `yarn start` suffices.

Paired with @decentralion.

wchargin-branch: home-page-prose
2018-08-02 19:25:24 -07:00
Dandelion Mané
56c17d2597
Implement AppState and StateTransitionMachine (#579)
The cred explorer app has a variety of valid states. Currently, it is
thrown together without explicit documentation of what its states are,
how they transition, or error handling or testing. I worry that this
will be hard to maintain.

This commit creates the AppState type which explicitly reifies every
reachable state for the app, and a StateTransitionMachine which handles
transitions between states. The transitions are thoroughly tested,
including edge cases where the user makes a change while waiting for a
promise to resolve, or where one of the promises failes.

Test plan:
The unit tests are comprehensive. `yarn test` passes.

Thanks to @wchargin for much discussion about how to structure the
states.
2018-08-02 19:18:33 -07:00
Claire L
fa66c7ba80
Rename "Explore(r)" to "Prototype" in route and navigation (#584)
"Explore(r)" does not accurately convey the current state of the
project. In order to more accurately convey the current state,
"Explore(r)" has been updated to "Prototype"

Addresses #584

Test plan: Visual inspection and manual testing of pathing
2018-08-02 13:17:33 -07:00
Claire L
8e653403dc
Better navbar styling and external project links
Currently, the navbar lacks styling, and only provides links to the home and explorer pages.
This change adds:
* Better styling for the navbar
* External links to SourceCred github and twitter
Test plan: visual inspection
2018-08-02 12:20:51 -07:00
William Chargin
9d5c4454c5
Remove src/app/public (#582)
Summary:
This subtree has no effect on the new build process; it contains only
stale code.

Test Plan:
Running `yarn test --full` passes. Running `yarn build` and running an
HTTP server on the result indicates the expected behavior, as does
running `yarn start`. A quick `git grep public` finds no amok results.

wchargin-branch: remove-public
2018-07-31 21:45:25 -07:00
Dandelion Mané
56f0b8b1b9
Streamline the cred explorer UI (#581)
This commit removes some unecessary text and whitespace from the cred
explorer. The result is more minimal. It's not super pretty, but that
will come later.

Test plan: Visual inspection
2018-07-31 19:59:37 -07:00
Dandelion Mané
8009cd279b
Remove graph node and edge count (#575)
This commit removes the node and edge counts that are displayed on the
cred explorer. While this is nice information to surface, I think it's
currently surfaced in the wrong place: it should be displayed as part of
the PagerankTable.

My proximate motivation for removing it is that it cleans up the data
structure slightly and I'm about to intensively refactor the whole file.

Test plan: `yarn test`; also, I manually engaged the cred explorer and
it still works properly.
2018-07-31 13:26:53 -07:00
William Chargin
e492965c12
Treat plugin adapters generically in App (#560)
Test Plan:
Unit tests pass, and manual testing indicates that graph loading works.

wchargin-branch: generic-plugin-adapters
2018-07-28 11:24:06 -07:00
Dandelion Mané
3266eb31fa
CLI takes repo strings as owner/name (#559)
Test plan:
```
$ yarn backend
$ node bin/sourcecred.js load sourcecred/sourcecred
```
2018-07-27 23:44:41 -07:00
Dandelion Mané
4406c96c95
Create a Repo type and use throughout the project (#555)
Our data model orients on getting repos from GitHub, which are
alternatively represented as strings like "sourcecred/sourcecred", or
pairs of variables representing the owner and name, or objects with
owner and name properties. We also have a few different implementations
of repo validation, which are not applied consistently.

This commit changes all that. We now have a consistent Repo type which
is an object containing a string owner and string name. Thanks to a
clever suggestion by @wchargin, it is implemented as an opaque subtype
of an object containing those properties, so that the only valid way to
construct a Repo typed object is to use one of the functions that
consistently validates the repo.

As a fly-by fix, I noticed that there were some functions in the GitHub
query generation that didn't properly mark arguments as readOnly. I've
fixed these.

Test plan: No externally-observable behavior changes (except insofar as
there is a slight change in variable names in the GitHub graphql query,
which has also resulted in a snapshot diff). `yarn travis --full`
passes. `git grep repoOwner` presents no hits.
2018-07-27 21:30:50 -07:00
William Chargin
68fa7237a0
Add external link to Discord invite (#551)
Test Plan:
None really needed—the infrastructure has already been tested—but you
can verify that this works both under `yarn start` and `yarn build` by
navigating to the evident URL.

wchargin-branch: discord-invite
2018-07-27 20:18:22 -07:00
William Chargin
8e062592ae
Add external redirect infrastructure (#550)
Summary:
This patch extends our routing infrastructure to add support for
_external_ redirects. It does not include dedicated support for
site-internal redirects.

Test Plan:
Add an external redirect to `routeData`, like the following:

```diff
diff --git a/src/app/routeData.js b/src/app/routeData.js
index 83dff72..eaba130 100644
--- a/src/app/routeData.js
+++ b/src/app/routeData.js
@@ -36,6 +36,15 @@ const routeData /*: $ReadOnlyArray<RouteDatum> */ = [
     title: "SourceCred explorer",
     navTitle: "Explorer",
   },
+  {
+    path: "/discord-invite",
+    contents: {
+      type: "EXTERNAL_REDIRECT",
+      redirectTo: "https://discord.gg/tsBTgc9",
+    },
+    title: "SourceCred Discord invite",
+    navTitle: null,
+  },
 ];
 exports.routeData = routeData;

```

Then:
  - run `yarn build`, and:
     - verify that the appropriate `index.html` file is correctly
       generated;
     - verify that opening the `index.html` file in a browser redirects
       you to the appropriate destination, even with JavaScript
       disabled;
     - verify that the link in the body of the HTML page is correct
       (easier to do if you remove the `<meta>` tag)
  - run `yarn start`, and:
    1. use the React DevTools to change the “Explorer” link’s `to` prop
       from `/explorer` to `/discord-invite`;
    2. click the link; and
    3. verify that you are properly redirected.

wchargin-branch: add-external-redirect
2018-07-27 19:13:51 -07:00
Dandelion Mané
49da7cfdb0
Display cred explorer scores as -Log(score) (#535)
@wchargin suggested displaying scores this way. This way, lowest scores
are best, and higher scores are worse. This is a little
counterintuitive, but maybe less counterintuitive than the current
approach, which arbitrarily adds 10 to scores to keep them non-negative,
and results in an arbitrary crossing point where scores become negative
without any particular significance.

Test plan: Travis, and manual inspection of the frontend.
2018-07-27 17:04:29 -07:00
William Chargin
873eca6350
Upgrade Flow to v0.76.0 (#546)
Summary:
In addition to a routine libdef update, we also need to work around a
particularly nasty new bug in Flow, which requires `any`-casts that are
even more unsafe than usual. That said, I think that it’s worth that
cost to remain up to date with Flow, so that we can amortize future such
issues.

Test Plan:
Running `yarn travis --full` passes.

wchargin-branch: upgrade-flow-v0.76.0
2018-07-27 15:54:59 -07:00
Dandelion Mané
e669e89315
RepositorySelect displays NO_REPOS on 404 (#547)
Test plan: Unit tests included, plus I manually tested it.
2018-07-27 15:47:15 -07:00
Dandelion Mané
0b0815eb12
When repo registry fails, error to console (#544)
Some slight changes were needed to the other test code to avoid spurious
errors. Specifically, we now always set up a mocked fetch response in
non-failure cases, even if we don't wait for it to resolve.

Test plan: I manually tested it, also see the new unit tests.
2018-07-27 15:42:18 -07:00
Dandelion Mané
126fdb69dc
Add default weights for node types (#543)
Modifies the PluginAdapter interface so that NodeTypes come with
default weights, and modify the WeightConfig so that it loads those
NodeTypes as the default weights.

The new weight choices are not super principled, but are clearly better
than the uniform default. Now, projects find that most pull requests are
more valuable than most git blobs. :)

Sadly, the WeightConfig does not yet have any tests, so there are no
test changes.

Test plan: I manually verified that it works as expected, by clearing
application data and reloading the cred explorer.
2018-07-27 15:34:11 -07:00
Dandelion Mané
294616b556
RepositorySelect tests verify no console errors (#545)
We should really do this as a matter of course on all frontend testing.
Not sure what the right pattern is for ensuring that.

Test plan: Travis
2018-07-27 15:32:47 -07:00
Dandelion Mané
b61b8fbdb8
Improve error messages when GitHub query fails (#536)
Currently, the GitHub graph fetcher will characteristically fail if:
1. it times out GitHub's server
2. it triggers the semidocumented abuse detection mechanism

In case 1, an intelligible error is posted to the console. In case 2, it
produces an unintelligible TypeError, because the response is not a
valid GraphQL response (the error field is not populated; it has a
custom message instead).

As of this commit, we gracefully catch both cases, and print a message
to console directing the user to #350, which has context on GitHub query
failures. This new catch works because in case 2, the data field is
empty, so we now properly recognize `x.data === undefined` as an error
case.

Thanks to @wchargin for the investigatory work behind this commit.

Fixes #223.

Test plan:
We don't have unit tests that cover this case, but I did manually test
it by asking GitHub to fetch `ipfs/go-ipfs`, which consistently fails.
I also tested it by using an invalid length-40 GitHub API token.
2018-07-27 13:27:40 -07:00
William Chargin
4058a3fd85
Extract dedent to util, adding tests (#538)
Summary:
There have been a couple of occasions on which we’ve considered using
it, but didn’t want to require from `app/`.

Test Plan:
Unit tests added, with full coverage.

wchargin-branch: extract-dedent
2018-07-27 12:30:28 -07:00
Dandelion Mané
aa3382a8b2
Default to selecting last loaded repository (#531)
In #529, I made the cred explorer populate a dropdown with the list of
repositories that are available to explore. That dropdown defaults to
selecting the alphabetically first repository.

This has an unfortunate consequence in that it makes it impossible for
us to explicitly set a default - for example, we would like
sourcecred.github.io/explorer to show sourcecred/sourcecred by default,
but instead it shows example-git.

So that we can choose the default, I've changed the logic so that it
instead shows the most-recently-loaded data first. This required
a breaking change to the repoRegistry serialized format, so I've also
refactored the module to use compat, which I should have done from the
beginning.

Test plan:
Unit tests for the repo selector are updated. The CLI load command
unfortunately has no tests, so I manually tested that it always provides
the lastest repository last, and appropriately handles the case where
the same repository is loaded multiple times.
2018-07-27 10:33:15 -07:00
Dandelion Mané
f110114833
Convert Explorer repository selection to dropdown (#529)
Context: The Cred Explorer loads data (currently on a per-repository
basis) that has previously been prepared by running the `sourcecred
load` cli command.

Currently, to select a repository to load, the user must manually type
the repository owner and name. This is a confusing UI, because it
suggests that any repository may be chosen, when in fact only repos
already loaded into the data store are available. The user is given no
feedback as to which repositories are valid options.

As of #516, the backend stores a registry listing available
repositories. This commit adds a `RepositorySelect` component which
loads the available from that registry, and makes them available in a
dropdown, in sorted order.

When the user manually selects one of the repositories, that selection
is persisted into localStorage and respected on future loads. If the
user hasn't made such a choice, then the first repository is selected by
default.

The implementation is highly influenced by testability considerations.
The default export, `<RepositorySelect onChange={} localStore={} />`, is
pretty straightforward. The `RepositorySelect` is somewhat cumbersome to
test because it asynchronously fetches data and then updates its state,
which affects the render output. So as to avoid testing inside async
react components wherever possible, I've factored out:

* `loadStatus`, which uses fetch and localStore to get the status of the
selector.
* `PureRepositorySelect`, which just renders a `Status`, such as
loading, failure, or valid
* `LocalStoreRepositorySelect`, which wraps the `PureRepositorySelect`
with logic to bind the repository select to localStore on change.

Test plan: Extensive unit tests were added. Also, to ensure that the
tests were testing the right thing, I manually tested:
- attempting to load invalid registry
- attempting to load with no registry
- attempting to load with empty registry
- loading without valid localStore
- changing the setting via dropdown
- loading from localStore after changing the dropdown

And all behavior was as expected.

Thanks to @wchargin for considerable help testing this PR.
2018-07-26 19:24:25 -07:00
Dandelion Mané
e36a7c1af2
Fix a mistake in the implementation of #527 (#530)
Test plan: Travis
2018-07-26 18:32:34 -07:00
William Chargin
e0c97fee9e
Extract a TestLocalStore (#527)
Summary:
Test code should probably always use a checked, memory-backed local
storage implementation. This endpoint will help users not forget to
include the checks.

wchargin-branch: test-local-store
2018-07-26 15:05:43 -07:00
William Chargin
8655838b2c
Use CheckedLocalStore in the cred explorer (#526)
Summary:
Might as well have runtime type safety, in case we accidentally try to
store any more `Map`s or `undefined`s.

Test Plan:
Tests pass, but are likely not sufficient. Manual testing indicates that
the local storage still works, for both reads and writes, on a fresh
profile or with existing data, for both the repository owner/name and
the weight configuration.

wchargin-branch: use-checked-local-store
2018-07-24 19:34:35 -07:00
William Chargin
c0da12af6e
Use MemoryLocalStore for existing tests (#525)
Summary:
This resolves a TODO. It’s not urgent, but it’s good practice.

wchargin-branch: use-memory-local-store
2018-07-24 19:19:53 -07:00
William Chargin
0489ff8844
Add a memoryLocalStore implementation (#524)
Summary:
We can use this in tests. If need be, we can enhance this class to allow
simulating failures, low storage limits, etc., but just having a pure
implementation at all is all we need right now.

Test Plan:
Unit tests added.

wchargin-branch: memory-local-store
2018-07-24 19:10:38 -07:00
William Chargin
d0906eed16
Add a checkedLocalStore implementation (#523)
Summary:
This provides some extra checking around `LocalStore` calls. In
particular, it fails fast on the nasty bug where storing a `Map`
actually stores the empty object (`JSON.stringify(new Map()) === "{}"`).
Similarly, retrieving a value that was stored as `undefined` will raise
an error, because `JSON.parse(JSON.stringify(undefined))` raises an
error.

This should have negligible performance impact—local storage access
should never be on a critical path. We can choose to elide this in
production if we want.

Test Plan:
Unit tests added. Manual testing of the cred explorer yields no errors.

wchargin-branch: checked-local-store
2018-07-24 19:00:39 -07:00
William Chargin
801b4ec700
Dependency-inject LocalStore (#522)
Summary:
This commit modifies components that directly depend on the
browser-specific local store implementation to instead have their
dependencies injected.

Test Plan:
Tests pass, but are likely not sufficient. Manual testing indicates that
the local storage still works, for both reads and writes, on a fresh
profile or with existing data, for both the repository owner/name and
the weight configuration.

wchargin-branch: di-localstore
2018-07-24 18:56:36 -07:00
William Chargin
1fa039ba6c
Extract a LocalStore interface (#521)
Summary:
We’d really like to be able to test components that use `LocalStore`. We
can do this by dependency-injecting the storage backend. This commit
begins that process by extracting `LocalStore` to its interface,
preserving the unique existing implementation.

wchargin-branch: extract-localstore
2018-07-24 18:53:40 -07:00
William Chargin
77fa29320c
Reduce memory pressure by double-buffered PageRank (#520)
Summary:
This commit switches to a double-buffered PageRank implementation. When
benchmarked on `ipfs/js-ipfs`, the critical section improves from
3059 ms to 2433 ms (79.5% of original), and peak heap usage drops from
342 MB to 207 MB. (Tested non-rigorously in Chrome 67.)

Test Plan:
Existing unit tests for `sparseMarkovChainAction`,
`findStationaryDistribution`, and `pagerank` are sufficient.

wchargin-branch: pagerank-dbuf
2018-07-24 17:51:40 -07:00
William Chargin
4435a3cfad
Make PageRank functions asynchronous (#519)
Summary:
The PageRank functions can take a long time to compute. We’d like them
to not lock the browser, and we’d also like them to communicate with
their clients (e.g., to update a progress bar). This code updates
`findStationaryDistribution` and downstream `pagerank` to return
promises.

Test Plan:
Unit tests updated. The cred explorer (`yarn start`) still works.
Applying

```diff
diff --git a/src/core/attribution/markovChain.js b/src/core/attribution/markovChain.js
index 2acce9c..c7a7159 100644
--- a/src/core/attribution/markovChain.js
+++ b/src/core/attribution/markovChain.js
@@ -166,6 +166,7 @@ export function findStationaryDistribution(
           return;
         }
       } while (Date.now() - start < yieldAfterMs);
+      console.log("Yielding.");
       setTimeout(tick, 0);
     };
     tick();
```

causes the appropriate log messages to be printed in the browser—about
once every ten iterations for `sourcecred/sourcecred`.

wchargin-branch: asynchronous-pagerank
2018-07-24 17:46:32 -07:00
Dandelion Mané
cd6c869d84
Add a registry of loaded repositories (#516)
We want the UI to offer a list of available repositories, rather than
using a text input box. To do this, we first need the backend to include
a registry of all available repositories.

Test plan:
Sadly we don't have CLI testing, so I manually verified this by doing
the following:

```
$ yarn backend
$ rm -r $SOURCECRED_DIRECTORY
$ node bin/sourcecred.js load sourcecred example-github
$ cat $SOURCECRED_DIRECTORY/repositoryRegistry.json
{"sourcecred/example-github":true}
$ node bin/sourcecred.js load sourcecred example-github
$ cat $SOURCECRED_DIRECTORY/repositoryRegistry.json
{"sourcecred/example-github":true}
$ node bin/sourcecred.js load sourcecred example-git
$ cat $SOURCECRED_DIRECTORY/repositoryRegistry.json
{"sourcecred/example-git":true,"sourcecred/example-github":true}
```
2018-07-24 12:33:58 -07:00
Dandelion Mané
94a023ef6f
WeightConfig loads from plugin adapters (#515)
Previously, WeightConfig hackily contained its own enumeration of all
node and edge types. Now, it loads them from the StaticPluginAdapter.

Test plan:
Unit tests pass, as does manual inspection of the frontend.
2018-07-23 15:40:43 -07:00
Dandelion Mané
2a39844445
Split PluginAdapter into Dynamic and Static parts (#513)
In some cases (e.g. WeightConfig) we want to have information from the
PluginAdapater before loading any data from the server. In other cases,
we need to combine the PluginAdapater with actual data, e.g. so we can
get the description of a GitHub node.

To support this, we split the PluginAdapter into a Static and Dynamic
component. The Dynamic component has data needed to give node
descriptions, etc. Given a static adapter, you can get a promise to load
the dynamic adapter. Given the dynamic adapter, you can immediately get
the static adapter. (There's a parallel to NodeReference (static) and
NodePorcelain (dynamic)).

Test plan:
Travis passes, as does manual testing of the frontend.
2018-07-23 15:37:14 -07:00
Dandelion Mané
3c14ef8a43
Refactor PluginAdapter abstraction (#512)
- PluginAdapters no longer expose a Renderer; instead, the render
methods are inlined on the PluginAdapter. The extra abstraction didn't
provide any lift in the current architecture.

- The edgeVerb function has been removed.

- PluginAdapters now enumerate EdgeTypes. Each has a prefix, and a
forward and a backward name.

Test plan: `yarn travis`, plus manual testing of the frontend and the
weight config.
2018-07-23 15:25:17 -07:00
William Chargin
28100275c4
Disable service workers (#514)
Summary:
We don’t need this to be a “progressive web app”—certainly not now. The
n+1 caching problem is not a good tradeoff for us, and furthermore
service workers are causing flashes of content on server-side rendered
pages.

This commit is a quick fix to remove them. We can remove the code
entirely if we want, or just keep it as is.

Test Plan:
On a machine has the service worker registered, run `yarn build`, then
`node bin/sourcecred.js start`. Note in the network panel that the
service worker is loaded on the first page load, but then deregistered.
On subsequent refreshes, it should not activate. In the “Application”
panel of the Chrome dev tools, it should appear as “deleted”.

wchargin-branch: disable-sw
2018-07-23 15:16:45 -07:00
Dandelion Mané
943d04cc70
Allow expanding/hiding the WeightConfig (#511)
The WeightConfig is a power user feature. Now that we're building a
public-facing demo out of the Cred Explorer, it will be better to hide
the weight configuration by default.

This commit adds a button for showing/hiding the weight configuration.
The weights are still propagated correctly regardless of whether the
weight config is shown.

Test plan:
- Ensure that the site loads with weights hidden by default.
- Ensure that clicking the button causes the weight config to display.
- Ensure that PageRank loads and displays correctly with the weights
hidden.
- Ensure that changes to the weight config still propagate to PageRank
(with weights hidden or not hidden).
2018-07-23 14:05:06 -07:00
William Chargin
73e36b2ab2 Make route path data available in vanilla context
Test Plan:
Ensure that `require("./src/app/routeData")` works in `node` without any
preprocessing. Ensure that `yarn start` works, and that `yarn build`
then `node ./bin/sourcecred.js start` also works.

wchargin-branch: vanilla-route-data
2018-07-23 13:29:48 -07:00
William Chargin
b41009b1f7 Implement a first-pass static site generation
Summary:
Some of the code here is adapted from my site (source available on
GitHub at wchargin/wchargin.github.io). It has been improved when
possible and made worse when necessary to fit into our existing build
system with minimal churn.

As of this commit, there remain the following outstanding tasks:
  - Use a non-hardcoded list of paths in static site generation router.
    This is not trivial. We have the paths nicely available in
    `routes.js`, but this module is written in ES6, and transitively
    depends on many files written in ES6 (i.e., the whole app). Yet
    naïvely it would be required from a Webpack config file, which is
    interpreted as vanilla JavaScript.
  - Add `csso-loader` to minify our CSS. This is easy.
  - Add unit tests for `dedent`. (As is, it comes from my site
    verbatim. I wrote it. dmnd’s `dedent` package on npm is insufficient
    because it dedents arguments as well as the format string, which is
    incorrect at least for our purposes.)
  - Link in canonical static data for the site.
  - Rip out the whole build system and replace it with my build config,
    which is orders of magnitude saner and less bad. (By “the whole
    build system” I mostly mean `webpack.config.{dev,prod}.js`.)

Test Plan:

```shell
$ yarn backend
$ yarn build
$ node ./bin/sourcecred.js start
```

wchargin-branch: static-v0
2018-07-23 13:29:48 -07:00
William Chargin
08e8494170 Update page title on route change
Test Plan:
Navigate to `/`, then click the “Explorer” link, and note that the page
title has updated.

wchargin-branch: update-page-title
2018-07-23 13:29:48 -07:00
William Chargin
256582d8b3 Add a landing page
Summary:
This adds a dummy landing page. We’ll want to actually put nice content
on it. For development convenience, I’m totally fine with having the
`yarn start` launch `/explorer` instead of just `/`.

Test Plan:
Run `yarn start` and note that the navigation works.

wchargin-branch: landing-page
2018-07-23 13:29:48 -07:00
William Chargin
6be05e91c8 Add basic react-router@3 routing
Summary:
This commit introduces a `Page` component that we can use to provide
common styling and navigation to our pages.

wchargin-branch: use-rrv3
2018-07-23 13:29:48 -07:00
William Chargin
ab0fa81a40
Show PageRank node decomposition in the explorer (#507)
Summary:
This commit hooks up the PageRank table to the PageRank node
decomposition developed previously. The new cred explorer displays one
entry per contribution to a node’s cred (i.e., one entry per in-edge,
per out-edge, and per synthetic loop), listing the proportion of the
node’s cred that is provided by this contribution. This makes it easy to
observe facts like, “90% of this issue’s cred is due to being written by
a particular author”.

Paired with @decentralion.

Test Plan:
Unit tests added; run `yarn travis`.

wchargin-branch: pagerank-table-node-decomposition
2018-07-23 10:42:40 -07:00
William Chargin
bb7b538f44
Use NullUtil functions where appropriate (#506)
Summary:
The aesthetically nicest win is in `WeightConfig`. Other changes are
nice to have.

In many cases, we reduce the specificity of error messages thrown. For
instance, if an invariant was violated on an edge `e`, then we might
have thrown an error with message `EdgeAddress.toString(e.address)`. But
we did so not because we thought that this was genuinely worth it, but
only because we were forced to explicitly throw an error at all. These
errors should never be hit, anyway, so we don’t feel bad about replacing
these with errors that are simply the string `"null"` or `"undefined"`,
as appropriate.

Test Plan:
Running `yarn travis --full` passes, and the cred explorer still seems
to work with both populated and empty `localStorage`.

wchargin-branch: use-null-util
2018-07-09 17:53:05 -07:00
William Chargin
4af8ff2471
Add utilities for working with nullable types (#505)
Summary:
This commit adds a module with four functions: `get`, `orThrow`, `map`,
and `orElse`.

Here is a common pattern wherein `get` is useful:

```js
sortBy(Array.from(map.keys()), (x) => {
  const result = map.get(x);
  if (result == null) {
    throw new Error("Cannot happen");
  }
  return result.score;
});

// versus

sortBy(Array.from(map.keys()), (x) => NullUtil.get(map.get(x)).score)
```

(The variant `orThrow` allows specifying a custom message that is only
computed in the case where the error will be thrown.)

Here is a common pattern where `map` is useful:

```js
arr.map((x) => {
  const result = complicatedComputation(x);
  return result == null ? result : processResult(result);
});

// versus

arr.map((x) => NullUtil.map(complicatedComputation(x), processResult))
```

In each of these cases, by using these functions we gain a dose of
safety in addition to our concision: it is tempting to “shorten” the
expression `x == null ? y : z` to simply `x ? y : z`, while forgetting
that the latter behaves incorrectly for `0`, `false`, `""`, and `NaN`.
Similar patterns like `x || defaultValue` also suffer from this problem,
and can now be replaced with `orElse`.

Designed with @decentralion.

Test Plan:
Unit tests included; run `yarn travis`.

wchargin-branch: null-util
2018-07-09 14:47:10 -07:00
Dandelion Mané
fed58aee7b
Rename PagerankResult to NodeDistribution (#504)
Test plan: travis
2018-07-09 14:21:37 -07:00